你可能之前使用过:nth-
伪元素选择器:比如使用:last-child
从列表中去掉最后一个元素的边框;或者使用:first-child
为一篇文章开始的段落添加一个边框,如下所示。
p:first-child {
padding-bottom : 1.5rem;
border-bottom : 1px solid #ebf4f6;
font-size : 1rem; }
还不错,只是选择首尾的元素来做一些简单的样式定义。只能做到这些吗?当然不是。
在处理可预见的情况时(列表中的项或者表格中的行),:nth-child
选择器的表现不错。但当我们不能预知元素的位置时,就需要一个更加灵活的选择。如果能根据类型或者元素在文档中的位置来选择岂不是更好?其实这就是:nth-of-type
伪元素选择器要做的,也是CSS的秘密之一。
想选中第一段,不管它出现在文档中的什么位置,都不是问题。那么要选中第四个无序列表例子中的第十三项呢?:nth-of-type
同样可以帮助你。任何目标元素,无论它出现在什么位置,都不需要id
或者class
属性,这确实很强大。
:nth-of-type
可以接受像odd
或者even
这样的关键字,也可以是数字或者表达式。听起来有点复杂,其实并不是,我们一起看几个例子。
如果你想为列表里的奇数项(一、三、五、七…)添加边框,使用:nth-of-type
就可以很轻松实现。你不需要为HTML添加class属性或者使用JavaScript hack,只需要用odd
关键字就可以。
li:nth-of-type(odd) {
border-bottom : 1px solid #ebf4f6; }
在下面的例子中,使用:nth-of-type
选择器给文章中的第一段文字加粗。
article p:nth-of-type(1) {
font-weight : bold; }
表达式相对复杂些,刚接触时我们都会觉得很烧脑。我的建议是从右往左倒着阅读。在下面的例子中,3n+1
表示匹配表格里的第一行(1
),然后是每隔3行(3n
)。
tr:nth-of-type(3n+1) {
background-color : #fff; }
6n+3
将匹配每隔六个元素后的第三个元素。
tr:nth-of-type(6n+3) {
opacity : .8; }
现在使用:nth-of-type
伪元素选择器来为每张卡片添加背景图像。
.h-card:nth-of-type(1) {
background-image : url(card-01.jpg); }
.h-card:nth-of-type(2) {
background-image : url(card-02.jpg); }
.h-card:nth-of-type(3) {
background-image : url(card-03.jpg); }
.h-card:nth-of-type(4) {
background-image : url(card-04.jpg); }
.h-card:nth-of-type(5) {
background-image : url(card-05.jpg); }
.h-card:nth-of-type(6) {
background-image : url(card-06.jpg); }
.h-card:nth-of-type(7) {
background-image : url(card-07.jpg); }
.h-card:nth-of-type(8) {
background-image : url(card-08.jpg); }
.h-card:nth-of-type(9) {
background-image : url(card-10.jpg)); }
在小屏幕上,卡片整齐地摆在一起。
因为我们只是希望显示元素的背景图像,所以通过缩进把HTML文本移到屏幕外。
.h-card * {
text-indent : -9999px; }
那些卡片虽然看起来不错,但是有点呆板,接下来我们给它们添加一些旋转变换的效果。我们不会给特定的卡片应用这些转换,而是通过:nth-of-type(n)
选择器来让设计看起来是随机的。我们把奇数的卡片逆时针旋转2度(-2deg
),让它们显得松散一些。
.h-card:nth-child(odd) {
transform : rotate(-2deg);
transform-origin : 0 100%; }
现在让我们继续调整,给3、4、6的倍数的每一个卡片设置不同的rotate
值,给6的倍数的卡片设置translate
值,让它们偏离原点。
.h-card:nth-child(3n) {
transform : rotate(2deg) translateY(-30px); }
.h-card:nth-child(4n) {
transform : rotate(2deg);
transform-origin : 0 100%; }
.h-card:nth-child(6n) {
transform : rotate(-5deg);
transform-origin : 0 0; }
多亏了transform
和伪元素选择器,现在这堆卡片变得一团糟。
在小屏幕上,那些名片很适合垂直的布局,然而在中大型屏幕上,垂直布局并不能很好地利用可用的空间。所以我们接下来使用伪元素通过定位和一些transform
,将卡片排成一个网格的形状。
再回到设计本身,我们需要给每张卡片设置定位,但又不需要在小屏幕上生效,所以我们使用媒体查询来让这些样式只应用于中大型屏幕。
@media (min-width: 48rem) {
.h-card {
position : absolute; }
}
通过定位,给每张卡片的顶部top
和左侧left
设置一些值,用来形成一个松散的网格。
@media (min-width: 48rem) {
.h-card:nth-of-type(1) {
top : 100px;
left : 0; }
.h-card:nth-of-type(2) {
top : 80px;
left : 320px; }
.h-card:nth-of-type(3) {
top : 100px;
left : 640px; }
.h-card:nth-of-type(4) {
top : 320px;
left : 40px; }
.h-card:nth-of-type(5) {
top : 270px;
left : 570px; }
.h-card:nth-of-type(6) {
top : 320px;
left : 600px; }
.h-card:nth-of-type(7) {
top : 540px;
left : 0; }
.h-card:nth-of-type(8) {
top : 560px;
left : 320px; }
.h-card:nth-of-type(9) {
top : 540px;
left : 640px; }
}
通过应用rotate
和translate
,设计看起来更自然。
你应该已经发现我故意出的错。第五张卡片与水平放置的卡片不同,它是垂直的。把卡片顺时针旋转90deg
,这个问题就解决了。旋转的原点transform-origin
位于卡片的左上角。
@media (min-width: 48rem) {
.h-card:nth-of-type(5) {
transform : rotate(90deg);
transform-origin : 0 0; }
}
当我们把它顺时针旋转90deg
并与其他卡片重叠后,这个孤零零的卡片看起来就好多了。
最后我们再做一点润色,给这些卡片添加一些RGBa阴影。
.h-card {
box-shadow :
0 2px 1px rgba(0,0,0,.8),
0 2px 10px rgba(0,0,0,.5); }
放大设计,左侧柔和的RGBa阴影增添了景深。