第二章:选择器
2.1 样式的基本规则
元素选择器
元素选择器通常是HTML元素。(但也有例外,比如在XML中可能有quote选择器)。
声明和关键字
声明块中有一个或多个声明。
声明的格式是固定的:属性 + 冒号 + 值+ 分号。例如:
p {font: medium Helvetica;}
2.2 群组
把同一个样式应用到多个元素上。
群组选择器
选择器之间以,(逗号)分隔。
h2, p{color: red;}
通配选择器
*匹配所有元素。
在配合其他简单选择器的时候,省略掉通配选择器会有同样的效果.比如,*.warning 和.warning 的效果完全相同.
/*
文档中所有元素都显示为红色。
*/
*{color: red;}
群组声明
一个群组可以有多个选择器,也可以有多个声明。
h1{font: 18px Helvetica;}
h1{color: red;}
/*
上面的声明和下面的声明效果一样。
*/
h1{
font: 18px Helvetica;
color: red;
}
在旧浏览器中使用新的元素
有些旧浏览器不支持新加入的元素,解决方法是在DOM中创建元素。
// 例如在IE8中识别main元素
document.createElement("main")
//运行这段代码后,IE8将可以识别main元素
2.3 类选择器和ID选择器
类选择器和ID选择器以一种独立于元素的方式赋予样式。
类选择器
应用样式而不关心所涉及的元素,最常使用类选择器。
为了把类选择器定义的样式应用在元素上,必须为class属性赋予适当的值。
<p class='warning'>
这是一段警告文本
</p>
然后就可以使用.(点号)为设定好的class设置样式。
.warning{
font-weight: bold;
color: red;
}
效果:

类选择器可以和其他选择器一起使用,比如对于:
<p class='warning'>
这是一段警告文本
</p>
<p>
这一段无法被匹配
</p>
可以设置:
p.warning{
font-weight: bold;
color:red;
}
效果:

多个类
如果HTML中一个元素有多个类,可以把类选择器串联在一起。
<p class='warning urgent'>
这是一段警告文本
</p>
<p class='warning'>
这一段class为warning无法被匹配
</p>
可以设置:
/*
串联顺序不影响效果,
所以下面的声明也可以设置为p.urgent.warning
*/
p.warning.urgent{
font-weight: bold;
color:red;
}
效果:

ID选择器
ID选择器以#(井号)开头,引用id属性的值。
#{
font-weight: bold;
}
在类选择器和ID选择器之间选择
一个文档中,类选择器可以使用任意多次,ID选择器只能使用一次。ID选择器不能串联使用,并且ID选择器权重更高。
2.4 属性选择器
不管是类选择器还是ID选择器,选择的都是属性的值。
属性选择器分为4类:简单属性选择器、精准属性值选择器、部分匹配属性值选择器和起始值属性选择器。
简单属性选择器
如果想要选取具有某个属性的元素,而不管这个属性的值是什么,可以使用简单属性选择器。
h1[class] {color: red;}
简单属性选择器可以选择多个属性:
/*
对于以下css设置
*/
p[class][id] {color: red;}
当HTML文档为:
<p id='warning' class="urgent">
这一段文本可以被匹配
</p>
<p class='warning'>
这一段只有class属性无法被匹配
</p>
效果:

精准属性值选择器
在简单属性选择器的基础上,可以精准选择属性为特定值的元素。
p[class][id='first'] {color: red;}
对于文档:
<p id='first' class="urgent">
这一段文本可以被匹配
</p>
<p id='warning' class="urgent">
这一段id属性值不匹配,无法被匹配
</p>
效果:

