自是寻春去校迟,不须惆怅怨芳时。
狂风落尽深红色,绿叶成阴子满枝。
CSS 选择器用于选择需要添加样式的元素,其重要性不言而喻。最近更新博客模板就在不断调整 CSS 样式,好多时候就因为选择器不熟悉而不能让样式生效,费时不少。所以干脆好好学习,总结一下常用的 CSS 选择器,也为下一步学习 jQuery 做好准备。
先来看看 w3schools 给的这个 CSS 选择器列表,逐个浏览一下,有个全局再各个击破。
选择器 | 示例 | 示例解释 |
---|---|---|
.class | .clearfix | 选择 class="clearfix" 的所有元素 |
#id | #toc | 选择 id="toc" 的元素 |
* | * | 选择所有元素 |
element | p | 选择所有 <p> 元素 |
element, element | p, em | 选择所有 <p> 和 <em> 元素 |
element element | p span | 选择 <p> 元素 (块) 内部所有 <span> 元素 |
element>element | div>p | 选择父元素为 <div> 的所有 <p> 元素 |
element+element | div+p | 选择紧接在 <div> 之后的 <p> 元素 |
[attribute] | [target] | 选择带有 target 属性的所有元素 |
[attribute=value] | [target=_blank] | 选择所有 target=_blank 的元素 |
[attribute~=value] | [title~=hello] | 选择 title 包含 hello 单词的所有元素 |
[attribute|=value] | [lang|=zh-Hans] | 选择 lang 属性以 zh-Hans 开头的所有元素 |
:link | a:link | 选择所有未被访问过的链接 |
:visited | a:visited | 选择所有已被访问过的链接 |
:active | a:active | 选择当前活动链接 |
:hover | a:hover | 选择鼠标指针位于其上的链接 |
:focus | input:focus | 选择获得焦点的 input 元素 |
:first-letter | p:first-letter | 选择所有 <p> 元素的首字母 |
:first-line | p:first-line | 选择每个 <p> 元素的首行 |
:first-child | p:first-child | 选择属于父元素的第一个子元素的每个 <p> 元素 |
:before | p:before | 在每个 <p> 元素的内容之前插入内容 |
:after | p:after | 在每个 <p> 元素的内容之后插入内容 |
:lang(language) | p:lang(it) | 选择带有以 it 开头的 lang 属性值的每个 <p> 元素 |
element1~element2 | p~ul | 选择前面有 <p> 元素的每个 <ul> 元素 |
[attribute^=value] | a[src^=”https”] | 选择其 src 属性值以 “https” 开头的每个 <a> 元素 |
[attribute$=value] | a[src$=”.pdf”] | 选择其 src 属性以 “.pdf” 结尾的所有 <a> 元素 |
[attribute*=value] | a[src*=”abc”] | 选择其 src 属性中包含 “abc” 子串的每个 <a> 元素 |
:first-of-type | p:first-of-type | 选择属于其父元素的首个 <p> 元素的每个 <p> 元素 |
:last-of-type | p:last-of-type | 选择属于其父元素的最后 <p> 元素的每个 <p> 元素 |
:only-of-type | p:only-of-type | 选择属于其父元素唯一的 <p> 元素的每个 <p> 元素 |
:only-child | p:only-child | 选择属于其父元素的唯一子元素的每个 <p> 元素 |
:nth-child(n) | p:nth-child(2) | 选择属于其父元素的第二个子元素的每个 <p> 元素 |
:nth-last-child(n) | p:nth-last-child(2) | 同上,从最后一个子元素开始计数 |
:nth-of-type(n) | p:nth-of-type(2) | 选择属于其父元素第二个 <p> 元素的每个 <p> 元素 |
:nth-last-of-type(n) | p:nth-last-of-type(2) | 同上,但是从最后一个子元素开始计数 |
:last-child | p:last-child | 选择属于其父元素最后一个子元素每个 <p> 元素 |
:root | :root | 选择文档的根元素 |
:empty | p:empty | 选择没有子元素的每个 <p> 元素(包括文本节点) |
:target | #news:target | 选择当前活动的 #news 元素 |
:enabled | input:enabled | 选择每个启用的 <input> 元素 |
:disabled | input:disabled | 选择每个禁用的 <input> 元素 |
:checked | input:checked | 选择每个被选中的 <input> 元素 |
:not(selector) | :not(p) | 选择非 <p> 元素的每个元素 |
::selection | ::selection | 选择被用户选取的元素部分 |
当把这个表格一点点复制过来的时候,我已经学到了不少新东西,好些个之前没用过的选择器也大概了解了。不过,也有几个比较模糊,比如 :first-child
和 :first-of-type
就傻傻分不清楚。
不过不要紧,待我慢慢啃下 Selector Level 3。
CSS 选择器的语法并不复杂,但清楚最基础的东西总是不会错的。首先,需要注意大小写的问题,虽然 HTML 元素大小写无所谓,但 CSS 选择器都必须是小写的,所以 HTML 中也推荐统一使用小写元素。
此外,不管多复杂的选择器,都是由一个或多个简单选择器通过连接符组合而成,而简单选择器有以下几种类别:
连接多个简单选择器的连接符也有多种类别:
>
+
~
其中,空白(whitespace)可以是:空格(space, U+0020
)、制表符(tab, U+0009
)、换行符(line feed, U+000A
)、回车符(carriage return, U+000D
)以及换页符(form feed, U+000C
)。而全角空格(em-space, U+2003
)和表意空格(ideographic space, U+3000
)则不能用在 CSS 选择器的连接符中。
当多个选择器采用同一种(或一系列)CSS 设置时,可以用逗号(comma, U+002C
)将各选择器组合到一起进行统一设置,例如:
h1 { font-family: sans-serif }
h2 { font-family: sans-serif }
h3 { font-family: sans-serif }
等同于:
h1, h2, h3 { font-family: sans-serif }
CSS 类型选择器(也称为元素选择器)通过 node 节点名称匹配元素。因此,在单独使用时或寻找特定类型的元素时,元素选择器都会匹配该文档中所有此类型的元素。例如下面的选择器会选择文档中所有的 h1
元素:
h1 {}
与命名空间结合使用时,通过竖线(vertical bar, U+007C
)分隔开:
ns|h1
- 会匹配 ns 命名空间下的所有 h1 元素*|h1
- 会匹配所有命名空间下的 h1 元素,包括没有命名空间的|h1
- 会匹配没有命名空间的 h1 元素h1
- 如果定义了默认命名空间 ns,则相当于 ns|h1
,如果没有定义默认命名空间,则相当于 *|h1
在 CSS 中,一个星号(asterisk, *
, U+002A
)就是一个通配选择器。它可以匹配任意类型的 HTML 元素。在配合其他简单选择器的时候,省略掉通配选择器会有同样的效果。比如:*.warning
和 .warning
的效果完全相同。
示例:
*[lang^=en] { color: green }
*.warning { color: red }
*#maincontent { border: 1px solid blue }
在 CSS3 中,星号可以和命名空间组合使用:
ns|*
- 会匹配 ns 命名空间下的所有元素*|*
- 会匹配所有命名空间下的所有元素|*
- 会匹配所有没有命名空间的元素CSS2 引入了 4 种属性选择器:
[attr]
- 表示带有以 attr 命名的属性的元素
[attr=value]
- 表示带有以 attr 命名的,且值为 “value” 的属性的元素
[attr~=value]
- 表示带有以 attr 命名的属性的元素,并且该属性是一个以空白符(whitespace)作为分隔的值列表,其中至少一个值为 “value”
[attr|=value]
- 表示带有以 attr 命名的属性的元素,并且该属性是一个以空白符作为分隔的值列表,其中至少一个值为 “value” 或者至少一个值以 “value-“(”-“ 为连字符,Unicode 编码为 U+002D
)开头。典型的应用场景是用来来匹配语言简写代码(如 zh-Hans, zh-Hant 可以用 zh 作为 value,见下例)。
示例:
/* 所有具有 "lang" 属性的 span 元素的字体加粗 */
span[lang] {font-weight: bold;}
/* 所有具有 "lang" 属性,且值为 "pt" 的 span 元素的字体为绿色 */
span[lang="pt"] {color: green;}
/* 所有具有 "lang" 属性,且值为 "en-us" 的 span 元素的字体为蓝色*/
span[lang~="en-us"] {color: blue;}
/* 任意具有 "lang" 属性,且值带有 "zh" 字符串的 span 元素的字体为红色, 它会匹配简体中文(zh-Hans)以及繁体中文(zh-Hant) */
span[lang|="zh"] {color: red;}
另外,还有 3 个属性选择器用以匹配子字符串:
[attr^=value]
- 表示带有以 attr 命名的,且值是以 “value” 开头的属性的元素
[attr$=value]
- 表示带有以 attr 命名的,且值是以 “value” 结尾的属性的元素
[attr*=value]
- 表示带有以 attr 命名的,且值包含有 “value” 的属性的元素
示例:
/* 所有内部链接背景都为金色 */
a[href^="#"] {background-color: gold}
/* 所有以 ".cn" 结尾的链接字体都为红色 */
a[href$=".cn"] {color: red;}
/* 所有带有 "example" 的链接背景都为灰色 */
a[href*="example"] {background-color: #CCCCCC;}
在带有属性值的属性选择器表达式后添加用空格间隔开的字母 i(或 I)可以忽略属性值的大小写(ASCII 字符范围内的字母),例如:
/*所有 email 输入框的边框都为蓝色*/
/*这里匹配的输入框类型 "emeil" 可以忽略其大小写,比如 "email","EMAIL","eMaiL" 等等都能匹配*/
input[type="email" i] {border-color: blue;}
在一个 HTML 文档中,CSS 类选择器会根据元素的类属性中的内容匹配元素。类属性被定义为一个以空格分隔的列表项,在这组类名中,必须有一项与类选择器中的类名完全匹配,此条样式声明才会生效。同时,类选择器与属性选择器中 [class~=类名]
是等价的,例如 div.value
和 div[class~=value]
等价。
示例:
/*所有 class 为 pastoral 的元素都为绿色*/
.pastoral {color: green}
/*所有 class 为 pastoral 的 h1 元素都为绿色*/
h1.pastoral {color: green}
/*所有 class 同时包含 pastoral 和 marine 的 p 元素都为绿色*/
p.pastoral.marine {color: green}
在一个 HTML 文档中,CSS ID 选择器会根据该元素的 ID 属性中的内容匹配元素,元素 ID 属性名必须与选择器中的 ID 属性名完全匹配。同样,与属性选择器中 [id=id属性]
是等价的。
示例:
/*将 id 为 chapter1 的 h1 元素设为绿色*/
h1#chapter1 {color: green}
/*所有 id 为 chapter1 的任意元素设置为绿色*/
#chapter1 {color: green}
使用伪类选择元素基于的是当前元素处于的状态,或者说元素当前所具有的特性,而不是元素的 id、class、属性等静态的标志。由于状态是动态变化的,所以一个元素达到一个特定状态时,它可能得到一个伪类的样式;当状态改变时,它又会失去这个样式。它的功能和 class 有些类似,但它是基于 DOM 文档之外的抽象,所以叫伪类。
CSS3 的伪类选择器分为六种:
和其它 CSS 选择器的不同之处在于伪类选择器都以冒号(colon, :
)开头。
动态伪类并不存在于 HTML 文档中,只有当用户和网站交互的时候才能体现出来,动态伪类包含两种:
锚点伪类::link
和 :visited
:link
- 用于还未被访问的链接:visited
- 用于用户访问过的链接示例:
/*将用户访问后 class 为 external 的链接设为绿色*/
a.external:visited {color: green}
用户行为伪类::hover
,:active
和 :focus
hover
- 常见情形为鼠标滑过某元素,但并未点击它。一些特殊装置可能不支持该伪类(例如触控笔)active
- 用于用户激活某元素时(用户单击鼠标左键和释放鼠标左键这段时间)focus
- 用于某元素获得焦点,经常用在表单元素上为了辅助标识那些指向文档特定部分链接的目标, CSS3 选择器引入了 :target
伪类。
在一些 HTML 文档中,会有部分链接指向文档内部的部分片段,这类链接以井号(number sign, #
)开头,紧接着片段标识符,例如:https://frankindev.com/2016/12/01/CSS-selector/#top。
假设你想修改 URI 指向的任何 h2 元素,但是又不想把样式应用到任何其它同类型的元素,那么以下示例就简单有用:
/*将获得 target 伪类的 h2 元素加粗,而其他的 h2 标题仍然保持原有设置*/
h2:target {font-weight: bold;}
如果想要创建应用于所有目标元素的样式,那么可以使用通用选择器:
:target {color: red}
使用语言伪类选择器来匹配使用语言的元素是非常有用的,特别是用于多语言版本的网站,作用更是明显。可以使用它来根据不同语言版本设置页面的字体风格。
语言伪类选择器是根据元素的语言编码匹配元素。这种语言信息必须包含在文档中,或者与文档关联,不能从 CSS 指定。
为文档指定语言,有两种方法:
<html lang="en-US">
<body lang="fr">
语言伪类选择器 E(element):lang(language) 表示选择匹配 E 的所有元素,且匹配元素指定了 lang 属性,其值是 language。
示例:
:lang(en) {quotes:'"' '"';}
:lang(en) q {background:red;}
:lang(fr) {quotes:'?' '?';}
:lang(fr) q {background:green;}
我想这个选择器我可以用来区分英语和中文的 blockquote,毕竟一大段的中文斜体真的不好看……
主要用于 form 表单元素上,以提高网页的人机交互、操作逻辑以及页面的整体美观,使表单页面更具个性与品位,而且使用户操作页面表单更便利和简单。
:enabled
- 匹配所有启用的表单元素:disabled
- 匹配所有禁用的表单元素:checked
- 匹配选中的复选按钮或单选按钮表单元素HTML 元素表单文本输入框,分启用和禁用;HTML 元素表单单选按钮和多选按钮,分选中和未选中。
结构伪类选择器是根据元素在文档树中的某些特性(如相对位置)定位到它们。也就是,通过文档树结构的相互关系来匹配特定的元素,从而减少 HTML 文档对 ID 或类名的定义,帮助你保持代码干净和整洁。
选择器 | 功能 |
---|---|
E:root | 选择匹配元素 E 所在文档的根元素。在 HTML 中,根元素始终是 html,此时该选择器与类型选择器匹配的内容相同 |
E:first-child | 匹配作为父元素的第一个子元素的元素 E,与 E:nth-child(1) 等同 |
E:last-child | 匹配作为父元素的最后一个子元素的元素 E |
E F:nth-child(n) | 选择父元素 E 的第 n 个子元素 F。其中 n 可以是整数(1、2、3)、关键字(even、odd),也可以是公式(2n+1、-n+5),且 n 值起始值为 1,而不是 0 |
E F:nth-last-child(n) | 选择元素 E 的倒数第 n 个子元素 F |
E:nth-of-type(n) | 选择父元素内具有指定类型的第 n 个 E 元素 |
E:nth-last-of-type(n) | 选择父元素内具有指定类型的倒数第 n 个 E 元素 |
E:first-of-type | 选择父元素内具有指定类型的第一个 E 元素,与 E:nth-of-type(1) 等同 |
E:last-of-type | 选择父元素内具有指定类型的最后一个 E 元素,与 E:nth-last-of-type(1) 等同 |
E:only-child | 选择父元素只包含一个子元素,且该子元素匹配 E 元素 |
E:only-of-type | 选择父元素只包含一个同类型的子元素,且该子元素匹配 E 元素 |
E:empty | 选择没有子元素的元素,而且该子元素也不包含任何文本节点 |
看下面这张图,让你分清楚结构伪类选择器:
CSS 结构伪类选择器
结构伪类选择器中的参数 n:
n*length
:n 从零开始计算,length>0 的整数;为 n 的倍数n+length
:选择 >=length 的元素-n+length
:选择 <=length 的元素n*length+b
:b 为偏移值,表示隔 length 个元素选中第 n*length+b 个元素odd
:选择奇数even
:选择偶数还不明白,看看这张表格理解消化一下:
n | 2n+1 | 4n+1 | 4n+4 | 4n | 5n-2 | -n+3 |
---|---|---|---|---|---|---|
0 | 1 | 1 | 4 | — | — | 3 |
1 | 3 | 5 | 8 | 4 | 3 | 2 |
2 | 5 | 9 | 12 | 8 | 8 | 1 |
3 | 7 | 13 | 16 | 12 | 13 | — |
4 | 9 | 17 | 20 | 16 | 18 | — |
5 | 11 | 21 | 24 | 20 | 23 | — |
:first-of-type
选择器类似于 :first-child
选择器,不同之处就是指定了元素的类型,其主要用来定位一个父元素下的某个类型的第一个子元素。:first-child
选择的一定是第一个子元素,但是 :first-of-type
选择的不一定是第一个元素,而是第一个出现的指定类型的元素。
否定选择器 :not()
是 CSS3 的新选择器,类似 jQuery 中的 :not()
,用来定位不匹配该选择器的元素。一般起到过滤内容的作用。
:not(:not(...))
就不要用了。示例:
/*匹配所有 disabled 以外的 button 元素*/
button:not([DISABLED])
/*匹配所有不是 p 元素的其他任意元素*/
*:not(p)
/*匹配所有非链接类型的元素*/
html|*:not(:link):not(:visited)
CSS2.1 中用到的::first-line
、:first-letter
、:before
、:after
,CSS3 对伪元素进行了调整,在之前的基础上增加了一个冒号 ::first-line
、::first-letter
、::before
、::after
,还增加了 ::selection
伪元素,目前的浏览器对这两种伪元素都支持,不过最好采用新的规范,使用两个冒号。
::first-letter
:用来选择文本块的第一个字母,eg:下沉首字母::first-line
:用来选择元素的第一行文本::before
和 ::after
:不是指存在于标记中的内容,而是可以插入额外内容的位置。尽管生成的内容不会成为 DOM 的一部分,但它同样可以设置样式;要为伪元素生成内容,还需要配合 content
属性::selection
:用来匹配突出显示的文本,也就是用鼠标选中文本之后的样式。但需要注意:::selection
仅接受两个属性,一个是 background
,另一个是 color
示例:
p::first-line { text-transform: uppercase }
p::first-letter { color: green; font-size: 200% }
CSS 组合选择器(combinator)包括各种简单选择器的组合方式。在 CSS3 中包含了四种组合方式:
后代选择器(descendant selector)又称为包含选择器。后代选择器可以选择作为某元素后代的元素。
我们可以定义后代选择器来创建一些规则,使这些规则在某些文档结构中起作用,而在另外一些结构中不起作用。 举例来说,如果你希望只对 h1
元素中的 em
元素应用样式,可以这样写:
h1 em { color:red; }
上面这个规则会把作为 h1
元素后代的 em
元素的文本变为红色。其他 em
文本(如段落或块引用中的 em
)则不会被这个规则选中。
在后代选择器中,规则左边的选择器一端包括两个或多个用空格分隔的选择器。选择器之间的空格是一种结合符(combinator)。每个空格结合符可以解释为“… 在 … 找到”、“… 作为 … 的一部分”、“… 作为 … 的后代”,但是要求必须从右向左读选择器。 因此,h1 em
选择器可以解释为 “作为 h1
元素后代的任何 em
元素”。如果要从左向右读选择器,可以换成以下说法:“包含 em
的所有 h1
会把以下样式应用到该 em
”。实际作用的元素始终是最右边的那个。
关于后代选择器有一个常被忽略的地方,即两个元素之间的层次间隔可以是无限的。例如,如果写作 ul em
,这个语法就会选择从 u1
元素继承的所有 em
元素,而无论 em
的嵌套层次有多深。
另外,下面一个例子匹配一个 p 元素,如果该 p 元素是 div 元素的孙元素或更后的元素:
div * p { color: red; }
注意上例中星号两侧的空白符并不是通用选择器的一部分,这两个空白符不可或缺,用以表示 div
元素必须是 p
元素的父辈元素。
再如:
div p *[href] { color: red; }
这里将符合以下三个条件的元素设置为红色: 1)具有 href
属性;2)位于 p
元素内部;3)该 p
元素位于 div
元素中。
某些情况下,可能并不想选择一个任意的后代元素,而是希望缩小范围,只选择另一个元素的子元素(不是所有后代元素)。可以使用子结合符,即大于号(>)。
h1 > strong { color: red; }
div ol>li p { color: red; }
这里第一例比较简单,匹配 h1
的子元素 strong
;而第二例匹配一个 p
元素,它是 li
元素的后代元素,同时该 li
元素必须是 ol
元素的子元素,而 ol
元素又必须是 div
元素的后代元素。注意这里的 >
符号两侧都没有空白符。
相邻兄弟选择器 (adjacent sibling selector) 可选择紧接在另一元素后的元素,且二者有相同父元素。
/*选择所有位于 div 元素内的第一个 p 元素。*/
div+p { background-color:yellow; }
/*同上面类似,只是限定 h1 元素的 class 须为 opener*/
h1.opener + h2 { color: red; }
普通相邻兄弟选择器 (general sibling combinator) 选取所有指定元素的相邻兄弟元素。
h1 ~ pre { color: red; }
作用于以下片段:
<h1>Definition of the function a</h1>
<p>Function a(x) has to be applied to all figures in the table.</p>
<pre>function a(x) = 12x/13.5</pre>
会让 h1
临近的第一个 pre
设为红色。
优先级就是分配给指定的 CSS 声明的一个权重,它由匹配的选择器中的每一种选择器类型的数值决定,待会会讨论该数值的计算。
而当优先级与多个 CSS 声明中任意一个声明的优先级相等的时候,CSS 文件中最后出现的那个声明将会被应用到元素上,覆盖文件中之前出现的设置。
当同一个元素有多个声明的时候,优先级才会有意义。因为每一个直接作用于元素的 CSS 规则总是会接管/覆盖 (take over) 该元素从祖先元素继承而来的规则。
选择器的优先级由选择器本身的组件确定。优先级表述为 4 个部分,从 0,0,0,0 开始,然后具有以下属性再增加权重:
h1 {color: red;} 0,0,0,1
p em {color: purple;} 0,0,0,2
.grape {color: purple} 0,0,1,0
*.bright {color: yellow} 0,0,1,0
p.bright em.dark {color: maroon} 0,0,2,2
div#sidebar *[href] {color: silver} 0,1,1,1
内联样式的优先级:上面示例中都是以 0 开头的,所以你可能会奇怪为什么会这样。一般地,第一个 0 是为内联样式声明保留的,它比所有其他声明的优先级都高,内联样式的优先级是 1,0,0,0。这里的内联样式指的是元素 style="..."
属性,而 HTML 中 <style>...</style>
和 <link href=".../*.css">
同级,取决于它俩出现的顺序。
!important 的优先级:有时某个声明可能非常重要,超过了所有其他声明,包括上述的内联样式。CSS2.1 称之为重要声明,并允许在这些声明的结束分号之前插入 !important
来标识:
p.dark {color: #333 !important; background: white;}
必须正确地放置 !important
,否则声明将无效,它应该总是放在声明的最后,即分号之前。如果一个属性的值包含多个关键字,则必须放在最后一个关键词的后面,比如 font:sss,sss !important
。
读取选择器的原则是从右到左。因此,我们书写的右边的最后一个选择器,被称作关键选择器,对于效率有决定性影响。
优先级高的不一定效率高,举个例子:#id .class
与 div#id p.class
,前者效率高于后者,而后者优先级高于前者。我们需要在效率与优先级之间平衡取舍。
最后这部分内容关于效率的内容我没有去看参考资料,从这里直接拷贝而来,对目前的我来说,正确应用选择器比优化其效率更为重要,或许当我进一步熟悉 CSS 之后会再来总结这部分内容吧。
Frank Lin
Web Notes
2016.08.20
Liquid is a simple template language that Jekyll uses to process pages for your site. With Liquid you can output complex contents without additional plugins.
Web Notes
2017.03.18
By default, Jekyll 3 and versions above integrated with Rouge, a pure Ruby syntax highlighter which supports over 100 languages. Since Rouge themes are compatible with Pygments's stylesheets, it’s nice for us to choose a favourable style.
叹花 / 怅诗
自是寻春去校迟,不须惆怅怨芳时。
狂风落尽深红色,绿叶成阴子满枝。