聊聊那些你可能不知道的 CSS 选择器
关于 CSS 发展的一些思考
到今天为止,CSS3 在很多人的印象中似乎还是一个比较新的技术名词,其中很多模块的发展也很难引起大家的关注。但是 CSS3 可不是新东西,这个技术的发展从上个世纪就开始了。原因是什么呢?毫无疑问,是因为 JavaScript 的发展过于迅猛,进而催生出一堆以 SCSS/LESS 为代表的 CSS 预编译器工具。由于这类工具太好用了,反而大家的注意力就从 CSS 技术本身上迁移到 CSS 工具上面了。想想你有多久没有写过传统的 CSS 了呢?同时因为 All in JS 的趋势,很多样式相关的代码都被迁移到 JavaScript 中,比如 React 生态中以 StyledComponent 为代表的 CSS-in-JS 框架。那不用 CSS 写 CSS,反而使用 JavaScript 写 CSS 有什么缺点呢?有人认为性能不好;有人认为调试样式变得复杂;还有人认为职责不够分明。不管有多少不好,还是有人用,而且有大量的人用。这个道理其实也用在 UI 框架中,WebComponents 的发展很少有人关注,但是像 React 这类框架的一举一动却影响着无数的开发者。计算机领域有个名言:永远不要为了使用一个技术而用另一个技术。但是现在似乎不好用了。不过没关系,我们只要都去学就可以了。React 要学,ECMAScript Next 也要学。TailwindCSS 要学,CSS3、CSS4 也要学。这并不冲突。
CSS3 选择器
言归正传,今天这篇文章就来聊聊 CSS3 和 CSS4 中的几个比较新的选择器。CSS 选择器自然都不会陌生,这也是所有人学习 CSS 最先接触到的知识之一。CSS3 以来,选择器越来越复杂了,不再仅仅是 class 选择器,标签选择器,父子选择器等基础的选择器。
is 伪类选择器
这个选择器最早不叫作 is,而是叫 metches 或者是 any,但是现在已经被确定为 is。我们通过案例来看它的作用。我们设置 p 的默认颜色为黑色,但是在 main、header 和 footer 中为绿色。原生 CSS 需要这么写:
/* p 标签默认样式 */
p {
color: black;
}
/* p 标签在 main header 和 footer 中的样式 */
main p,
header p,
footer p {
color: green;
}
如果你用 SASS,它支持嵌套,所以可以应该这么写:
main, header, footer {
p {
color: green;
}
}
这样会让代码变得简洁。如果我们使用 is 选择器来解决这个问题的话,可以这么写:
:is(main, header, footer) p {
color: green;
}
is 支持所有的现代选择器,除了那么马上死掉的 IE。像一些更复杂的情况,比如这样:
article section.primary:not(:first-child) h1,
article section.primary:not(:first-child) h2,
article section.primary:not(:first-child) p,
article section.secondary:not(:first-child) h1,
article section.secondary:not(:first-child) h2,
article section.secondary:not(:first-child) p {
color: red;
}
我们使用 is 可以让它们变得更加简单。
article section:not(:first-child):is(.primary, .secondary) :is(h1, h2, p) {
color: red;
}
但是需要注意 is 不能匹配伪元素。像下面这样是跑不起来的。
p:is(::before, ::after) {
display: block;
content: 'pseudo';
}
where 伪类选择器
where 和 is 一样被所有现代浏览器支持,并且通常会和 is 有相同的作用,比如这样:
:where(main, header, footer) p {
color: green;
}
但是它们肯定不会完全一样,不然就没必要存在两个了。它们的区别在于 is 会提高选择器权重,但是 where 不会提高权重。像下面这个例子:
main p {
color: black;
}
:is(main, header, footer) p {
color: green;
}
:where(main, header, footer) p {
color: blue;
}
虽然 where 在后面,但是由于 is 会让权重变高,所以 p 的颜色还是绿色。所以 where 的优势是可以覆盖任何样式,也可以被任何样式覆盖,不需要使用权重更高的选择器或者 !important。
has 伪类选择器
has 选择器需要有一个目标元素,后面的参数是它的父元素。这是目前唯一一种可以选择父元素的选择器。下面是给所有包含 img 和 div 的 a 标签设置边框的用法:
a:has(img, div) {
border: 2px solid blue;
}
它还支持更复杂的用法,比如在表单按钮中:
/* 必填字段无效时设置红色边框 */
fieldset:has(:required:invalid) {
border: 3px solid red;
}
/* 必填字段无效时禁用提交按钮 */
fieldset:has(:required:invalid) + button[type='submit'] {
opacity: 0.2;
pointer-events: none;
}
在过去实现这种功能必须通过 JavaScript 的能力,但是现在不需要了。不过 has 选择器的支持度不如 is 和 where,Chrome 和 Safari 只提供了有限的支持,预计会在 2022 年底全面支持。
转载自:https://juejin.cn/post/7132785726688608287