部分匹配属性值选择器
根据属性值的一部分选择元素,而不是完整的值。
| 形式 | 说明 |
|---|---|
| [foo |= “bar”] | 选择的元素有foo属性,并且它的值为bar或者以bar和一个英文破折号开头。 |
| [foo ~= “bar”] | 选择的元素有foo属性,并且它的值是包含bar(用空格隔开)的一组词。 |
| [foo *= “bar”] | 选择的元素有foo属性,并且它的值包含子串bar。 |
| [foo ^= “bar”] | 选择的元素有foo属性,并且它的值以bar开头 |
| [foo $= “bar”] | 选择的元素有foo属性,并且它的值以bar结尾。 |
对于|=:匹配属性值或属性值加-开头的子串
*[lang |= "en"] { color: red;}
对于文档
<h1 lang="en">H1标题</h1>
<p lang="en-us">一段文本</p>
<div lang="fr">一个div</div>
结果为:

对于~=:匹配以空格分隔的一组词中的一个
span[class ~= "warning"] { color: red;}
对于文档
<span class="warning">第一个span</span>
<span class="blue warning">第二个span</span>
<span class="blue-warning">第三个span</span>
结果为:

对于*=:匹配属性值的子串
span[class *= "warning"] { color: red;}
对于文档
<span class="warning">第一个span</span>
<span class="blue warning">第二个span</span>
<span class="blue-warning">第三个span</span>
结果为:

对于^=:匹配属性值开头的子串
a[href ^= "https:"] { color: red;}
对于文档
<a href = "https://www.baidu.com">https百度</a>
<a href = "http://www.baidu.com">http百度</a>
<a href = "www.baidu.com">百度</a>
结果为:

对于$=:匹配属性值结尾的子串
a[href $= ".pdf"] { color: red;}
对于文档
<a href = "a.pdf">PDF</a>
<a href = "b">any</a>
<a href = "c.txt">TXT</a>
结果为:

不区分大小写的标识符
在结束方括号前加上i,属性选择器不管文档语言的要求,匹配属性值时不区分大小写。
a[href $= ".pdf" i] { color: red;}
a[href $= ".txt"] { color: red;}
对于以下文档:
<a href = "a.PDF">大写PDF</a>
<a href = "b.pdf">小写pdf</a>
<a href = "c.Pdf">混合大小写pdf</a>
<a href = "a.TXT">大写TXT</a>
<a href = "b.txt">小写txt</a>
<a href = "c.Txt">混合大小写Txt</a>
结果为:

2.5 根据文档结构选择
父子关系
dom树状图:

如上图,以body的第一个p元素为例:
p元素是em和strong的父元素,em和strong是p元素的子元素。
p元素是html的后代元素。
p元素是p元素的strong元素的a元素的祖先元素。
后代选择器
后代选择器(descendant selector),又称为上下文选择器(contextual selector)。
' ' (空格) 操作符将选择第一个元素的子代节点。
对于:
<p>
这是一个
<em>段落</em>
</p>
设置:
p em {color: red;}
效果:

后代选择器的两个元素之间的层级是可以无限的。
对于:
<ul>
<li>第一个li元素</li>
<ol>
<li>ol里面的li元素</li>
</ol>
</ul>
设置:
ul li {color: red;}
结果为:

子代选择器
'>' 操作符选择第一个元素的直接子节点。选择器两边的空格是可选的。
对于:
<ul>
<li>第一个li元素</li>
<ol>
<li>ol里面的li元素</li>
</ol>
</ul>
设置:
ul > li {color: red;}
结果为:

后代选择器和子代选择器可以同时使用,比如
table.warning td > p
相邻兄弟选择器
'+' 操作符选择相邻元素,即第二个节点紧邻着第一个节点,并且拥有共同的父节点。选择器两边的空格是可选的。
对于:
<ul>
<li>One</li>
<li>Two!</li>
<li>Three</li>
</ul>
设置:
li + li {
color: red;
}
结果为:

两个元素之间的文本不影响相邻兄弟选择器的作用。因为这些文本属于父元素,但是如果把文本放在p元素里面,就会影响到相邻兄弟选择器。
比如:
<ul>
<li>One</li>
一些文字
<li>Two!</li>
<p>第二段文字</p>
<li>Three</li>
</ul>
结果为:

兄弟选择器
'~' 操作符选择兄弟元素,也就是说,第二个节点在第一个节点后面的任意位置,并且这俩节点的父节点相同。
对于:
<h2>h2标题</h2>
<p>第一段文字</p>
<h3>h3标题</h3>
<p>第二段文字</p>
<p>第三段文字</p>
设置:
h2 ~ p {
color: red;
}
结果为:

2.6 伪类选择器
伪类选择器指定要选择的元素的特殊状态,可以为文档中不一定真正存在的结构指定样式。
伪类始终指代所依附的元素。
拼接伪类
css允许把伪类串联(拼接)在一起,伪类串联的顺序没有什么关系。
a:link:hover{color: red;}
/*
等价于
*/
a:hover:link{color: red;}
但是互斥的伪类不能串联,比如link和visited。
结构伪类
伪类大部分是结构上的,即它们指代文档中的标记结构。
选择根元素
:root伪类选择根元素,在HTML中,根元素始终是html,这个选择符真正的用途是在XML语言的样式表中。
选择空元素
:empty伪类可以选择没有任何子代的元素,甚至连文本和空白都没有。
:empty伪类可以匹配html的空元素,比如img和input,但是它还可以匹配没有内容的textarea元素。
截止2017年末,empty是唯一一个在匹配时考虑文本节点的css选择器,其他选择器只会考虑元素。
选择唯一子代
only-child伪类
:only-child伪类匹配的元素是另一个元素唯一的子代。
对于:
<ul>
<li>第一个li元素</li>
<li>第二个li元素</li>
<ol>
<li>第三个li元素</li>
</ol>
</ul>
设置:
li:only-child {
color: red;
}
效果为:

only-of-type伪类
:only-of-type伪类匹配的元素没有其他相同类型的兄弟元素(唯一的那一种元素)。
对于:
<main>
<div>I am `div` #1.</div>
<p>I am the only `p` among my siblings.</p>
<div>I am `div` #2.</div>
<div>I am `div` #3.
<i>I am the only `i` child.</i>
<em>I am `em` #1.</em>
<em>I am `em` #2.</em>
</div>
</main>
设置:
/*
这里使用了后代选择器,所以选取的是main元素的后代里面的相对于父元素唯一的那一种元素。
*/
main :only-of-type {
color: red;
}
效果为:

选择第一个和最后一个子代
:first-child选择一个元素的第一个元素。
:last-child选择一个元素的最后一个元素。
对于:
<div>
<p>第一个p元素</p>
<p>第二个p元素</p>
<p>最后一个p元素</p>
</div>
设置:
p:first-child {
color: red;
}
p:last-child {
color: blue;
}
效果为:

选择第一个和最后一个某种元素
:first-of-type选择一组兄弟元素中某类型的第一个元素。
:last-of-type选择一组兄弟元素中某类型的最后一个元素。
对于:
<article>
<div>这是第一个 `div` </div>
<div>这个 <span> `span` 是第一个也是最后一个</span>!</div>
<div>这个 <em> `em` 是第一个</em>, 这个 <em> `em` 是最后一个</em> !</div>
<div>这个 <span> `span` 是第一个也是最后一个</span>!</div>
<b>这个 `b` 是第一个也是最后一个</b>
<div>这个 `div` 是最后一个</div>
</article>
设置:
article :first-of-type {
background-color: pink;
}
article :last-of-type {
color: red;
}
效果为:

选择每第N个子元素
:nth-child(an+b)首先找到所有当前元素的兄弟元素,然后按照位置先后顺序从1开始排序,选择的结果为第(an+b)个元素的集合(n=0,1,2,3..…)。示例:
0n+3或简单的3匹配第三个元素。1n+0或简单的n匹配每个元素。2n+0或简单的2n匹配位置为 2、4、6、8..…的元素(n=0时,2n+0=0,第0个元素不存在,因为是从1开始排序)。你可以使用关键字 even 来替换此表达式。2n+1匹配位置为 1、3、5、7..…的元素。你可以使用关键字 odd 来替换此表达式。3n+4匹配位置为 4、7、10、13..…的元素。
a 和 b 都必须为整数,并且元素的第一个子元素的下标为 1。
:nth-last-child(an+b)的作用与:nth-child(an+b)一样,不过它是从最后一个开始计算。
对于:
<ul>
<li>第1个li元素</li>
<li>第2个li元素</li>
<li>第3个li元素</li>
<li>第4个li元素</li>
<li>第5个li元素</li>
<li>第6个li元素</li>
<li>第7个li元素</li>
</ul>
设置:
li:nth-child(1) {
background: pink;
}
li:nth-child(2n + 2) {
background: #5bc49f;
}
li:nth-last-child(3n + 1) {
color: red;
}
效果为:

选择每第N个某种元素
:nth-of-type(an+b)和:nth-last-of-type(an+b)选择每第N个某种元素。
对于:
<div>
<span>这是 span.</span>
<span>这是另一个 span.</span>
<em>这个是 em.</em>
<span>这是第三个span</span>
<p>这个是p.</p>
<span>这是最后一个span.</span>
</div>
设置:
span:nth-last-of-type(1) {
background-color: lime;
}
span:nth-of-type(2) {
background-color: #5bc49f;
}
p:nth-last-of-type(1) {
color: white;
}
p:nth-of-type(1) {
background-color: #5bc49f;
}
效果为:

动态伪类
动态伪类在页面渲染结束后根据页面变化而变化。
超链接伪类
| 伪类 | 说明 |
|---|---|
| :link | 指代用作超链接的锚记(即具有href属性),而且指向未访问过的地址。 |
| :visited | 指代指向已访问地址的超链接。出于安全考虑,可用的样式十分有限。 |
出于隐私考虑,:visited伪类只能设置颜色相关的属性,并且通过DOM查询已访问链接的样式,返回的值和未访问时一样。
用户操作伪类
| 伪类 | 说明 |
|---|---|
| :focus | 指代当前获得输入焦点的元素,即可以接受键盘输入或以某种方式激活。 |
| :hover | 指代鼠标指针放置在上面的元素,例如鼠标指针悬停在超链接上。 |
| :active | 指代由用户输入激活的元素,例如用户点击超链接时按下鼠标的那段时间。 |
可以处于:active状态的元素有链接,菜单项目,以及可以设定tabindex属性的元素。这些元素,加上其他所有的交互元素,还可以获得焦点。
这些伪类通常用于超链接,推荐使用顺序为:link - visited - hover - active
动态样式引起的问题
动态伪类有些耐人寻味的问题和怪异行为。比如:把已访问的链接和未访问的链接设置成相同的字号,同时在悬停时把字号放大,这可能会导致这个链接后面的内容重排(重新绘制文档)。
UI状态伪类
| 伪类 | 说明 |
|---|---|
| :enabled | 指代启用的用户界面元素(比如表单元素),即接受输入的元素。 |
| :disabled | 指代禁用的用户界面元素(比如表单元素),即接受输入的元素。 |
| :checked | 指代由用户或文档默认选中的单选按钮或复选框。 |
| :indeterminate | 指代既没有选中也没有未选中的单选按钮或复选框,这个状态只能由DOM脚本设定。 |
| :default | 指代默认选中的单选按钮、复选框或选项。 |
| :valid | 指代满足所有数据有效性语义的输入框。 |
| :invalid | 指代不满足所有数据有效性语义的输入框。 |
| :in-range | 指代输入的值在最大值和最小值之间的输入框。 |
| :out-of-range | 指代输入的值不在最大值和最小值之间的输入框。 |
| :required | 指代必须输入值的输入框。 |
| :optional | 指代不需要一定输入值的输入框。 |
| :read-write | 指代可由用户编辑的输入框。 |
| :read-only | 指代不能由用户编辑的输入框。 |
虽然UI元素的状态可由用户操作而改变,但是UI状态伪类不是单纯动态的,因为它们还受文档结构或DOM脚本的影响。
target伪类
:target伪类代表一个唯一的页面元素(目标元素),其id 与当前URL片段匹配 .
对于:
<section id="section2">Example</section>
设置:
:target {
border: 2px solid black;
}
当访问页面的#section2时,效果为:

