顾名思义。CSS中选择器的主要作用就是与HTML页面中的元素实现一对一,一对多或者多对一的控制,而在CSS3中又对选择器进行了扩展,极大的提高了查找元素的精度及准确性。 CSS选择器主要可以分为基本选择器和高级选择器:
一、基本选择器
1、通配符选择器(*)
匹配页面中所有元素,一般用来清除浏览器的默认样式。
示例:
* {
margin: 0;
padding: 0;
}
2、元素选择器
通过标签名选择样式,选择所有的同标签名元素。
示例:
div {
margin: 0;
padding: 0;
}
3、class选择器(.)
通过类名选择元素,同一个类名在页面中可以出现多次,不具备唯一性。
示例:
.yolanda {
color: black;
border: 2px dashed white;
}
4、ID选择器
通过ID选择元素,一般编码规范要求ID命名应具有唯一性。
#yolanda {
color: yellow;
border: 2px dashed blue;
}
二、高级选择器
1、后代选择器 (E F)
匹配到E元素下面的所有的F元素(包括子、孙),之间用空格隔开。
示例:
<!DOCTYPE html>
<html>
<head>
<title>文本环绕</title>
<meta charset=“UTF-8” />
<style type="text/css">
#container span {
border: 1px solid gray;
}
</style>
</head>
<body>
<div id="container">
<span>first</span>
<span>second</span>
<span>third</span>
<div>
<span>four</span>
<span>five</span>
</div>
</div>
</body>
</html>
页面效果:
2、选择器列表(E,F)
同时匹配到E元素和F元素,适用于有两个及多个使用相同CSS样式的选择器的情况。
<style type="text/css">
#box1, #box2 {
width: 100px;
height: 100px;
border: 1px solid yellow;
}
</style>
<body>
<div id="box1">first</div>
<div id="box2">second</div>
</body>
页面效果:
3、子元素选择器(E>F)
选择E元素的直接子代F元素即初代子元素,不包含孙元素。
示例:
<style type="text/css">
.container {
width: 150px;
}
.container > ul {
border: 2px solid gray;
}
</style>
<body>
<div class="container">
<div id="frameWork">
<ul>
<li>Angular</li>
<li>React</li>
<li>Vue</li>
</ul>
</div>
</div>
<div class="container">
<ul>
<li>html</li>
<li>CSS</li>
<li>javascript</li>
</ul>
</div>
</body>
页面效果:
4、相邻兄弟选择器(E+F)
在同一个父级元素下,相邻兄弟选择器可命中子元素E后面紧邻的下一个子元素F。
示例:
<style type="text/css">
.container {
width: 150px;
}
.container>ul {
border: 2px solid gray;
}
#frameWork + div {
background-color: yellow;
}
</style>
<body>
<div class="container">
<div>大家好欢迎来到选秀现场</div>
<div id="frameWork">
<ul>
<li>Angular</li>
<li>React</li>
<li>Vue</li>
</ul>
</div>
<div>一位练习一年半的练习生</div>
<div>唱、跳、rap</div>
</div>
<div class="container">
<ul>
<li>html</li>
<li>CSS</li>
<li>javascript</li>
</ul>
</div>
</body>
页面效果:
可以看出,#frameWork+div只会影响父元素<div class="container">下面的第一个子元素<div>一位练习一年半的练习生</div>,不影响上面的子元素和更下面的子元素。
那如果两个兄弟元素相同呢?
示例:
<style type="text/css">
.container {
width: 150px;
}
.container>ul {
border: 2px solid gray;
}
#frameWork >ul > li + li {
background-color: yellow;
}
</style>
<body>
<div class="container">
<div>大家好欢迎来到选秀现场</div>
<div id="frameWork">
<ul>
<li>Angular</li>
<li>React</li>
<li>Vue</li>
</ul>
</div>
<div>一位练习一年半的练习生</div>
<div>唱、跳、rap</div>
</div>
<div class="container">
<ul>
<li>html</li>
<li>CSS</li>
<li>javascript</li>
</ul>
</div>
</body>
页面效果:
此时#frameWork >ul > li + li 不仅影响了<li>React</li>还影响了
<li>Vue</li>。这是因为当两个兄弟元素相同时,会进行循环查找。 <li>Vue</li>是<li>React</li>的下一个满足条件的子元素,所以也会被命中。
5、兄弟选择器E~F(CSS3新增)
在同一个父级元素下,兄弟选择器可命中子元素E后面所有的子元素F。
示例:
<style>
div~p {
width: 100px;
height: 50px;
background: yellow;
}
</style>
// 选择到div后面的三个p元素
<div>我是div</div>
<p>react</p>
<p>vue</p>
<p>angular</p>
页面效果:
6、属性选择器
E[attr] 匹配具有attr属性的E元素:
示例:
<style>
div[title] {
width:100px;
height:100px;
margin-top:2px;
background:pink;
}
</style>
//匹配到下文中的第一个和第三个div元素 因为他们含有title属性
<div title="sing"></div>
<div></div>
<div title="dance"></div>
E[attr=val] 匹配具有attr属性且值为val的的E元素
示例:
<style>
div[title="sing"] {
width: 100px;
height:100px;
margin-top:2px;
background:pink;
}
</style>
//匹配到下文中的第一个div元素,因为他含有title属性且值为sing
<div title="sing"></div>
<div></div>
<div title="dance"></div>
E[attr~=val] 匹配属性为attr,且属性值包含独立单词“val”的E元素,用于选取属性值中包含独立的指定词汇的元素。
示例:
<style type="text/css">
div {
width: 150px;
height: 50px;
border: 1px solid gray;
}
div[title~="sing"] {
background: yellow;
}
</style>
// 第一个和第三个div会被选中,因为他们的title属性中都含有sing词汇
<body>
<div title="sing song"></div>
<div title="singsong"></div>
<div title="sing"></div>
</body>
页面效果:
E[attr|=val] 匹配属性为attr,且属性值为“val”或是以“val-”为前缀("-"为连字符,Unicode 编码为 U+002D)开头的E元素,用于选取属性值中以指定词汇-开头或为指定词汇的元素。
示例:
<style type="text/css">
div {
width: 150px;
height: 50px;
border: 1px solid gray;
}
div[title|="sing"] {
background: yellow;
}
</style>
// 第二个和第三个div会被选中,因为他们的title属性分别是以"sing-"开头或者直接为“sing”
<body>
<div title="sing song"></div>
<div title="sing-song"></div>
<div title="sing"></div>
<div title="s-sing"></div>
</body>
页面效果
E[attr^=" val"]
匹配attr属性以val开头的E元素(CSS3新增) 示例:
<style>
div[class^="box"] {
width:100px;
height: 100px;
margin-top: 2px;
background: #000;
}
</style>
//选择到了前面三个div元素
<div class="box"></div>
<div class="boxBlue"></div>
<div class="box1"></div>
<div class="anotherBox"></div>
E[attr$="val"]
匹配attr以val结尾的E元素(CSS3新增) 示例:
<style>
div[class$="Box"] {
width: 100px;
height: 100px;
margin-top: 2px;
background: #000;
}
</style>
// 选择到前三个元素
<div class="Box"></div>
<div class="redBox"></div>
<div class="yellowBox"></div>
<div class="BoxContainer"> </div>
E[attr*=val]
选择到attr包含值val的E元素(CSS3新增) 示例:
<style>
div[class$="box"] {
width: 100px;
height: 100px;
margin-top: 2px;
background: #000;
}
</style>
// 选择到前三个元素
<div class="box"></div>
<div class="redbox"></div>
<div class="-box-"></div>
<div class="BoxContainer"> </div>
E[attr1][attr2=val]
多属性选择器,匹配属性attr1和attr2同时满足要求的E元素
示例:
<style>
div[class="box"][title|="container"] {
width: 100px;
height: 100px;
margin-top: 2px;
background: #000;
}
</style>
// 选择到前两个元素
<div class="box" title="container"></div>
<div class="box" title="container-Box"<</div>
<div class="box"><div>
<div title="container"></div>
7、伪类选择器
锚伪类: 当元素处于某种状态时选择该元素并为其添加样式,这些状态包括:活动状态,已被访问状态,未被访问状态,和鼠标悬停状态。
a:link {color: #FF0000} /* 未访问的链接 */
a:visited {color: #00FF00} /* 已访问的链接 */
a:hover {color: #FF00FF} /* 鼠标移动到链接上 */
a:active {color: #0000FF} /* 选定的链接 */
a:focus{ background-color: pink;} /* 获得焦点的元素*/
注意:
- 在 CSS 定义中,a:hover 必须被置于 a:link 和 a:visited 之后,才是有效的。
- 在 CSS 定义中,a:active 必须被置于 a:hover 之后,才是有效的。
- 伪类名称对大小写不敏感。
- 问:既然a{}定义了超链接的属性,a:link{}定义了超链接点击之前的属性,那这两个有啥区别呢? 答:a{}和a:link{}的区别:a{}定义的样式针对所有的超链接(包括锚点);a:link{}定义的样式针对所有写了href属性的超链接(不包括锚点)
其他伪类:
first-child:匹配在页面中第一个出现的元素
示例:
// 匹配所有p元素中的第一个i元素
<html>
<head>
<style type="text/css">
p>i:first-child {
font-weight: blod;
}
</style>
</head>
<body>
<p>some <i>text</i> some <i>text</i>.</p>
<p>some <i>text</i> some <i>text</i>.</p>
</body>
</html>
lang伪类: 匹配带有指定 lang 属性的元素
lang 伪类使你有能力为不同的语言定义特殊的规则。
应用于元素带有指定lang的情况。
示例:
<html>
<head>
<style type="text/css">
q:lang(no) {
quotes: "~" "~"
}
</style>
</head>
<body>
<p>文字<q lang="no">段落中的引用文字</q>文字</p>
</body>
</html>
页面效果:
first-of-type(CSS3新增)
p:first-of-type:选择的每个 p 元素是其父元素的第一个 p 元素 示例:
<style>
p:first-of-type{
width:100px;
height:100px;
background: #000;
}
</style>
//父级下面所有p元素的第一个
<div>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
</div>
last-of-type
p:last-of-type 父级下面所有p元素的最后一个
only-of-type
p:only-of-type 父级下面只有一个p元素,其他的元素不能是p,如果有其他元素那么会选不中。
nth-of-type
p:nth-child(n) 选中父级元素中第n个p
nth-last-of-type(n)
p:nth-last-of-type(n) 选择p,父级元素中倒数第n个p元素
8、伪元素选择器
给某些修饰类的元素添加样式,这些元素对于用户来说是可见的,但是对于DOM来说不可见,因此说他是伪元素。
- first-letter: 为文本第一个字母添加样式
- first-line: 为文本第一行添加样式
- before: 向文本之前添加元素(IE7以下不支持)
- after: 向文本之后添加元素(IE7以下不支持)
示例:
<body>
<p>对于你,我只能是一颗 无言的星 在深邃的天庭 静静地闪烁 闪烁,却不是为了诱惑 只为了让那皎洁的光 照亮你也照亮我 照亮一道纯净的小溪 照亮一条清澈的小河</p>
</body>
<style>
p: first-letter {
font-size: 50px;
}
p: first-line {
background-color: #dafbef;
}
/style>
页面效果:
补充:
(1)除了上面列举的常用的,伪元素选择器比较常用的还有 selection:[CSS4]应用于文档中被用户高亮的部分(比如使用鼠标或其他选择设备选中的部分)。(IE8及以下不支持)(火狐-moz-selection),但需要注意只有一小部分CSS属性可以用于::selection 选择器: color, background-color, cursor, outline, text-decoration, text-emphasis-color和text-shadow。
要特别注意的是,background-image 会如同其他属性一样被忽略。
注意:::selection中的text-shadow属性仅有Chrome, Safari 和 Firefox 17+支持。::selection CSS伪元素选择器是CSS第3级选择器的草案,但是在被推荐使用前就被废弃。它现在在第4级伪元素选择器草案中。 示例:
<style>
::-moz-selection {
color: gold;
background: red;
}
::selection {
color: gold;
background: red;
}
p::selection: {
color: white;
background: black;
}
p::-moz-selection: {
color: white;
background: black;
}
</style>
<body>
<div>我们无法与生活讨价还价,所以只能拼命努力</div>
<p>对于你,我只能是一颗 无言的星 在深邃的天庭 静静地闪烁 闪烁,却不是为了诱惑 只为了让那皎洁的光 照亮你也照亮我 照亮一道纯净的小溪 照亮一条清澈的小河</p>
</body>
页面效果:
其他的伪元素选择器更为不常用且兼容性很差,此处不再做介绍。
(2)与伪类一样, 伪元素添加到选择器,但不是描述特殊状态,它们主要作用是为元素的某些部分设置样式。
(3)有时你会发现伪元素使用了两个冒号 :: 而不是一个冒号 :,这是CSS3的一部分,并尝试区分伪类和伪元素。伪类像类选择器一样给已存在的、处于指定状态的元素添加额外的样式;伪元素则是给某些并不真实存在的、虚拟存在的元素添加样式。 大多数浏览器都支持这两个值。若页面只需要兼容 webkit、firefox、opera 等浏览器,建议对于伪元素采用双冒号的写法,如果不得不兼容 IE 浏览器,还是用 CSS2 的单冒号写法比较安全。
(4)伪元素选择器不会匹配任何真实存在的html元素,因此也没法通过DOM操作直接操作伪元素。
(5)before和after: ::before 创建一个伪元素,其将成为匹配选中的元素的第一个子元素。常通过 content 属性来为一个元素添加修饰性的内容。此元素默认为行内元素。 ::after类似,因此如果要给插入的内容添加宽高属性必须通过display转换。
注意: 由::before 和::after 生成的伪元素 包含在元素格式框内, 因此能应用在可替换元素上, 比如<img>或<br> 元素。使用::before 和::after生成的伪元素的content不能够被选择。
上述内容可以解释我在[《浮动与清除浮动》] 中提到的利用before和after伪元素清除浮动。
(6)为什么input元素不支持before,after伪元素插入内容? 答::before和:after伪元素指定生成的内容的样式和位置。如其名所示,:before和:after伪元素指定了一个元素文档树内容之前和之后的内容。'content'属性,与这些伪元素联用,指定了插入的内容。作为DOM元素,伪元素都是在容器内进行渲染的。input无法容纳其他元素,因此它不支持伪元素。按钮也是在其他元素的支持下才由浏览器呈现出来的。同理,img,iframe等元素都不能包含其他元素,所以不能通过伪元素插入内容。
三、选择器的权重
在说明CSS选择器的权重之前我们先一起看一下浏览器如何实现页面的解析渲染,我们以Webkit内核为例:
上图为Webkit内核渲染DOM的主要流程,我们可以看到其中HTML文档解析和CSS规则解析是同时进行的,浏览器有专门的html解析器来解析HTML,并在解析的过程中构建DOM树,本文中不再对构建DOM树的过程进行深入探讨及研究,HTML解析完毕后,开始创建呈现树(又称渲染树)RenderTree,这一步的主要工作在于将CSS样式应用到DOM节点上,通过分析CSS文档,会生成如下图所示的CSS规则树状图,CSSRule会保持每个不同元素和对应样式的映射关系。在渲染树逐行生成的阶段,DOM树中的节点会在CSS分析树中根据元素、类、id选择器来提取与之对应元素的一条或多条CSSRule,进行CSS规则的层叠和权重计算,得到最终生效的样式CSSRule并添加到DOM渲染树上,当每个DOM节点提取CSS样式完成时,用于页面布局和绘制的DOM渲染树便形成了。在一个已经形成的DOM渲染树中,节点的CSS规则可通过document.defaultView.getComputedStyle (element, null)方法来获取查看,下图是CSS解析结构示意图:
Webkit内核把进行CSS规则的层叠和权重计算,得到最终生效的样式CSSRule并添加到DOM渲染树上这一过程称为附着,这一过程会涉及到CSS选择器的权重问题。
首先将根据样式的重要性排序,由低到高依次为:
- 浏览器声明;
- 用户普通声明;
- 作者普通声明;
- 作者重要声明;
- 用户重要声明;
对于同一重要级别,则是根据CSS选择符的特指度来判定优先级。 一条样式声明的特指度由以下四部分决定: S-I-C-E。特指度越高,选择器优先级越高。
- 声明来自内联的style属性则 S+1;
- 声明中含有Id属性则 I+1;
- 声明中含有类、伪类、属性选择器则 C+1;
- 声明中含有元素选择器、伪元素选择器则 E+1;
特指度比较规则如下:
- 先从高等级进行比较,高等级相同时,再比较低等级的,以此类推;
- 完全相同的话,就采用 后者优先 原则;
示例:
// 假设下面样式都作用于同一个节点元素`span`,判断下面哪个样式会生效
body#god div.dad span.son {width: 200px;}
body#god span#test {width: 250px;}
两种方式的S都为0,第一种的I为1,第二种为2,因此最终span元素的宽度为150px,即第二个样式会生效。
根据特指度越高,选择器优先级越高的原则,选择器有一个特定的排序,我们可以理解为选择器的指向越具体,其优先级越高。
行内样式
交叉选择器
id选择器(#myid)
类选择器(.myclassname)
标签选择器(div,h1,p)
相邻选择器(h1+p)
子选择器(ul > li)
后代选择器(li a)
通配符选择器(*)
属性选择器(a[rel="external"])
伪类选择器(a:hover,li:nth-child)
注意:在css中,!important的权重相当的高。如果出现了!important,则不管权重如何都取有!important的属性值。但是宽高有例外情况,由于宽高会被max-width/min-width覆盖,所以!important会失效。
示例:
span {
width: 100px!important;
min-width: 200px;
}
上面代码浏览器解析后最终赋给元素的宽度为200px。