悬停零高度元素:浏览器错误?

时间:2017-04-03 11:16:57

标签: css google-chrome

在用户悬停父菜单项时处理(un)折叠的子菜单时,我遇到了以下问题。请考虑以下标记(在JSFiddle下方或上方)。

ul {
  max-height: 0;
  overflow: hidden;
  margin: 10px;
  padding: 0;
  border: 10px solid #bada55;
  list-style-type: none;
  transition: border-color .4s;
}
ul:hover {
  max-height: 100px;
  border-color: #de2d26;
}

ul > li {
  padding: 10px;
  pointer-events: auto;
}

.ignorant {
  pointer-events: none;
}

.offset {
  position: relative; /* This is the culprit! */
}
<ul class="ignorant">
  <li>I am ignorant of your pointer.
      If you see me, something went wrong!</li>
</ul>
<ul>
  <li>I am not. Hover me!</li>
</ul>
<ul class="ignorant offset">
  <li>I should be ignorant of your pointer.
      If you see me, something went wrong!</li>
</ul>

设置。我们这里有三个列表,其内容被隐藏,因为列表的max-height设置为0.仍然显示边框,这是预期的行为:元素by default的height指令仅适用于元素的内容。

我们通过将max-height设置为足够大的值来显示列表悬停时的内容。

现在,我想只在内容悬停时才显示列表,而不是边框​​。我认为,这应该可以使用pointer-events实现,如上所示。忽略边框上的事件,并在列表中的项目上重新启用它们。

问题。到目前为止,这很好,这在Firefox中运行良好,而Chrome中的主要是。也就是说,当我放置容器relative时,可以触发Chrome中内容的悬停。

Firefox仍然按照我的预期运行,不会触发悬停。当没有边框时,Chrome中也不再能够触发悬停。

问题。这是Chrome中的错误吗?或者是否没有明确说明应如何处理这种情况并因此未定义的行为?我会对以下任何一种感兴趣:
1.解释我做错了什么,为什么;
2.解释为什么不同的浏览器在这种情况下表现不同的原因;
3.简要解释为什么这是一个错误。在这种情况下,我很乐意报告一个。

此刻已通过测试进行了测试 •Firefox 52.0.1(64位Linux N );
•Firefox 52.0.2(64位Windows N );
•Internet Explorer 11.0.9600.17031(64位Windows N );
•Chrome 57.0.2987.133(64位Linux S ,64位Windows S );
•Chromium 57.0.2987.98(64位Linux S S 表示显示, N 表示在使用相对定位时悬停时不显示。

感谢BoltClock通过他们的建设性意见使这个问题变得更好。

2 个答案:

答案 0 :(得分:2)

Hover事件在this example验证的所有浏览器上以相同的方式冒泡。

ul {
  max-height: 0;
  /* overflow: hidden; */
  margin: 10px;
  padding: 0;
  border: 10px solid #bada55;
  list-style-type: none;
  transition: border-color .4s;
}

ul:hover {
  max-height: 100px;
  border-color: #de2d26;
}

ul > li {
  padding: 10px;
  pointer-events: auto;
  position: relative;
  top: 100px;
  background: yellow;
}

.ignorant {
  pointer-events: none;
}

.offset {
  position: relative;
}
<ul class="ignorant offset">
  <li>Hover me! Testing :hover across browsers...</li>
</ul>

我的结论是:

  • 我们使用的元素无关紧要,重要的是它们的位置和显示属性;
  • 当孩子有position: relativedisplay: inline
  • 时,不会发生这种情况

只有当鼠标位于子框模型覆盖与其父框模型相同像素的区域上时才会触发悬停。可以在蓝色矩形正上方的屏幕上看到此区域。甚至不说它是aqua或者什么,我是一个简单的程序员,我不知道颜色。

common box area fires hover event

Chrome会隐藏子元素,因为它的父级overflow: hidden属性是预期的行为。出乎意料的是,孩子的事件框(如果我可以称之为)仍然是“可见的”并且悬停在父母的边界上,就像它与overflow: visible一样。

奇怪的是,正如我之前所说,当孩子有position: relativedisplay而不是block时,它不会发生。

根据W3C

  

一旦盒子按照正常流动布置或浮动,它可以相对于该位置移动。这称为相对定位。以这种方式偏移方框(B1)对随后的方框(B2)没有影响:给B2一个位置,好像B1没有偏移,B2在应用B1的偏移后没有重新定位。

根据我的理解,这意味着position: relative对盒子没有任何影响。事实证明它是一个Chrome bug。

关于指针事件。 MDN states

  

请注意,通过使用指针事件来防止元素成为鼠标事件的目标,并不一定意味着不能或不会触发该元素上的鼠标事件侦听器。如果其中一个元素的子节点明确设置了指针事件,以允许该子节点成为鼠标事件的目标,则当事件沿父链传播时,任何以该子节点为目标的事件都将通过父节点,并触发事件侦听器。父母酌情。当然,在父母所覆盖但不是由孩子覆盖的屏幕上的某个点上的任何鼠标活动都不会被孩子或父母捕获(它将“通过”父母和目标下面的任何东西)。 / p>

这意味着Chrome没有在其父级之上显示子级的事件框,但实际上低于它。只是事件通过父元素并击中其子元素。但overflow: hidden不应该发生这种情况。

答案 1 :(得分:1)

我没有正式的解释,但我知道它与块格式化上下文MDNW3C)有关。我也非常自信@BoltClock,他对BFCs有了透彻的了解(我有时会怀疑他首先编写规范),如果他愿意的话,他将能够提供一个确切的技术解释

简而言之,知道源代码是知道修复(测试和工作):当您需要在父项上设置position:relative时,还要在子项上设置position:relative

/* ... */
.offset {
  position: relative; /* This is the culprit! */
}
.offset > * {
  position: relative; /* And this is the fix! */
}

&#13;
&#13;
ul {
  max-height: 0;
  overflow: hidden;
  margin: 10px;
  padding: 0;
  border: 10px solid #bada55;
  list-style-type: none;
  transition: border-color .4s;
}
ul:hover {
  max-height: 100px;
  border-color: #de2d26;
}

ul > li {
  padding: 10px;
  pointer-events: auto;
}

.ignorant {
  pointer-events: none;
}

.offset {
  position: relative; /* This is the culprit! */
}
.offset > * {
  position: relative; /* And this is the fix! */
}
&#13;
<ul class="ignorant">
  <li>I am ignorant of your pointer.
      If you see me, something went wrong!</li>
</ul>
<ul>
  <li>I am not. Hover me!</li>
</ul>
<ul class="ignorant offset">
  <li>I should be ignorant of your pointer.
      If you see me, something went wrong!</li>
</ul>
&#13;
&#13;
&#13;

这就是你想要的,对吧?跨浏览器。

注意: 必须 relative。它必须是static

之外的任何东西