CSS :hover 覆盖元素高度 0 后重新渲染
Posted
技术标签:
【中文标题】CSS :hover 覆盖元素高度 0 后重新渲染【英文标题】:CSS :hover rerender after covering element height 0 【发布时间】:2016-11-12 10:47:41 【问题描述】:我有一个我称之为 back
的元素被另一个我称之为 front
的元素覆盖。
Back
在 CSS 中设置为在悬停时更改颜色。 Front
设置为,当悬停时,在 1s
延迟和现在位于 Front
元素上的鼠标指针后消失位于返回元素上。
Front
通过在 javascript 中设置 height: 0
消失。在 Front
消失并且鼠标指针悬停在 Back
上后,浏览器不会重新渲染 Back
上的悬停效果导致其颜色没有按应有的方式改变。
当我通过从 DOM 中自然删除 Front
来尝试相同的示例时,它可以正常工作。不过,我的应用要求我通过设置 height: 0
来执行此操作。
您可以在以下示例中亲自尝试。您将看到一个红色框和一个蓝色框。红色是 Front
,蓝色是 Back
。当您将鼠标指针移到红色框时,红色框的颜色变为green
。当您将鼠标移到蓝色框上时,一秒钟后,它会消失。
这个例子的重点是表明在蓝色框消失后,鼠标指针现在悬停在红色框上,因此它应该变成green
。
在this example 中,蓝色框已从 DOM 中完全移除,并且可以正常工作。
不过,在this example 中,蓝色框将通过设置height: 0
来移除。消失后,红色元素不会变成green
,直到我移动鼠标。
有没有办法强制浏览器重新渲染?
问题在 Google Chrome 和 Microsoft Edge 中仍然存在。 Firefox 运行良好。
【问题讨论】:
【参考方案1】:不要尝试强制浏览器重新呈现,您只需向 foo
添加一个类,当 bar
消失,然后在 mouseleave
上恢复正常。
CSS:
#foo.hover, /* <- I just added this */
#foo:hover
background-color: green;
JavaScript:
var
foo = document.getElementById("foo"),
bar = document.getElementById("bar");
/* Set the 'mouseenter' event for bar to set the height to 0 and & the 'hover' class. */
bar.onmouseenter = function()
setTimeout(function()
bar.style.height = 0;
foo.classList.add("hover");
, 1000);
/* Set the 'mouseleave' event for bar to remove the 'hover' class. */
bar.onmouseleave = function()
foo.classList.remove("hover");
查看以下 sn-p 以获得直观的表示。
片段:
/* --- JavaScript --- */
var
foo = document.getElementById("foo"),
bar = document.getElementById("bar");
/* Set the 'mouseenter' event for bar. */
bar.onmouseenter = function()
setTimeout(function()
/* Set the height to 0. */
bar.style.height = 0;
/* Add the 'hover' class. */
foo.classList.add("hover");
, 1000);
/* Set the 'mouseleave' event for bar. */
bar.onmouseleave = function()
/* Remove the 'hover' class. */
foo.classList.remove("hover");
/* --- CSS --- */
#foo
width: 200px;
height: 200px;
background-color: red;
position: absolute;
top: 10px;
left: 15px;
#foo.hover,
#foo:hover
background-color: green;
#bar
width: 200px;
height: 200px;
background-color: blue;
position: absolute;
top: 100px;
left: 100px;
<!-- html -->
<div id = "foo"></div>
<div id = "bar"></div>
【讨论】:
我正在寻找一些没有JS的。【参考方案2】:这可能是浏览器问题,但有一些方法可以强制 webkit 重绘。但我不建议你这样做。您可以简单地使用 bar.style.display = 'none';
而不是将高度设置为零。
另一种强制重绘/重绘效果很好的解决方案:
sel.style.display='none';
sel.offsetHeight; // no need to store this anywhere, the reference is enough
sel.style.display='';
**
为避免闪烁,您可以尝试使用'inline-block'
、'table'
或'run-in'
而不是'none'
,但这可能会产生副作用。此外,超时 0 会触发重排,就像查询 offsetHeight 一样:sel.style.display = 'run-in'; setTimeout(function () sel.style.display = 'block'; , 0);
试试这个真的很管用!
【讨论】:
这确实有效,它是已在此处发布的最佳解决方案。但这在 Edge 中不起作用。 一种常见的设计模式是使用样式类来切换内联元素(例如锚点)的样式和内容。 jquery.mobile 包含样式类,可将您的锚元素转换为切换开关。【参考方案3】:只需使用 transition
属性就可以在 CSS 中实现。
#foo
width: 200px;
height: 200px;
background-color:red;
position: absolute;
top:10px;
left:15px;
z-index: 10;
#foo:hover
background-color: green;
#bar
width: 200px;
height: 200px;
background-color:blue;
position: absolute;
top:100px;
left:100px;
z-index: 20;
transition: all 1000000s;
#bar:hover
transition: all 0.01s;
opacity: 0;
z-index: 1;
<div id="foo"></div>
<div id="bar"></div>
【讨论】:
【参考方案4】:如果back完全被front覆盖,您可以在中设置front.style['pointer-events'] = 'none'
onmouseenter
回调,让鼠标在 front 消失之前激活 back 的 :hover
规则。
见modified working snippet。
【讨论】:
这不是ma case,但我考虑在我的项目中使用它。它可以帮助我。 谢谢。在我的情况下,pointerEvents 属性对我有帮助。赏金是你的,但我认为它不能回答这个一般性问题。【参考方案5】:这似乎真的是一个浏览器问题,there are some ways on how to force webkit to redraw。但我真的不建议你这样做。您可以简单地使用bar.style.display = 'none';
而不是将高度设置为零。具有相同的效果,一切都按预期工作。看到这个小提琴:https://jsfiddle.net/zkhorh38/4/。
【讨论】:
我的应用在front
(蓝色)元素中使用了嵌套元素(带有position: absolute
)。其中display: none
隐藏但height: 0
使其可见。
您的解决方案适用于 Chrome,但不适用于 Microsoft Edge。以上是关于CSS :hover 覆盖元素高度 0 后重新渲染的主要内容,如果未能解决你的问题,请参考以下文章