CSS :覆盖元素高度 0 后悬停重新渲染

CSS :hover rerender after covering element height 0

本文关键字:悬停 新渲染 高度 覆盖 元素 CSS      更新时间:2023-09-26

我有一个我称之为back元素被另一个我称之为front的元素覆盖。

Back在 CSS 中设置为在悬停时更改颜色。 Front在悬停时设置为在1s延迟后消失,并且Front元素上的鼠标指针现在位于后部元素上。

Front通过在 JavaScript 中设置height: 0而消失。 Front消失并且鼠标对象悬停在Back浏览器不会在Back上重新渲染悬停效果后,这会导致其颜色无法正常更改。

当我通过自然地从 DOM 中删除Front来尝试相同的示例时,它工作正常。但是,我的应用程序要求我通过设置height: 0来执行此操作。

您可以在以下示例中亲自尝试。您将看到一个红色框和一个蓝色框。红色是Front,蓝色是Back。将鼠标指针移到红色框时,红色框的颜色将更改为 green 。当您将鼠标移动到蓝色框上时,一秒钟后,它将消失。

该示例的重点是表明,在蓝色框消失后,鼠标指针现在悬停在红色框上,因此它应该变为green

在此示例中,蓝色框已从 DOM 中完全删除,并且它按预期工作。

但是,在此示例中,将通过设置 height: 0 来删除蓝色框。消失后,红色元素直到我移动鼠标后才会变得green

有没有办法强制浏览器重新渲染?

该问题在Google Chrome和Microsoft Edge中仍然存在。火狐效果很好。

与其尝试强制浏览器重新渲染,不如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");
}

查看以下代码片段以获取可视化表示形式。

片段:

/* --- 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>

这似乎真的是一个浏览器问题,有一些方法可以强制 webkit 重绘。但我真的不推荐给你。您可以简单地使用bar.style.display = 'none';而不是将高度设置为零。具有相同的效果,一切都按预期工作。看到这个小提琴:https://jsfiddle.net/zkhorh38/4/。

只需使用 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>

如果后方完全被前方覆盖,您可以先在onmouseenter回调中设置front.style['pointer-events'] = 'none',让鼠标在前方消失之前激活后方:hover规则。

请参阅修改后的工作片段。

这可能是浏览器问题,但有一些方法可以强制 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);

试试这个它真的有效!