CSS 的 :has()
伪类无疑是我最喜欢的 CSS 新特性之一,相信许多 State of CSS 调查参与者也认同这一点。这种“倒置”选择器的能力赋予了我们意想不到的强大功能。
之所以说是“更强大的功能”,是因为许多聪明的开发者已经发表了许多令人惊叹的巧妙想法,例如:
本文并非 :has()
的权威指南,也不是对现有内容的重复。我只是想分享一些我在日常工作中最可能使用 :has()
的方法……当然,前提是浏览器支持足够好。(Firefox 是最后一个坚持不懈的浏览器,但即将支持它。)
一旦浏览器支持完善,我肯定会在各个地方使用 :has()
。以下是一些我最近构建的真实案例,当时我心想:“一旦 :has()
得到完全支持,这将会变得多么简洁!”
你是否曾经构建过一个交互式组件,有时需要影响页面其他地方的样式?以下示例中,<nav></nav>
是一个 mega 菜单,打开它会更改上方内容的颜色。
我觉得我总是需要做这种事情。
这个具体的例子是我为一个网站制作的 React 组件。我不得不使用 document.querySelector(...)
“触及”页面的 React 部分之外,并在 <header></header>
、<main></main>
或其他组件上切换一个类。这并非世界末日,但感觉确实有点别扭。即使在一个完全的 React 网站(例如 Next.js 网站)中,我也必须在管理更高组件树上的 menuIsOpen
状态或执行相同的 DOM 元素选择之间做出选择——这不太符合 React 的风格。有了 :has()
,问题就解决了:
header:has(.megamenu--open) { /* 如果包含具有类“.megamenu--open”的元素,则以不同的方式设置 header 样式 */ }
我的 JavaScript 组件不再需要处理 DOM 的其他部分了!
为表格添加交替的行“条纹”可以改善用户体验。它们可以帮助你的眼睛在扫描表格时跟踪当前所在的行。
但根据我的经验,这在只有两三行的表格上效果不佳。例如,如果你的表格在 <tbody> 中有三行,并且你对每“偶数”行进行“条纹”处理,你最终可能只有一条条纹。这并不值得采用这种模式,并且可能会让用户疑惑那一个高亮显示的行有什么特别之处。使用 Bramus 使用 <code>:has()
根据子元素数量应用样式的技术,我们可以在有超过三行时应用表格条纹:
想要更高级的功能?你还可以决定只有在表格至少有特定数量的列时才执行此操作:
header:has(.megamenu--open) { /* 如果包含具有类“.megamenu--open”的元素,则以不同的方式设置 header 样式 */ }
我经常需要根据页面上的内容更改页面布局。以以下网格布局为例,主要内容的位置会根据是否存在侧边栏而更改网格区域。
这可能取决于 CMS 中是否设置了同级页面。我通常会使用模板逻辑来有条件地向布局包装器添加 BEM 修饰符类,以适应这两种布局。该 CSS 可能如下所示(为简洁起见,省略了响应式规则和其他内容):
table:has(:is(td, th):nth-child(3)) { /* 只有在有三列或更多列时才执行操作 */ }
当然,从 CSS 的角度来看,这完全没问题。但这确实使模板代码有点混乱。根据你的模板语言,有条件地添加一堆类可能会变得非常难看,尤其是在你必须对许多子元素也这样做的情况下。
将其与基于 :has()
的方法进行对比:
/* m = 主要内容 */ /* s = 侧边栏 */ .standard-page--with-sidebar { grid-template-areas: 's s s m m m m m m m m m'; } .standard-page--without-sidebar { grid-template-areas: '. m m m m m m m m m . .'; }
老实说,从 CSS 的角度来看,这并没有好多少。但在我看来,从 HTML 模板中移除条件修饰符类是一个不错的收获。
很容易想到 :has()
的微型设计决策——例如,当卡片中包含图像时——但我认为它对于这些宏观布局更改也非常有用。
如果你阅读过我之前的文章,你会知道我是一个特异性方面的坚持者。如果你像我一样,不希望在整个样式中添加 :has()
和 :not()
时特异性分数激增,请务必使用 :where()
。
这是因为 :has()
的特异性基于其参数列表中最具体的元素。因此,如果你在其中包含类似 ID 的内容(我不知道为什么!),你的选择器将很难在级联中被覆盖。
另一方面,:where()
的特异性始终为零,永远不会增加特异性分数。
/* m = 主要内容 */ /* s = 侧边栏 */ .standard-page:has(.sidebar) { grid-template-areas: 's s s m m m m m m m m m'; } .standard-page:not(:has(.sidebar)) { grid-template-areas: '. m m m m m m m m m . .'; }
这些只是我迫不及待想要在生产环境中使用的一些功能。CSS-Tricks Almanac 也提供了一些示例。你期待用 :has()
做什么?你遇到过哪些 :has()
将是完美解决方案的真实案例?
以上是更多现实世界的用途:has()的详细内容。更多信息请关注PHP中文网其他相关文章!