We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
今天群里讨论了一个非常有意思与 CSS 选择器相关的题目。题目如下:
假设我们如下的 HTML 结构:
<div class="box"> <p class="aa">aaaaaaaaaaaa</p> <p class="bb">bbbbbbbbbbbb</p> <p class="cc">cccccccccccc</p> <p class="aa">aaaaaaaaaaaa</p> <p class="bb">bbbbbbbbbbbb</p> <p class="cc">cccccccccccc</p> <p class="aa">aaaaaaaaaaaa</p> <p class="bb">bbbbbbbbbbbb</p> <p class="cc">cccccccccccc</p> </div>
效果如下:
如何在不添加类名的情况下,快速的选取第一个 class 为 .cc 的元素?
.cc
当然,上面的结构示意图只是一种可能的情况,这里想表述的场景的意思是:
<p>
.bb + .cc
.bb
基于上述的限定条件,你可以暂停阅读,思考 20 秒,可能的方式有哪些?
一般而言,比较容易想到的,肯定是首先使用 :nth-child 和 :nth-of-type 伪类选择器进行尝试。
:nth-child
:nth-of-type
但是,遗憾的是,这两个选择器都无法做到在上述结构下,成功选取第一个 .cc 元素。
代码如下:
.box .cc:nth-child(1) { color: red; font-size: 24px; }
或者
.box .cc:nth-of-type(1) { color: red;.box .cc:nth-child(1) { color: red; font-size: 24px; }
也就是说,上述两种方式,都是不行的。简单解释一下:
:nth-child()
这里最重要的是,它是根据父元素内的所有兄弟元素的位置来选择子元素,而我们无法得知在实际业务场景下,第一个 .cc 到底处于第几个索引。因此,这个选择器明显没法胜任。
非常重要的一点是,使用此选择器无法选择基于相同类名的元素的位置,来匹配元素。
什么意思呢?
如果我们把上述 DEMO 改造,改造成这样:
<div class="box"> <p class="aa">aaaaaaaaaaaa</p> <span class="bb">bbbbbbbbbbbb</span> <div class="cc">cccccccccccc</div> <p class="aa">aaaaaaaaaaaa</p> <span class="bb">bbbbbbbbbbbb</span> <div class="cc">cccccccccccc</div> <p class="aa">aaaaaaaaaaaa</p> <span class="bb">bbbbbbbbbbbb</span> <div class="cc">cccccccccccc</div> </div>
再基于上述结构下,选择第一个 class 为 .cc 的元素,就可以利用 :nth-of-type 实现。因为,所有的 .cc 都是 div 元素,且没有其它 div 元素:
div
.box div:nth-of-type(1) { color: red; font-size: 24px; }
当然,实际情况远没有如此乐观。在所有子元素标签情况无法确定的情况下,基于上述讨论,使用 :nth-child 或者 :nth-of-type 都不可行。还有什么办法呢?
按照上面说的,如果存在一个伪类 :nth-of-class,可以实现,基于相同类名的元素的位置,来匹配元素,那么问题就解决了。
:nth-of-class
但是实际情况是,目前 CSS 规范仍未支持 :nth-of-class 伪类选择器。
我们必须另辟蹊径。
好,现在我们换个思路,如果要我们选择,非第一个 class 为 .cc 的 .cc 元素,可以怎么实现呢?
可以利用 ~ 后续兄弟选择器实现:
~
.box .cc ~ .cc { color: red; font-size: 24px; }
成功了!此时,我们只需要基于上述结果,取反即可。在现代 CSS 中,我们可以利用 :not() 伪类实现。
:not()
:not() 伪类::not() CSS 伪类用来匹配不符合一组选择器的元素。由于它的作用是防止特定的元素被选中,它也被称为反选伪类(negation pseudo-class)。
改造一下上述的代码:
.box .cc:not(.cc ~ .cc) { color: red; font-size: 24px; }
这样,我们就成功的选取到了第一个 .cc 元素。
还有办法吗?
是的,在现代 CSS 中,:nth-child() 提供了一种更为强大的方式供我们使用。
从 Chrome 111,:nth-child() 提供了一种更为强大的特性,让我们能够方便的实现上述的效果,这种语法就是 :nth-child(1 of .foo)。
:nth-child(1 of .foo)
看看 [CanIUse - :nth-child(1 of .foo)(https://caniuse.com/?search=%3Anth-child):
我们能够通过 :nth-child(1 of .foo) 这个特性,间接实现 :nth-of-class 的效果:
.box .cc:nth-child(1 of .cc) { color: red; font-size: 24px; }
当然,利用这个特性,可以快速的选择任意 index 的 .cc 元素:
譬如第二个:
.box .cc:nth-child(2 of .cc) { color: red; font-size: 24px; }
完整的 DEMO,你可以戳这里:CodePen Demo -- 选择子元素下第一个类名为 xx 的元素
此功能由规范 Selectors Level 4 - :nth-child() pseudo-class 提出,感兴趣的可以看看规范原文定义。
of S
在掌握 of S 这个规则之后,我们就可以轻松的 Cover 非常多在之前选取起来非常困难的一些场景。
我们举几个例子一起看看,假设我们有如下的结构:
<div class="g-container"> <div class="g-item-triangle"></div> <div class="g-item-star"></div> <div class="g-item-hexagon"></div> <div class="g-item-triangle"></div> <div class="g-item-star"></div> <div class="g-item-hexagon"></div> <div class="g-item-star"></div> <div class="g-item-hexagon"></div> <div class="g-item-triangle"></div> <div class="g-item-star"></div> <div class="g-item-hexagon"></div> <div class="g-item-triangle"></div> <div class="g-item-triangle"></div> <div class="g-item-star"></div> <div class="g-item-hexagon"></div> <div class="g-item-triangle"></div> <div class="g-item-star"></div> <div class="g-item-hexagon"></div> </div>
简单的 CSS 代码如下:
.g-container { position: relative; width: 800px; height: 300px; display: flex; justify-content: space-between; flex-wrap: wrap; & > div { width: 120px; height: 120px; flex-shrink: 0; background: #fc0; } .g-item-triangle { clip-path: polygon(50% 0, 100% 100%, 0 100%); } .g-item-star { clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%); } .g-item-hexagon { clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%); } }
即可得到如下结构:
由于上述的三角形 .g-item-triangle、星形 .g-item-star以及六边形 .g-item-hexagon 都在同一个父容器下,并且它们都是使用 div 表示,只是有不同的 class 进行表示。
.g-item-triangle
.g-item-star
.g-item-hexagon
class
首先,我们来看看,我们的诉求是,如何选取所有元素下的第二个六边形元素?
你可能认为可以使用如下代码?
.g-item-hexagon:nth-child(2) { background: #f00; }
按照我们上面文章提到的,这显然是选不到的。
但是如果你了解了 :nth-child 的 of S 特性,这个问题就非常简单了:
:nth-child(2 of .g-item-hexagon) { background: #f00; }
这样,成功选取到了所有元素下的第二个六边形元素:
继续,此外,of S 规范还支持 2n、even、odd 这样匹配规则。
2n
even
odd
因此,当我们想选取偶数位数的三角形时,可以写成:
:nth-child(2n of .g-item-star) { background: #f00; } // OR, 下述写法也可以 :nth-child(even of .g-item-star) { background: #f00; }
最后,of S 规则还可以在内部再使用 :not() 伪类,实现某些特定元素的剔除。
譬如,我们希望去掉所有元素内部的星星元素,在剩下的元素中,再选取所有奇数序号的元素。
听起来有点麻烦,写起来很简单:
:nth-child(2n+1 of :not(.g-item-star)) { background: #f00; }
此时,效果如下:
这里应用 :not() 规则后,相当于把 .g-item-star 去掉,剩余的 .g-item-hexagon 和 .g-item-triangle 当成一个新的整体,应用 of S 前的规则。需要好好理解一下。
完整的 DEMO,你可以戳这里:CodePen Demo -- nth-child of S rule Demo
好了,本文到此结束,一个非常有意思的现代选择器功能,你学会了吗?希望本文对你有所帮助 :)
想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 -- iCSS前端趣闻 😄
更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。
如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
The text was updated successfully, but these errors were encountered:
这个会选取每个元素下的第一个 有没有办法选区整个document下的第一个 更进一步,限定到某个范围内的第一个
Sorry, something went wrong.
No branches or pull requests
今天群里讨论了一个非常有意思与 CSS 选择器相关的题目。题目如下:
假设我们如下的 HTML 结构:
效果如下:
如何在不添加类名的情况下,快速的选取第一个 class 为
.cc
的元素?当然,上面的结构示意图只是一种可能的情况,这里想表述的场景的意思是:
.cc
元素,在其父元素下,存在多个.cc
,所以需要精准定位第一个;.cc
元素一定不是其所有兄弟元素中的第一个;<p>
元素或者某个同类标签.bb + .cc
的方式直接进行选取,因为第一个.cc
元素的上一个元素不一定是.bb
,可以是其他任何元素;基于上述的限定条件,你可以暂停阅读,思考 20 秒,可能的方式有哪些?
使用 :nth-child 或者 :nth-of-type
一般而言,比较容易想到的,肯定是首先使用
:nth-child
和:nth-of-type
伪类选择器进行尝试。但是,遗憾的是,这两个选择器都无法做到在上述结构下,成功选取第一个
.cc
元素。代码如下:
或者
也就是说,上述两种方式,都是不行的。简单解释一下:
:nth-child
而言,:nth-child()
伪类根据元素在父元素的子元素列表中的索引来选择元素。最为核心的是,选择器,它是根据父元素内的所有兄弟元素的位置来选择子元素。这里最重要的是,它是根据父元素内的所有兄弟元素的位置来选择子元素,而我们无法得知在实际业务场景下,第一个
.cc
到底处于第几个索引。因此,这个选择器明显没法胜任。:nth-of-type
而言,基于相同类型(标签名称)的兄弟元素中的位置来匹配元素。非常重要的一点是,使用此选择器无法选择基于相同类名的元素的位置,来匹配元素。
什么意思呢?
如果我们把上述 DEMO 改造,改造成这样:
再基于上述结构下,选择第一个 class 为
.cc
的元素,就可以利用:nth-of-type
实现。因为,所有的.cc
都是 div 元素,且没有其它div
元素:效果如下:
当然,实际情况远没有如此乐观。在所有子元素标签情况无法确定的情况下,基于上述讨论,使用
:nth-child
或者:nth-of-type
都不可行。还有什么办法呢?使用 :nth-of-class 伪类?
按照上面说的,如果存在一个伪类
:nth-of-class
,可以实现,基于相同类名的元素的位置,来匹配元素,那么问题就解决了。但是实际情况是,目前 CSS 规范仍未支持
:nth-of-class
伪类选择器。我们必须另辟蹊径。
巧用 :has() 与后代选择器 ~
好,现在我们换个思路,如果要我们选择,非第一个 class 为
.cc
的.cc
元素,可以怎么实现呢?可以利用
~
后续兄弟选择器实现:效果如下:
成功了!此时,我们只需要基于上述结果,取反即可。在现代 CSS 中,我们可以利用
:not()
伪类实现。改造一下上述的代码:
这样,我们就成功的选取到了第一个
.cc
元素。还有办法吗?
是的,在现代 CSS 中,
:nth-child()
提供了一种更为强大的方式供我们使用。使用 :nth-child 伪类的现代特性
从 Chrome 111,
:nth-child()
提供了一种更为强大的特性,让我们能够方便的实现上述的效果,这种语法就是:nth-child(1 of .foo)
。看看 [CanIUse - :nth-child(1 of .foo)(https://caniuse.com/?search=%3Anth-child):
我们能够通过
:nth-child(1 of .foo)
这个特性,间接实现:nth-of-class
的效果:效果如下:
当然,利用这个特性,可以快速的选择任意 index 的
.cc
元素:譬如第二个:
效果如下:
完整的 DEMO,你可以戳这里:CodePen Demo -- 选择子元素下第一个类名为 xx 的元素
此功能由规范 Selectors Level 4 - :nth-child() pseudo-class 提出,感兴趣的可以看看规范原文定义。
进阶理解新特性
of S
规则及实际应用演示在掌握
of S
这个规则之后,我们就可以轻松的 Cover 非常多在之前选取起来非常困难的一些场景。我们举几个例子一起看看,假设我们有如下的结构:
简单的 CSS 代码如下:
即可得到如下结构:
由于上述的三角形
.g-item-triangle
、星形.g-item-star
以及六边形.g-item-hexagon
都在同一个父容器下,并且它们都是使用div
表示,只是有不同的class
进行表示。1.选取第二个六边形元素
首先,我们来看看,我们的诉求是,如何选取所有元素下的第二个六边形元素?
你可能认为可以使用如下代码?
按照我们上面文章提到的,这显然是选不到的。
但是如果你了解了
:nth-child
的of S
特性,这个问题就非常简单了:这样,成功选取到了所有元素下的第二个六边形元素:
2. 选取偶数位数的三角形
继续,此外,
of S
规范还支持2n
、even
、odd
这样匹配规则。因此,当我们想选取偶数位数的三角形时,可以写成:
效果如下:
3. 选取去掉星形元素后的所有奇数个数元素
最后,
of S
规则还可以在内部再使用:not()
伪类,实现某些特定元素的剔除。譬如,我们希望去掉所有元素内部的星星元素,在剩下的元素中,再选取所有奇数序号的元素。
听起来有点麻烦,写起来很简单:
此时,效果如下:
这里应用
:not()
规则后,相当于把.g-item-star
去掉,剩余的.g-item-hexagon
和.g-item-triangle
当成一个新的整体,应用of S
前的规则。需要好好理解一下。完整的 DEMO,你可以戳这里:CodePen Demo -- nth-child of S rule Demo
最后
好了,本文到此结束,一个非常有意思的现代选择器功能,你学会了吗?希望本文对你有所帮助 :)
想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 -- iCSS前端趣闻 😄
更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。
如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
The text was updated successfully, but these errors were encountered: