barbabravo / blog

3 stars 1 forks source link

CSS 伪类选择器:如何使用 CSS3 伪类 #9

Open barbabravo opened 9 years ago

barbabravo commented 9 years ago

CSS 伪类选择器:如何使用 CSS3 伪类

任侠 2013-05-31 14:19 前端开发, 网站建设 抢沙发 11,114 views

CSS3 是个好东西,但也很容易被她的变形(transform)和动画(其中许多特性因浏览器厂商而异)特性所迷惑,因而忘了那些已经被添加到标准规范中的最为基本的选择器。许多强大的新伪类选择器(最新的 W3C 规范中列出了 16 条)使得我们能够在新的标准范围内使用元素选择器。

在探讨这些新的 CSS3 伪类之前,先简要回顾追溯一下这些在 Web 应用中常常被误解的 CSS 选择器。

  1. 伪类简史

在 1996 年,当 CSS1 的规范完成后,一些伪类选择器已被囊括在内,其中许多你几乎每天都在使用。例如:

这些状态都可以被应用到某个元素,通常是以 “a:伪类名”的形式。令人难以置信的是,在 W3C 于 1997 年 12 月发布 HTML4 规范之前,这些伪类已经被极为广泛地使用了。

1.1 CSS2 来了

于是 CSS2 来了。其建议规范在两年之后的 1998 年 5 月发布。随之令人兴奋的是添加了 :first-child 和 :lang() 新伪类。

:lang

有许多种表示文档语言类型的方法,如果你使用 HTML5,很可能会直接在 DOCTYPE 声明之后放置 语句(指定本地语种)。当然,你也可以使用 :lang(en) 伪类来修饰页面元素,对于语言动态变化的情况,这将非常有用。

:first-child

您可能已经在文档中使用 :first-child 属性。它通常用于添加或删除列表中第一个元素的上边框。奇怪的是,却没有 :last-child 这样的伪类与之对应。于是不得等到 CSS3 规范的对这两个兄弟伪类的支持。

1.2 为何使用伪类?

伪类如此实用的原因在于它们允许动态地设置内容样式。比如上面的 例子,我们能够描述当用户与链接进行交互时,链接该如何呈现样式。正如我们看到的,新的伪类允许我们根据元素在文档中的位置或状态,动态地设置其样式。

16 个全新伪类已经成为 W3C 的 CSS 建议的一部分,它们被分成四组:结构伪类、UI 元素的状态伪类、一个目标(target)伪类和一个否定伪类。

W3C 是 CSS 之家

现在我们一起探究看看如何使用这 16 个新伪类选择器。我会使用和 W3C 相同的标识符来命名 CSS 类,比如 E 代表元素(element),n 表示数字(number),s 表示选择器(selector)。

1.3 示例代码

大部分新选择器都会给出参考示例,以便直观地看到代码呈现效果。这里会涉及一张适用于 iPhone 并且使用了 CSS3 伪类的表单。

请注意,这张表单中大部分样式可以使用 id 和类(class)选择器设定。即便如此,仍然可以使用新伪类针为这个表单锦上添花。点击这里查看页面示例

Awesome Widgets

All the cool kids have got one

Where do we send your receipt?
Personal Details
Payment Details /

Would you like Insurance?

使用前和使用后的表单样式

  1. 结构伪类

根据 W3C 规范,结构伪类用来做下面的事:

…允许选择位于文档树的额外信息,但不能用其他简单的选择器或组合选择器代替。

这意味着我们拥有了能根据选择器在文档中的所处位置,动态选择内容的选择器。那么让我们从文档本身开始,即 :root 伪类。

W3C 上的 Level 3 选择器

E:root

:root 伪类选择页面的根元素。十有八九根节点是 元素,例如:

