以下是来自 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;
}
感谢您的文章。 我几个小时前也遇到了类似的问题。 我明天会尝试一下,看看能不能解决问题。
我发誓,overflow-x/y 的规范是最愚蠢的规范之一。 禁止使用诸如 visible/auto 之类的简单组合的理由是什么?
不要告诉我这是因为太复杂了……
这可能是因为该规范遵循了一条老路;遵循了 IE 5 中微软的原始实现。 改变这种行为会破坏这种向后兼容性。
感谢您的努力,文章写得很好。
真正的“结论”是,在 2014 年,我们仍然无法使用最新的 HTML/CSS 创建 2006 年就已是最新技术的菜单。
除了 2006 年之外,这个示例在小型移动设备上看起来不太好。 例如,我在现代 iPhone 上看到闪烁/闪耀的伪影。
我知道这些标准的借口,无需再赘述。 但是,如果没有一些警告(“一种桌面优先技术,用于……”),这种方法不应该出现在现代 Web 应用程序中。 如果我错了,请告诉我使用这种技术的实时生产网站。
在 2014 年,我们不能将移动设备置之不理,而且目前尚不清楚如何解决移动设备上的方法。 如果我们不能讨论房间里的大象,至少应该承认它的存在 :-)
再次感谢!
你说得对,我不会在移动设备上使用这种技术。
..或者在任何没有足够大的屏幕和持久光标来悬停在事物上的地方使用 ;)
这种技术主要帮助具有长菜单和列表的桌面应用程序,这些菜单和列表带有弹出窗口,以显示有关这些项目的更多信息。
standard-body,我实际上必须使用这种技术,我偶然发现了我们的内部应用程序。
是的,这是一个面向桌面的应用程序,在移动设备上不会使用它,主要是因为移动 UI/UEX 需要一组不同的要求。
是的,位置很棒,除了不合适的时候。 将其与可见性结合起来,您可能会在复杂的交互中拔掉头发。
很棒的文章。 我现在几乎每个项目都会遇到这个问题。 移动菜单设计模式似乎有一些需要解决的怪癖。 我会在我的下一个构建中记住这一点,因为我毫无疑问会再次遇到这个问题。
Position: fixed; 也可以位于任何 overflow: hidden; 元素之外,因为它只相对于视窗定位,因此也只接受视窗溢出。
很棒的文章。 但是溢出在移动设备上效果不佳。 除了使用第三方插件之外,还有其他解决方案吗?
我不确定这种方法是否适合移动体验,所以您可能需要进行一些创造性的渐进式增强。 由于有多个层级的菜单弹出,这种方法似乎最适合较宽的屏幕。
哇,这太棒了!
对于像我一样每天都要处理 IE7 的人来说:你知道吗? 它甚至在 IE7 上也能运行! (JSFiddle)
非常感谢这个技巧!! :)
真是巧合! 我昨天一直在为我被要求构建的移动滑动导航解决这个问题! 这在所有设备上都运行得很好。
为什么
.related-articles-title
、.comments-title
、.comments-title
有margin-bottom: -7px
?它被阻塞了。
http://codepen.io/davidyarham/pen/sHiGm
我之前做的事情,突破了溢出隐藏。
差点忘了 - 你也不必将顶层项目包装在 Div 包装器中,如果你想将它们内联定位或其他方式 :)。
纯 CSS 解决方案!!!
您好:
我已经使用纯 css 达成了相同的解决方案 - 不需要 JS 来正确定位子项 :)。
使用以下 css - 当然,可以随意更改属性以适应您的需求
干杯,精彩的编码!
Hey HueMan,你能分享一个可用的 CodePen 吗?
悬停已死兄弟。
来自 John Pearse,在评论关闭后发送给我
我明白 John 为什么要谈到滚动父菜单而不看到子菜单随之移动。这里提出的解决方案已经是 JS 解决方案了,因此更多的 JS 可以解决它(滚动事件处理程序,重新定位子菜单)。