CSS :has(.parent-selectors) 👪
我不知道为什么我必须关注“科技推特”才能发现好消息,所以我在 dev.to 上写了一篇短文来庆祝新的 CSS 功能:
根据2021 年 CSS 状况调查,第二个最受期待的 CSS 功能“父选择器”(也称为has-selector)已获得浏览器支持!
引用 Sara Soueidan 在 Twitter 上引用 Jen Simmons 的话:
:has() 本质上是 CSS 中期待已久的父选择器🎊
不要说 Safari 总是垫底。有时我们也是第一。
但在庆祝这次“Safari 优先”之前,请注意,到 2022 年初,你可能还没有浏览器来测试父选择器。Safari 更新目前无法在旧版 Apple 操作系统上发布或安装。
不再“缺少 CSS”
现在 CSS 中不再缺少父选择器,让我们希望 Firefox 和 Chromium 能够快速跟进。
“父选择器”选择什么?
父选择器会选择父元素,对吧?实际上,它们也会选择祖父母元素以及任何匹配的祖先元素。
我并不是唯一一个将其视为:has()
“子选择器”的人,因此我应该称它们为“has-selectors”以避免误解吗?
Timothy Huang 称之为:has()
“一个 CSS 选择器,它可以选择带有子元素的父元素,这对我来说听起来像是一个恰当的描述。
例如,
a:has(>img)
选择所有<a>
包含<img>
子元素的元素。
性能考虑
实现时间如此之长的主要原因是担心计算成本过高。父选择器功能在实时应用于文档时,可能会影响网站的速度和性能。
Chris Coyier 引用了 Jonathan Snook(2010 年)的话“当元素在页面上动态添加和删除时,可能会导致整个文档需要重新渲染(主要存在内存使用问题)”。
当我们真正开始使用父选择器时,也许我们应该格外小心地衡量我们的性能?
避免性能问题的实施:
更新:性能问题可能已经解决了。Eric Meyer 提到了一篇关于该实现如何规避性能问题的详细讨论。
在 YouTube 上观看了 Byungwoo Lee 的视频后,我想说 Blink 引擎的策略在某种程度上类似于国际象棋引擎的效率,它必须弄清楚如何快速忽略不相关的动作,而不是预测每种可能的移动组合的每种可能结果。
对于 CSS,Blink 引擎会阻止无关元素的遍历和失效。为了减少应用样式后不相关的重新计算,引擎会:has()
在重新计算过程中标记样式是否受到状态变化的影响。
但是让 Byungwoo Lee 解释实现父选择器的问题和解决方案的细节。
他的解释包括复杂的用例,例如
.a:has(.b ~ .c)
或者
.a:is(:has(b), :has(c))
哇!我都不知道这居然是有效的 CSS。
永远不要停止学习!但千万别在代码审查中给我看这样的代码。我可能会要求你把它重构成更容易理解和维护的代码!
实际用例
我看到许多人都在努力想出如何使用 has 选择器的例子:你真幸运!
这是一个现实世界的例子:我必须对之前已经修复过的 Shopware 主题进行修复,而且情况紧急,!important
因此至少在路线图的这一部分没有干净的代码。
我希望我能:has()
在这里使用,以降低在CMS生成的标记中意外定位错误元素的风险。选择器太长了,你必须滚动才能看到全部!
/* override template heading style */
body.is-act-index .cms-sections .col-12 .cms-element-alignment.align-self-start {
使用has
可以使修复至少更清楚一点:
/* override template heading style */
body.is-act-index .cms-element-alignment:has(> h1) {
我们可能只是为了可读性而编写该代码。但我们必须确保浏览器支持。
如何填充 :has() 选择器?
由于新版 CSS 语法中没有办法绕过父选择器,因此它们无法被转译。别指望PostCSS或SASS 了!这次你需要 JavaScript 来 polyfill 旧版浏览器。
Eric Ponto 在 2015 年写道:“jQuery 的武器库中基本上一直都有 :has 选择器”,并且已经展示了一个基于 jQuery 的 polyfill:
Polyfill({
selectors: [":has"]
}).doMatched(rules => {
rules.each(rule => {
// just pass it into jQuery since it supports `:has`
$(rule.getSelectors()).css(rule.getDeclaration())
});
});
测验:如何在不使用 jQuery 的情况下进行 polyfill?
参加测验并提交您的 Vanilla JS 解决方案!
// TODO: add a parent selector polyfill without using jQuery
如果您知道解决方案,您还可以将其作为 StackOverflow 问题的答案发布,以了解是否存在与 jQuery .has() 等效的 vanilla JS。
querySelectorAllWithHas
Josh Larson 的 polyfill-css-has提供了一个querySelectorAllWithHas
(感谢@lukeshiru 提供的链接!)
但是我们已经在没有父选择器的情况下生活了很长时间,也许我们不想再担心了,而是继续进行 CSS 语言的下一次升级:
CSS 的下一步是什么?
2022 年 CSS 有何期待?
管道中还有更多有用的功能,例如CSS 容器查询,我们已经可以在 Chrome 和 Edge 中通过使用功能标志启用它们来使用它们。
本文是关于 CSS 新功能(以及被低估的功能)的小系列文章的一部分,您可以在 2022 年开始学习和使用这些功能。如果您想全面了解 2022 年 CSS 的新功能,请查看 @this-is-learning对 2022 年 CSS 状态报告的评论,并在我的2021/2022 开发书签/阅读清单帖子中找到更多有用的资源。
鏂囩珷鏉ユ簮锛�https://dev.to/ingosteinke/css-hasparent-selectors-287c