首页 > web前端 > css教程 > 更多现实世界的用途:has()

更多现实世界的用途:has()

Christopher Nolan
发布: 2025-03-09 11:51:12
原创
242 人浏览过

More Real-World Uses for :has()

CSS 的 :has() 伪类无疑是我最喜欢的 CSS 新特性之一,相信许多 State of CSS 调查参与者也认同这一点。这种“倒置”选择器的能力赋予了我们意想不到的强大功能。

之所以说是“更强大的功能”,是因为许多聪明的开发者已经发表了许多令人惊叹的巧妙想法,例如:

  • Jen Simmons 的《使用 :has() 作为 CSS 父选择器及更多》
  • Bramus 的《使用 CSS :has() 实现针对具有相同类别的“元素岛”的数量查询》
  • Bramus 的《根据子元素数量设置父元素样式》
  • Manuel Matuzović 的《在 :has() 中使用组合器》
  • Austin Gil 的《CSS :has() 让你的 HTML 表单更出色的四种方法》
  • Zoran Jambor 的《视频::has() 伪类的实用案例》
  • Jhey Tompkins 的《:has():家族选择器》

本文并非 :has() 的权威指南,也不是对现有内容的重复。我只是想分享一些我在日常工作中最可能使用 :has() 的方法……当然,前提是浏览器支持足够好。(Firefox 是最后一个坚持不懈的浏览器,但即将支持它。)

一旦浏览器支持完善,我肯定会在各个地方使用 :has()。以下是一些我最近构建的真实案例,当时我心想:“一旦 :has() 得到完全支持,这将会变得多么简洁!”

避免在 JavaScript 组件外部进行操作

你是否曾经构建过一个交互式组件,有时需要影响页面其他地方的样式?以下示例中,<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中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板