:root { background-color: #fcfcfc; }

除了给 元素设定样式,这个伪类基本没什么价值,可能也就描述性稍强些:

html { background-color: #fcfcfc; }

回到那张 iPhone 表单,为其添加基本的文本和背景样式:

:root { color: #fff; text-shadow: 0 -1px 0 rgba(0,0,0,0.8); background: url(…/images/background.png) no-repeat #282826; }

E:nth-child(n)

:nth-child() 选择器可能需要一些实践才能完全理解。最简单的记忆方法是使用关键词“奇数或偶数”(odd 或 even),因为在显示由行列组成的数据表格时,这将非常有用。例如,我们可以使用下列内容:

ul li:nth-child(odd) { background-color: #666; color: #fff; }

这将使无序列表中的每个奇数行高亮显示。您可能会发现在表格中使用这种技术非常方便。例如:

table tr:nth-child(even) { … }

:nth-child 选择器更明确灵活,因此,你可以选择列表的第三个元素,像这样:

li:nth-child(3) { … }

请注意 n 并不是从零开始,第一个元素是 :nth-child(1),第二个是 :nth-child(2),以此类推。

我们也可以利用一些简单的代数,使它变得更加精彩。考虑以下代码:

li:nth-child(2n) { … }

当我们以这种方式使用 n,它代表对所有正整数,直到文档耗尽可选择的元素。在这种情况下,它会选择下列列表项:

  • 未选择元素 (2 × 0)
  • 第 2 个元素 (2 × 1)
  • 第 4 个元素 (2 × 2)
  • 第 6 个元素 (2 × 3)
  • 第 8 个元素 (2 × 4)

这实际上和使用 :nth-child(even) 完全一致。因此我们混入点东西:

li:nth-child(5n) { … }

对应选择的节点元素:

  • 未选择元素 (5 × 0)
  • 第 5 个元素 (5 × 1)
  • 第 10 个元素 (5 × 2)
  • 第 15 个元素 (5 × 3)
  • 第 20 个元素 (5 × 4)

对于长列表或表格而言,也许这将很有用,也可能完全无用。我们还可以在这一公式中执行数字加减法:

li:nth-child(4n + 1) { … }

对应选择的节点元素:

  • 第 1 个元素 ((4 × 0) + 1)
  • 第 5 个元素 ((4 × 1) + 1)
  • 第 9 个元素 ((4 × 2) + 1)
  • 第 13 个元素 ((4 × 3) + 1)
  • 第 17 个元素 ((4 × 4) + 1)

这里 SitePoint 指出了一个怪癖的功能,如果你将 n 设置为负值,则可以像这样选择前 x 项。

li:nth-child(-n + x) { … }

如果你期望选择前 5 项,可以这样写:

li:nth-child(-n + 5) { … }

对应选择的节点元素:

  • 第 5 个元素 (-0 + 5)
  • 第 4 个元素 (-1 + 5)
  • 第 3 个元素 (-2 + 5)
  • 第 2 个元素 (-3 + 5)
  • 第 1 个元素 (-4 + 5)
  • 未选择元素 (-5 + 5)
  • 未选择元素 (-6 + 5)

如果你想要根据热门程度来列数据条目,并予以突出显示,也就是说,前十项可能是很有用的。

WebDesign & Such 创建了 斑马样式示例,这应该是一个 :nth-child 的最佳实践。

使用 CSS3 设置表格的斑马样式

如果没有需要设置样式的表格,那么你可以 Webvisionary Awards 奖已经做的和使用:第n -孩子式交替其网站部分。这里的css:

如果你的表格都不需要设置样式,那么你可以像 Webvisionary Awards 那样,使用 :nth-child 设置网站区块的交替样式。CSS 代码如下:

section > section:nth-child(even) { background:rgba(255,255,255,.1) url("../images/hr-damaged2.png") 0 bottom no-repeat; }

其效果很细微,但它增加了一个陈旧浏览器不支持的细节。

Webvisionary Awards 上使用的 :nth-child 选择器

iPhone 表单案例

继续回到那张 iPhone 表单案例,这个案例中几乎很少地方可以使用 :nth-child 伪类,但值得注意的一点是,我们期望对前三个字段集的 label 标签隐藏,取而代之使用占位符(placeholder)文本替代。CSS 代码如下:

form:nth-child(-n+3) label { display: none; }

这里,我们寻找

元素的前三个子节点,然后选取 label 元素,可以使用 display:none; 来隐藏。

E:nth-last-child(n)

我们并不仅仅满足于 :nth-child() 伪类,W3C 也给我们提供了 :nth-last-child(n) 伪类。它和 :nth-child() 的表现非常相似,除了反向操作,从最后一个向开始计算的功能。

li:nth-last-child(1) { … }

上述将选择列表中的最后一个元素,而下面将选择倒数第二个元素:

li:nth-last-child(2) { … }

当然,你也可以使用其他规则:

li:nth-last-child(2n+1) { … }

但你可能更倾向于使用以下方法选择最后五个列表元素(以上面讨论的逻辑为基础):

li:nth-last-child(-n+5) { … }

如果这仍然没有太大的意义,Lea Verou 创造了一个有用的 CSS3 结构伪类选择器测试工具,值得一试。

CSS3 结构伪类选择器测试工具

iPhone 表单案例

在案例中,我们可以使用 :nth-last-child 来为“Card number”字段添加圆角。以下 CSS 代码可能过于具体,但至少提供了一个关联伪类的方法:

fieldset:nth-last-child(2) input:nth-last-of-type(3) { border-radius: 10px; }

我们首先抓住倒数第二个字段,选择其中倒数第三个字段(这个案例中,是“Card Number”字段)。然后,我们添加一个圆角效果(border-radius)。

:nth-of-type(n)

现在我们将做得更加具体,只为特定类型的元素设定样式。例如,假设你想使得文章第一段具有较大的字体。CSS 代码如下:

article p:nth-of-type(1) { font-size: 1.5em; }

也许你要文章中的部分图片右对齐,另一部分左对齐。则可以使用关键字来控制:

article img:nth-of-type(odd) { float: right; } article img:nth-of-type(even) { float: left; }

通过 :nth-child() 和 :nth-last-child(), 你可以使用代数表达式:

article p:nth-of-type(2n+2) { … } article p:nth-of-type(-n+1) { … }

值得记住的是如果需要获得这些指定的目标元素,使用描述性的 CSS 类名可能更合理。

Simon Foster 创建了一个 关于 45 张 RPM 唱片集的漂亮图表,并且使用 :nth-of-type 来为某些数据设置样式。以下是他的代码片段,CSS 中各流派类型都做了区分。

ul#genre li:nth-of-type(1) { width:32.9%; background:url(images/orangenoise.jpg); } ul#genre li:nth-of-type(2) { width:15.2%; background:url(images/bluenoise.jpg); } ul#genre li:nth-of-type(3) { width:13.1%; background:url(images/greennoise.jpg); }

网站上是这样呈现的:

For the Record 中的 :nth-of-type 选择器应用

iPhone 表单案例

比方说,我们希望偶数序号的输入框元素有底部圆角。可以用 CSS 实现这一点:

input:nth-of-type(even) { border-bottom-left-radius: 10px; border-bottom-right-radius: 10px; }

该案例中,我们只期望应用到 “payment” 字段,因为个人信息含有三个文本输入框。处理方法有些棘手,要确保不会选择任何单选框。最终 CSS 代码:

payment input:nth-of-type(even):not([type=radio]) {

border-bottom-left-radius: 10px; border-bottom-right-radius: 10px; border-bottom: 1px solid #999; margin-bottom: 10px; }

我们将稍后讲解 :not 伪类。

:nth-last-of-type(n)

现在来看看 :nth-last-of-type() 从选定元素的末尾开始,并且倒序工作。

要选择文章的最后一段,可以这样使用:

article p:nth-last-of-type(1) { … }

当文章不确定是否以段楼你可能会选择这个选择器来代替 :last-child 伪类。

:first-of-type 和 :last-of-type

如果 :nth-of-type() 和 :nth-last-of-type() 对你而言不太灵活,你可以使用更简单的选择器取而代之,例如:

article p:nth-of-type(1) { font-size: 1.5em; }

也可以这么搞:

article p:first-of-type { font-size: 1.5em; }

正如你所期望的那样,使用 :last-of-type 效果完全一样,只不过从后续元素开始查找而已。

iPhone 表单案例

我们可以在这张表单中结合使用 :first-of-type 和 :last-of-type,特别是用于制作圆角。CSS 如下:

fieldset input:first-of-type:not([type=radio]) { border-top-left-radius: 10px; border-top-right-radius: 10px; }

fieldset input:last-of-type:not([type=radio]) { border-bottom-left-radius: 10px; border-bottom-right-radius: 10px; }

第一行 CSS 对所有具有 :first-of-type 伪类的 input 元素增加了圆角上边框,并且所在字段不是单选按钮。第二行对字段内的最后一个 input 元素增加圆角下边框。

:only-of-type

还有另一个选择器 :only-of-type()。用于选择那些和它父元素中与自身同类型的元素。例如下面的代码:

p { font-size: 18px; }

p:only-of-type { font-size: 18px; }

第一个选择器将影响到页面中的所有 p 元素,第二个选择器只会影响它父亲节点下的所有 p 元素。

如果数据库查询只返回一个结果数据,为这个内容设置样式时,用 :only-of-type 可能会很方便。

Devsnippet 创建了一个 Demo,说明如何在多个图片中为单个图片定义样式。

Devsnippet’s 的 :only-of-type 案例

iPhone 表单案例

这张表单中,我们可以确保所有输入字段,无论在顶部还是底部,都有圆角效果,并且是该输入字段的唯一子节点。CSS 代码如下:

fieldset input:only-of-type { border-radius: 10px; }

:last-child

这是一个奇怪的地方::first-child 是 CSS2 的规范,但 :last-child 却在 CSS3 中才出现。也不需要过多语言解释,:last-child 用于选择父元素下的最后一个子节点。例如:

li { border-bottom: 1px solid #ccc; }

li:last-child { border-bottom: none; }

这是一个从列表底部消除边框的有用方法,在 WordPress 小工具中可以经常看到这种应用。

Rachel Andrew 在他的 Cleaner Code With CSS3 Selectors 文章里谈论了 :last-child 和其他 CSS 伪类。他告诉我们如何使用这个伪类创建一份良好格式的图片画廊,而无需额外的 CSS 类。

Rachel Andrew 的 :last-child 伪类使用案例

:only-child

如果某个元素是它的父节点的唯一子节点,那么你可以使用 :only-child 选择它。不像 :only-of-type 伪类,并且和元素类型无关。例如:

li:only-child { … }

我们可以使用它来选择