原文链接:https://grack.com/blog/2015/01/09/abusing-css3-selectors/
如果你对这篇文章感兴趣,可以了解更多的有关 CSS4 的知识来提升自己。
CSS3的:nth-child
和 :nth-last-child
选择器的神奇之处,不仅仅是可以替代 :first-child
和 :last-child
选择器,它还可以匹配更为复杂的子元素,比如匹配某个元素(或除第一个元素外)的三个子孙元素,元素中四的倍数的子元素,又或者通过 a*n+b
这样的表达式来进行匹配子元素。
但你有没有想过这个选择器还有其他的妙用?比如,你可以使用它来获取仅有五个子元素的元素中的第三个元素子元素(接下来我们会介绍一个伪选择器 :nth-of-m-child
选择器)。你还可以获取仅有M个子元素的元素中的所有的子元素(另一个伪选择器,我们称之为 :family-of-m
)。
我们什么时候需要用这两个选择器呢?比如我们有一个大小不固定,个数不固定的照片墙,但不想依赖于JS来实现这个效果,能否实现呢?点击 示例 预览实现的效果。
src="http://10.168.0.151/zhengxuejiao/cssselector/image-count.html" width="550" height="300">选择含有M个子元素的第某个元素。
很感谢 xantys 向我提供了相关资料链接。资料1 和 资料2
首先,第一个我要介绍的是:nth-of-m-child
伪类。假设元素的子元素位置固定,我们可以通过结合使用:nth-child
和:nth-last-child
来获取元素。
如果,我们想获取仅含有五个子元素的第三个子元素 。示例
span:nth-child(3):nth-last-child(3) { ... }
由此我们得出一个通用的公式(m,n为变量)
如果,我们想获取仅含有五个子元素的第三个子元素 。示例
:nth-child(n):nth-last-child(m+1-n).
src="http://10.168.0.151/zhengxuejiao/cssselector/nth-test.html" width="550" height="300">
现在我们可以获取一共含有M个元素的第N个元素,如果我们想扩展一下,直接获取某个含有M个元素的父节点下的所有子元素。这里的秘密是我们使用了CSS3的~
兄弟选择器,它会暴力地匹配到所有的同级兄弟元素。如:
img ~ span { ... }
这种方法会获取到所有的同级的元素,而不管它一共有几个。那么,我们可以尝试结合加入我们的 :nth-of-m-child
选择器来实现。
span:nth-child(1):nth-last-child(5) ~ span { ... }
这种方法会获取到一共只含有5个子元素的第一个子元素(不包含它本身)的所有的兄弟节点,也就是说从第二个子元素到第五个子元素。最后,我们可以通过逗号,把第一个子元素的选择器加上,代码如下, 预览地址
span:nth-child(1):nth-last-child(5), span:nth-child(1):nth-last-child(5) ~ span { ... }
src="http://10.168.0.151/zhengxuejiao/cssselector/nth-family-test.html" width="550" height="300">
我们准备好了图片,接下来来填写它的样式。
一行展示一张图片是很容易的,但当我们准备放置三张图片,希望其中第一张或者第二张图片稍大一些,我们就会需要用到选择器匹配。我们的这种匹配方式可以不用在意图片的个数。
下面是一个带注释的例子。需要我们注意的是,可能使用弹性伸缩盒子更为简单实现,我们这里只是为读者提供一种练习使用这种选择器的方式。
我们使用第五个,第八个,第十一个….来进行特殊匹配。我们可以使用:nth-child(1):nth-last-child(3n+5)
来代替我们之前使用的:nth-child(1):nth-last-child(...)
这种方式,获取第 5,8,11,…等的子元素
/* First two are half-sized (99% / 2) */
img:first-child:nth-last-child(3n+5) ~ img, img:first-child:nth-last-child(3n+5) {
max-width: 49.5%;
margin-right: 1%;
}
/* Last n - 2 are (98% / 3) */
img:first-child:nth-last-child(3n+5) + img ~ img {
max-width: 32.6%;
margin-right: 1%;
}
/* But second, fifth, eighth, ... have no right margin */
img:first-child:nth-last-child(3n+5) ~ img:nth-child(3n+2) {
margin-right: 0;
}
想匹配6,9,12那就更容易了。
/* Six, nine, twelve, ... are all (98% / 3) */
img:first-child:nth-last-child(3n+6) ~ img, img:first-child:nth-last-child(3n+6) {
max-width: 32.6%;
margin-right: 1%;
}
/* Every third one of these has no right margin. */
img:first-child:nth-last-child(3n+6) ~ img:nth-child(3n) {
margin-right: 0;
}
7,10,13…类似于5/8/11
/* First four are half-sized (99% / 2) */
img:first-child:nth-last-child(3n+7) ~ img, img:first-child:nth-last-child(3n+7) {
max-width: 49.5%;
margin-right: 1%;
}
/* Last n - 4 are (98% / 3) */
img:first-child:nth-last-child(3n+7) + img + img + img ~ img {
max-width: 32.6%;
margin-right: 1%;
}
/* The second and fourth, seventh, tenth, ... have no right margin */
img:first-child:nth-last-child(3n+7) + img,
img:first-child:nth-last-child(3n+7) ~ img:nth-child(3n+4) {
margin-right: 0;
outline: 1px solid red;
}
我们可以通过使用:nth-child
和其他的选择器来实现更多有趣的效果。这种匹配方式也同样适用于 :nth-of-type
和:nth-last-of-type
。
这种方式在手机端和PC端并没有明显差距,但如果你介意的话,可以自己做一下测试。
如果你打算结合弹性盒子中的 flex-wrap 来简化示例,那么你可能可以更优雅的使用更多不同的尺寸来展示我们的图片。
你也可以将表达式中的参数改为even
或者 odd
,来匹配奇数偶数,或者其他限定符。
如果你对这篇文章有任何疑问或者更好的建议,可以通过JSFiddle展示给我。
欢迎关注我的Twitter账号@mmastrac ,与我联系。
2015.01.09