CSS权威指南(第四版)笔记(第二章:选择器)

1,375 阅读17分钟

第二章:选择器

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树状图:

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;
}

效果为:

only-of-type伪类

选择第一个和最后一个子代

: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..…的元素。

ab 都必须为整数,并且元素的第一个子元素的下标为 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个子元素

选择每第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;
}

效果为:

选择每第N个某种元素

动态伪类

动态伪类在页面渲染结束后根据页面变化而变化。

超链接伪类

伪类 说明
: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伪类

:target伪类在以下两种情况下不会被使用:

  1. 页面的URL中没有片段标识符
  2. 页面的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;
}

效果为:

not伪类

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%;
}

效果为:

::first-letter伪元素

这个规则相当于构建了一个虚拟的元素来包裹首行的第一个文本。比如:

<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 生成的伪元素 包含在元素格式框内, 因此不能应用在替换元素上, 比如imgbr 元素。

生成内容是一个单独的话题,会在15章进行更深入的介绍。