在CSS中,选择器用来指定页面上我们想要样式化的 HTML 元素。CSS选择器提供了许多种方法,让我们在选择样式化元素时,可以做到非常精确的地步。在本文中,我们会详细介绍选择器的不同种类和使用方式,并了解他们的工作原理。
何为选择器
CSS 选择器是 CSS 规则中的第一部分。它是元素和其他部分组合起来告诉浏览器哪个 HTML 元素应该被选为应用规则中的 CSS 属性值的方法。被选择器选中的元素,叫做“选择器的对象”。
CSS 中,选择器由 CSS 选择器规范来加以定义。就像 CSS 的其他部分一样,需要浏览器的支持才能工作。绝大多数的选择器都是在 CSS 3 中定义的。因为这是一个成熟的规范,所以你会发现,大多数的浏览器对这些选择器有良好的支持。
选择器列表
如果同时使用多个相同样式的 CSS 选择器,那么这些单独的选择器就可以被混编成一个“选择器列表”。这样,样式就能应用到所有的单个选择器上了。例如,在 h1 和 .special 类中具有相同的CSS,那么我们可以分成两部分来写。
h1{
color: blue;
}
.special{
color: blue;
}
也可以把它们组合起来,在它们之间加个逗号,变成选择器列表。
h1,.special{
color: blue;
}
也可以进行换行,这样会更好读些。
h1,
.special{
color: blue;
}
在使用选择器列表时需要注意,如果其中任何一个选择器无效(存在语法错误),那么整个选择器列表都会被忽视,无法生效。
在以下示例中,无效的 class 选择器会被忽视,但 h1 选择器人会生效。
h1 {
color: blue;
}
..special {
color: blue;
}
如果组合起来的话,整个规则都会失效,h1 和 class 都不会生效。
h1,
..special {
color: blue;
}
选择器的种类
在 CSS 中,有许多不同种类的选择器,只有在了解过后,才能更好的使用它们。接下来将详细介绍不同种类的选择器。
属性选择器
存否与值选择器
存否与值选择器是通过一个元素是否存在或者根据不同的属性值来选取元素。
- [attr] : 匹配带有 attr 属性的元素。input[type] 是选择所有带有
type属性的<input>元素。 - [attr = value] : 匹配值为 value 的 attr 属性的元素。input[type = "text"] 是选择所有
type属性,值为"text"的<input>元素。 - [attr~= value] : 匹配带有指定属性且包含一个以空格分隔的列表中的给定词的所有元素。
p[class~="intro"]将会选择所有 class 属性值包含 "intro"(作为独立单词)的<p>元素。 - [attr|=value] : 匹配带有指定属性且值以给定值开头,后面跟一个连字符(-) 的所有元素。通常用于语言子代码中。
div[lang|="en"]将会选择所有 lang 属性值以 "en" 开头的<div>元素。
在下面的示例中,将展示这些选择器是如何工作的。
- 使用
li[class],我们就能匹配任何有 class 属性的选择器。这匹配了除了第一项以外的所有项。 li[class="a"]匹配带有一个a类的选择器,不过不会选中一部分值为a而另一部分是另一个用空格隔开的值的类,它选中了第二项。li[class~="a"]会匹配一个a类,不过也可以匹配一列用空格分开、包含a类的值,它选中了第二和第三项。
代码如下:
<h1>Attribute presence and value selectors</h1>
<ul>
<li>Item 1</li>
<li class="a">Item 2</li>
<li class="a b">Item 3</li>
<li class="ab">Item 4</li>
</ul>
li[class] {
font-size: 200%;
}
li[class="a"] {
background-color: yellow;
}
li[class~="a"] {
color: red;
}
效果:
子字符串匹配选择器
使用这些选择器让更高级的属性的值的子字符串的匹配变得可行。例如,同时拥有box-warning 和 box-error类,如果想把开头为 "box- " 字符串的所有元素都选上,那么可以使用 [class^="box-"] 来把它们同时选中。
[attr^=value]: 匹配以 value 开头的、名为 attr 属性的元素。a[href^="https"]将会选择所有 href 属性值以 "https" 开头的<a>元素。[attr$=value]: 匹配以 value 结尾的、名为 attr 属性的元素。img[src$=".jpg"]将会选择所有 src 属性值以 ".jpg" 结尾的<img>元素。[attr*=value]: 匹配带有 attr 属性且值中含有 value 的所有元素。a[href*="example"]将会选择所有 href 属性值中含有 "example" 的<a>元素。
下个示例展示了这些选择器的用法:
li[class^="a"]匹配了任何值开头为a的属性,于是匹配了前两项。li[class$="a"]匹配了任何值结尾为a的属性,于是匹配了第一和第三项。li[class*="a"]匹配了任何值的字符串中出现了a的属性,于是匹配了所有项。
<h1>Attribute substring matching selectors</h1>
<ul>
<li class="a">Item 1</li>
<li class="ab">Item 2</li>
<li class="bca">Item 3</li>
<li class="bcabc">Item 4</li>
</ul>
li[class^="a"] {
font-size: 200%;
}
li[class$="a"] {
background-color: yellow;
}
li[class*="a"] {
color: red;
}
请注意,如果想要在大小写不敏感的情况下去匹配属性值的话,可以在方括号中添加
i 值。这个标记告诉浏览器,要以大小写不敏感的方式匹配 ASCII 字符。没有了这个标记的话,值会按照文档语言对大小写的处理方式,进行匹配——HTML 中是大小写敏感的。
我们将利用一个示例来演示一下。
<h1>Case-insensitivity</h1>
<ul>
<li class="a">Item 1</li>
<li class="A">Item 2</li>
<li class="Ab">Item 3</li>
</ul>
li[class^="a"] {
background-color: yellow;
}
li[class^="a" i] {
color: red;
}
不难看出,第一个选择器将会匹配一个开头为
a的值,这样它只匹配了第一项,因为另外两项开头是大写的 A。第二个选择器使用了大小写不敏感的标记,于是匹配了所有项。
伪类和伪元素选择器
什么是伪类?
伪类是选择器中的一种,它用于选择特定状态下的元素,如当它们是这一类型的第一个元素时,或者是当鼠标指针悬浮在元素上面的时候。它们表现得会像是你向你的文档的某个部分应用了一个类一样,帮你在你的标记文本中减少多余的类,让你的代码更灵活、更易于维护。
伪类是以冒号开头的关键字。例如,:hover 就是一个伪类。
简单伪类示例
如果我们想要让一篇文章中的第一段加大加粗,可以在此段上添加一个类,再为那个类添加 CSS 。
<article>
<p class="first">
蔬菜对你有好处,所以你需要多吃大头菜、大葱、白萝卜、苋菜、番茄酱、甜瓜、红豆、大蒜。
</p>
<p>
秋葵浓汤、甜菜叶、玉米、鸡冠菜、菊苣、秋葵浓汤、葫芦。欧芹、葱、西葫芦、塌棵菜、豌豆芽、蚕豆、羽衣甘蓝、蒲公英、秋葵、裙带菜、番茄。蒲公英、黄瓜、花生、豌豆、花生、鸡冠菜、西葫芦。
</p>
</article>
.first {
font-size: 120%;
font-weight: bold;
}
不过,这在维护的时候可能会很恼人——要是文档的头部又加上一段的话呢?我们会需要把这个类挪到新加的这段上。假如我们不加类,我们可以使用(
:first-child)伪类选择器——这将一直选中文章中的第一个子元素,我们将不再需要编辑 HTML(编辑 HTML 并不总是可行,也许是因为它是由一个 CMS 生成的)。
article p:first-child {
font-size: 120%;
font-weight: bold;
}
效果依旧一样。所有的伪类都可以以同样的方式来实现。它们将选中文档中的处于某个状态的那部分,表现得像已经向 HTML 中添加 CSS 一样。
用户行为伪类
有些伪类只会在用户与文档交互时才会应用,这些伪类被称为用户行为伪类,也被称为动态伪类,表现得就像是一个类在用户和元素交互的时候加到了元素上一样。
<p><a href="">悬停在我上方</a></p>
a:link,
a:visited {
color: rebeccapurple;
font-weight: bold;
}
a:hover {
color: hotpink;
}
运行后就会发现,正常情况下字体是紫色,当鼠标悬停在字体上时,字体会变成粉色。
这里使用了两个伪类:
- :hover—— 在用户将鼠标悬停在元素上时才会激活,一般为链接元素。
- :focus—— 当用户使用键盘操控,选定元素时触发。
伪元素是啥?
伪元素也是以类似的方法表现。不过是像往 HTML 中添加新的 HTML 元素,而不是添加类。
伪元素开头为双冒号 ::。比如,::before 就是一个伪元素的示例。但在早期也会用单冒号来表示伪元素。
例如,如果你想选中一段的第一行,你可以把它用一个<span>元素包起来,然后使用元素选择器;不过,如果包起来的单词/字符数目长于或者短于父元素的宽度,这样做会失败。由于我们一般不会知道一行能放下多少单词/字符——因为屏幕宽度或者字体大小改变的时候这也会变——通过改变 HTML 的方式来可预测地这么做是不可能的。
::first-line伪元素选择器会值得信赖地做到这件事——即使单词/字符的数目改变,它也只会选中第一行。
<article>
<p>
蔬菜对你有好处,所以你需要多吃大头菜、大葱、白萝卜、苋菜、番茄酱、甜瓜、红豆、大蒜。
</p>
<p>
秋葵浓汤、甜菜叶、玉米、鸡冠菜、菊苣、秋葵浓汤、葫芦。欧芹、葱、西葫芦、塌棵菜、豌豆芽、蚕豆、羽衣甘蓝、蒲公英、秋葵、裙带菜、番茄。蒲公英、黄瓜、花生、豌豆、花生、鸡冠菜、西葫芦。
</p>
</article>
article p::first-line {
font-size: 120%;
font-weight: bold;
}
这表现得就像是
<span>神奇地包在第一个被格式化的行一样,每当行长改变的时候还会更新。
你可以看到它把两段的第一行都选中了。
::before 和 ::after
::before 和 ::after 是一组特别的伪元素,它们和 content 属性一同使用,利用 CSS 将内容插到文档中。
我们通常不会在 Web 浏览器中利用 CSS 插入文本字符串。因为对于一些屏幕阅读器来说,文本是不可见的,而且也不利于别人的查找和编辑。所以更推荐插入图表,作为一个视觉提醒,同时也不希望屏幕阅读器能读出它。
<p class="box">我的 HTML 页面的盒子中的内容。</p>
.box::after {
content: " ➥";
}
::before 和 ::after 伪元素与 content 属性的共同使用,在 CSS 中被叫做“生成内容”,而且你会见到这种技术被用于完成各种任务。
关系选择器
后代选择器
后代选择器——使用单个空格(“ ”)来组合两个选择器,其中,第一个选择器定义父级或祖先元素,最后一个选择器定义目标元素。 这些选择器之间用空格分隔。后代选择器会选择所有符合条件的后代元素,而不只是直接子元素。
<div class="content">
<p>这是一个段落。</p>
<ul>
<li>列表项1</li>
<li>列表项2</li>
</ul>
<div>
<p>这是另一个段落。</p>
</div>
</div>
.content p {
color: blue;
}
这段 CSS 会把.content类下所有的 <p> 元素的文字颜色设置成蓝色,不管这些 <p> 元素是位于.content中还是更深一层嵌套在其他元素中。
子代关系选择器
自带关系选择器是个大于号(>),只会选择指定父元素的直接子元素。这意味着,如果一个元素嵌套在另一个元素中,则不会被选中。
我们将在有序列表中嵌套一个无序列表来演示。我们用子代关系选择器,只选中为<ul>的直接子元素的<li>元素,给了它们一个顶端边框。
如果除去 > 的话,它就会变成后代选择器,为所有的 <li> 添加红色的边框。
<ul>
<li>Unordered item</li>
<li>Unordered item
<ol>
<li>Item 1</li>
<li>Item 2</li>
</ol>
</li>
</ul>
ul > li {
border-top: 5px solid red;
}
相邻兄弟选择器
相邻兄弟选择器是用于选择紧接在另一个元素之后的元素,且这两个元素拥有同一个父元素。简单来说,它会选择紧跟在指定元素后的第一个兄弟元素。这种选择器是通过 + 来连接。
通常情况下,会用于改变紧跟在标题之后的段落。如果往<h1>和<p>之间插入其他的某个元素,例如<h2>,你将会发现,段落不再与选择器匹配,因而不会应用元素邻接时的前景和背景色。
<article>
<h1>A heading</h1>
<p>Veggies es bonus vobis, proinde vos postulo essum magis kohlrabi welsh onion daikon amaranth tatsoi tomatillo
melon azuki bean garlic.</p>
<p>Gumbo beet greens corn soko endive gumbo gourd. Parsley shallot courgette tatsoi pea sprouts fava bean collard
greens dandelion okra wakame tomato. Dandelion cucumber earthnut pea peanut soko zucchini.</p>
</article>
h1 + p {
font-weight: bold;
background-color: #333;
color: #fff;
padding: .5em;
}
通用兄弟选择器
如果你想选中一个元素的兄弟元素,即使它们不直接相邻,你还是可以使用通用兄弟选择器(~)。要选中所有的<p>元素后任何地方的<img>元素。
在下面的示例中,我们选中了所有的 <h1>之后的<p>元素,虽然文档中还有个 <div>,其后的<p>还是被选中了。
<article>
<h1>A heading</h1>
<p>I am a paragraph.</p>
<div>I am a div</div>
<p>I am another paragraph.</p>
</article>
h1 ~ p {
font-weight: bold;
background-color: #333;
color: #fff;
padding: .5em;
}
总结
选择器的存在为精细化选择样式变成可能。
- 属性选择器让我们更加精确地控制哪些元素应该应用特定的样式,从而提高CSS的灵活性和复用性。
- 伪类使得你可以将处于特定状态的元素作为目标,就像你已向 DOM 添加了该状态的类一样。伪元素的作用就像是你已向 DOM 添加了全新的元素,并允许你为其设置样式。
::before和::after伪元素让你可以使用 CSS 将内容插入文档。 - 使用关系选择器,将任何在我们前面的学习过程中学到的选择器组合起来。