从隐藏的溢出中弹出

Avatar of Agop Shirinian
Agop Shirinian

DigitalOcean 为您的旅程的每个阶段提供云产品。立即开始使用 价值 200 美元的免费积分!

以下是来自 Agop Shirinian 的客座文章。 Agop 遇到了一种有趣的情况,他需要一个元素在一个方向上可滚动,而在另一个方向上允许溢出。 你可能会认为这就是 overflow-x 和 overflow-y 的作用,但实际上并非如此简单。 我会让 Agop 来解释。

因此,您需要创建一个可滚动的菜单,其中包含在您将鼠标悬停在父菜单项上时弹出的子菜单。

简单!

为菜单创建一个列表,为子菜单添加一些嵌套列表,根据其父列表项定位嵌套列表,瞧!

查看 CodePen 上 Agop 的示例 可滚动菜单,带有弹出式子菜单(已损坏) (@agop)。

等等,不对。 哦,当然,我们使用了 overflow: auto – 也许如果我们使用 overflow-x: visible,子菜单的水平溢出将可见

查看 CodePen 上 Agop 的示例 可滚动菜单,带有弹出式子菜单(已损坏 #2) (@agop)。

怎么回事? 为什么我们仍然看到滚动条?

问题

如果我们查看 W3C 规范,我们会发现以下解释

‘overflow-x’ 和 ‘overflow-y’ 的计算值与其指定的数值相同,除了某些与 ‘visible’ 的组合不可用:如果一个指定为 ‘visible’,而另一个指定为 ‘scroll’ 或 ‘auto’,则 ‘visible’ 将被设置为 ‘auto’。

基本上,这

overflow-x: visible;
overflow-y: auto;

变成了这样

overflow-x: auto;
overflow-y: auto;

因此,如果垂直溢出不可见,我们就不能有可见的水平溢出,反之亦然。

如果我们不能有可见的水平溢出,我们就不能有弹出式的子菜单!

解决方案

有趣的是,如果我们从菜单项中省略 position: relative,子菜单就会显示出来,根据其最近的定位祖先定位。 在这种情况下,它们没有定位祖先,因此它们相对于 <body> 定位。

查看 CodePen 上 Agop 的示例 可滚动菜单,带有弹出式子菜单(步骤 1) (@agop)。

基本上,为了使绝对定位的元素出现在具有 overflow: hidden 的元素之外,其最近的定位祖先也必须是具有 overflow: hidden 的元素的祖先。

了解这一点后,我们可以围绕菜单添加一个包装器,用作每个子菜单的最近定位祖先。 然后,每当用户将鼠标悬停在菜单项上时,我们可以使用一些 JavaScript 定位子菜单包装器。

查看 CodePen 上 Agop 的示例 可滚动菜单,带有弹出式子菜单 (@agop)。

就是这样! 由于菜单和菜单项都没有定位,因此子菜单能够从隐藏/可滚动的溢出中弹出。 现在,我们可以根据需要创建任意层级的嵌套子菜单,并且不会出现任何意外裁剪。

结论

不幸的是,这种显示原本会被隐藏的项目的方法非常模糊。

如果我们可以指定一个裁剪深度,这将控制层次结构中哪个祖先负责裁剪特定元素,那就太好了。

./* Fair warning: not real code */
.submenu {
  /* only an ancestor 2 levels up can clip this element */ 
  clip-depth: 2;
}

或者,更好的是,也许我们可以通过 CSS 选择器指定裁剪父级。

/* Fair warning: not real code */
.submenu {
  /* only an ancestor that matches the .panel selector can clip this element */
  clip-parent: .panel;
}