:target伪类在以下两种情况下不会被使用:
- 页面的URL中没有片段标识符
- 页面的URL中有片段标识符,但是文档中没有与之匹配的元素
:lang 伪类
如果想根据文本使用的语言选择元素,可以使用:lang伪类,在匹配方式上,:lang伪类和|=属性选择器类似。
伪类选择器和属性选择器之间的主要区别是语言信息有多个来源,有可能来自元素自身以外。对于属性选择器来说,元素自身必须有lang属性菜能匹配,而:lang伪类能匹配设定了语言的元素的后代。
在HTML中, 语言是通过
lang属性,和meta元素的组合来决定的, 也可能是通过协议的信息来确定(例如HTTP头). 对于其他文档类型,也可能存在其他用于确定语言的方法。
否定伪类
:not()伪类依附在元素上,括号内是简单的选择器。
根据W3C的定义,简单选择器指:一个类型选择器,通用选择器,属性选择器,类选择器,ID选择器或伪类。(基本上就是没有祖辈 - 后代关系的选择器)。
:not()伪类中只能使用一个选择器,所以不能使用群则选择器,不能使用后代选择器等等。
:not()可以在选择器的任何位置使用。
:not()伪类不能嵌套。
:not()伪类可以串联使用,相当于“也不是”。
对于:
<p class='first' id='txt'>这是一段文本</p>
<p class='second' id='TXT'>这是第二段文本</p>
<p class='three' id='txt-other'>这是第三段文本</p>
设置:
p:not(#txt):not(.three) {
color: red;
}
效果为:

2.7伪元素选择器
伪元素和伪类很像,为了实现特定的效果,它在文档中插入虚拟的元素。
CSS2定义了4个伪元素,CSS2之后又定义了其他伪元素。这里只介绍CSS2定义的4个。
伪类使用一个冒号,伪元素使用两个冒号(为了向后兼容,伪元素也可以使用一个冒号,但是不建议)。
所有的伪元素只能出现在选择器的最后面(所有只能使用一个伪元素)。
装饰首字母伪元素
::first-letter伪元素用于装饰任何非行内元素的首字母,或者开头的标点符号和首字母。
::first-letter伪元素最常用来实现排版效果中的首字母下沉或者首字母大写。
对于:
<p>这是一段文本</p>
<p>这是第二段文本</p>
设置:
p:first-of-type::first-letter {
color: red;
font-size: 200%;
}
效果为:

这个规则相当于构建了一个虚拟的元素来包裹首行的第一个文本。比如:
<p>
<p-first-letter>这</p-first-letter>
是一段文本
</p>
<p>这是第二段文本</p>
p-first-letter元素既不出现在文档的源码中,也不出现在DOM树中,而是由用户代理动态构建,也就是说,p-first-letter是一个伪元素。
装饰首行
::first-line用于装饰元素的首行文本。
对于::first-letter和::first-line的限制
目前,::first-letter和::first-line伪元素只能应用到块级元素上,例如标题和段落,不能应用到行内元素上,比如超链接。
另外,对于它们可使用的CSS属性也有限制。
允许伪元素使用的属性:
| ::first-letter | ::first-line |
|---|---|
| 所有的字体属性 | 所有的字体属性 |
| 所有的背景属性 | 所有的背景属性 |
| 所有文本装饰属性 | 所有文本装饰属性 |
| 所有行内排版属性 | 所有行内排版属性 |
| 所有行内布局属性 | 所有外边距属性 |
| 所有边框属性 | 所有内边距属性 |
| box-shadow | 所有边框属性 |
| color | color |
| opacity | opacity |
装饰(或创建)前置和后置内容元素
::before和::after创建一个伪元素,其将成为匹配选中的元素的第一个子元素。常通过 content属性来为一个元素添加修饰性的内容。此元素默认为行内元素。
由::before 和::after 生成的伪元素 包含在元素格式框内, 因此不能应用在替换元素上, 比如img或br 元素。
生成内容是一个单独的话题,会在15章进行更深入的介绍。