当元素在 Chrome 中更改不透明度时,滚动条为 disappearing/reappearing
Scrollbar is disappearing/reappearing when element changes opacity in Chrome
我有一个名为 img-with-overlay
的 div
,它包含一个静态定位图像和一个绝对定位叠加层。当 img-with-overlay
悬停在上方时,叠加层的不透明度从 0
变为 1
。这样做的一个意外副作用是,在 Chrome 和基于 Chromium 的浏览器中,当覆盖层不透明时,垂直滚动条会消失。它不会出现在 Firefox 中。
你问为什么滚动条在那里?你可以看到有一个 container
和一个非常具体的 width
和 height
。即使这些尺寸改变了半个像素,也不会发生意想不到的副作用。我正在使用此容器来表示我网页的 body
,尽管我已将其缩小以适合片段。虽然大多数屏幕尺寸不会出现问题,但我仍然想防止它过度发生。
$(document).ready(function () {
$('.img-with-overlay').hover(function () {
$('.overlay').css('opacity',1);
}, function () {
$('.overlay').css('opacity',0);
})
});
.container {
width: 600px;
height: 248.5px;
overflow: auto;
overflow-x: hidden;
}
.img-with-overlay {
position: relative;
overflow: hidden;
width: 100%;
}
img {
display: block;
width: 100%;
}
.overlay {
position: absolute;
top: 0;
opacity: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="img-with-overlay">
<img src="https://via.placeholder.com/468x200?text=Hover">
<div class="overlay">This is an overlay</div>
</div>
</div>
为什么覆盖层的不透明度改变时滚动条disappearing/reappearing?
我注意到的一些有趣的事情:
- 如果将
img
替换为相同尺寸的 div
,则不会出现滚动条。
- 如果叠加层的不透明度设置为小于 1 的值,例如 0.7,悬停时滚动条不会消失。
发生的事情很简单,但并不那么明显。
背景
当您设置图像 width: 100%
时,系统会自动计算图像高度以保持原始比例。容器比图像高一点,因为它有 overflow-y: auto
,所以出现垂直滚动。但是现在奇迹发生了:垂直滚动条减少了容器的内部宽度,所以图像宽度相应地减少,它的高度也相应地减少以保持比例。但是现在图像比容器高一点点,所以不再需要垂直滚动条。但如果滚动条消失,图像将再次展开,开始无限循环,一切都在闪烁。为防止这种竞争情况,浏览器选择始终显示滚动条,但由于图像适合容器,因此无需向下滚动,因此滚动条被禁用。
这解释了为什么稍微改变一下尺寸就可以解决问题:如果您使容器稍微窄一点或高一点,图像总是适合,而不需要滚动条;如果您使容器更宽或更短,图像将永远无法容纳并且始终显示滚动条。
不透明度问题
现在考虑以下问题。您的图片同时包含 display: block
和 width: 100%
。这两个属性影响相同的 属性(宽度),但在布局工作流程中以不同的方式和不同的时间影响。这足以启动竞争条件,该行为未定义,浏览器会尝试以自己的方式解决。您可以通过打开检查器并切换 img 的 display
属性来验证它:开始时您有一个禁用的滚动条,然后当您关闭该属性时滚动条被启用,然后当您重新启用该属性时滚动条完全消失。什么?!我们又回到了初始状态,结果却不一样?! :我的天啊:
大多数情况下,这种竞争条件没有影响,但在这种情况下,由于上一节中的描述,它变得很清楚。
现在让我们谈谈不透明度。不透明度小于 1 的元素必须以特定的顺序(从后到前)呈现,并且在呈现背面不透明元素之后。虽然我不知道在 Chrome 和 Firefox 中这是如何实现的,但行为表明在 Chrome 中渲染顺序会以某种方式影响布局工作流程。这解释了为什么 opacity=1 的行为不同于 opacity=0.999。但这只会发生,因为存在没有定义行为的条件,如前所述。
因此解决方案非常简单:删除导致未定义行为的条件。由于 display: block
不影响图像大小,而只影响 space 元素占用,因此要做的事情很明显: 删除 display: block
并仅保留 [= img
元素上的 10=].
如果出于某种原因您不想删除 display: block
,您可以通过在容器上编码 overflow-y: scroll
强制滚动条始终可见(同时删除溢出属性) .这样您就不会删除导致未定义行为的条件,但会删除滚动条上的竞争条件。
我有一个名为 img-with-overlay
的 div
,它包含一个静态定位图像和一个绝对定位叠加层。当 img-with-overlay
悬停在上方时,叠加层的不透明度从 0
变为 1
。这样做的一个意外副作用是,在 Chrome 和基于 Chromium 的浏览器中,当覆盖层不透明时,垂直滚动条会消失。它不会出现在 Firefox 中。
你问为什么滚动条在那里?你可以看到有一个 container
和一个非常具体的 width
和 height
。即使这些尺寸改变了半个像素,也不会发生意想不到的副作用。我正在使用此容器来表示我网页的 body
,尽管我已将其缩小以适合片段。虽然大多数屏幕尺寸不会出现问题,但我仍然想防止它过度发生。
$(document).ready(function () {
$('.img-with-overlay').hover(function () {
$('.overlay').css('opacity',1);
}, function () {
$('.overlay').css('opacity',0);
})
});
.container {
width: 600px;
height: 248.5px;
overflow: auto;
overflow-x: hidden;
}
.img-with-overlay {
position: relative;
overflow: hidden;
width: 100%;
}
img {
display: block;
width: 100%;
}
.overlay {
position: absolute;
top: 0;
opacity: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="img-with-overlay">
<img src="https://via.placeholder.com/468x200?text=Hover">
<div class="overlay">This is an overlay</div>
</div>
</div>
为什么覆盖层的不透明度改变时滚动条disappearing/reappearing?
我注意到的一些有趣的事情:
- 如果将
img
替换为相同尺寸的div
,则不会出现滚动条。 - 如果叠加层的不透明度设置为小于 1 的值,例如 0.7,悬停时滚动条不会消失。
发生的事情很简单,但并不那么明显。
背景
当您设置图像 width: 100%
时,系统会自动计算图像高度以保持原始比例。容器比图像高一点,因为它有 overflow-y: auto
,所以出现垂直滚动。但是现在奇迹发生了:垂直滚动条减少了容器的内部宽度,所以图像宽度相应地减少,它的高度也相应地减少以保持比例。但是现在图像比容器高一点点,所以不再需要垂直滚动条。但如果滚动条消失,图像将再次展开,开始无限循环,一切都在闪烁。为防止这种竞争情况,浏览器选择始终显示滚动条,但由于图像适合容器,因此无需向下滚动,因此滚动条被禁用。
这解释了为什么稍微改变一下尺寸就可以解决问题:如果您使容器稍微窄一点或高一点,图像总是适合,而不需要滚动条;如果您使容器更宽或更短,图像将永远无法容纳并且始终显示滚动条。
不透明度问题
现在考虑以下问题。您的图片同时包含 display: block
和 width: 100%
。这两个属性影响相同的 属性(宽度),但在布局工作流程中以不同的方式和不同的时间影响。这足以启动竞争条件,该行为未定义,浏览器会尝试以自己的方式解决。您可以通过打开检查器并切换 img 的 display
属性来验证它:开始时您有一个禁用的滚动条,然后当您关闭该属性时滚动条被启用,然后当您重新启用该属性时滚动条完全消失。什么?!我们又回到了初始状态,结果却不一样?! :我的天啊:
大多数情况下,这种竞争条件没有影响,但在这种情况下,由于上一节中的描述,它变得很清楚。
现在让我们谈谈不透明度。不透明度小于 1 的元素必须以特定的顺序(从后到前)呈现,并且在呈现背面不透明元素之后。虽然我不知道在 Chrome 和 Firefox 中这是如何实现的,但行为表明在 Chrome 中渲染顺序会以某种方式影响布局工作流程。这解释了为什么 opacity=1 的行为不同于 opacity=0.999。但这只会发生,因为存在没有定义行为的条件,如前所述。
因此解决方案非常简单:删除导致未定义行为的条件。由于 display: block
不影响图像大小,而只影响 space 元素占用,因此要做的事情很明显: 删除 display: block
并仅保留 [= img
元素上的 10=].
如果出于某种原因您不想删除 display: block
,您可以通过在容器上编码 overflow-y: scroll
强制滚动条始终可见(同时删除溢出属性) .这样您就不会删除导致未定义行为的条件,但会删除滚动条上的竞争条件。