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 后重新渲染的主要内容,如果未能解决你的问题,请参考以下文章

更改DOM后刷新浏览器悬停效果

CSS 动画完成后应该 :hover 伪状态样式更改工作

如何强制 linux 上的 chrome 重新计算/重新渲染 ":hover" 样式?

渲染后如何获取元素的高度?

通过CSS3,实现元素覆盖效果

高度为 100% 的 Vue 组件在 v-if 重新渲染时改变高度