好的,我们来详细讲解 CSS 的选择器和优先级,这是 CSS 中非常核心且重要的概念。
一、 CSS 选择器 (Selectors)
CSS 选择器是 CSS 规则的第一部分,它定义了这条规则将要应用到 HTML 文档中的哪些元素上。选择器的种类非常多,可以让你精确地定位到想要设置样式的元素。
以下是一些常见的 CSS 选择器类型:
- 基本选择器 (Basic Selectors):
-
类型选择器 (Type Selector) / 元素选择器 (Element Selector): 直接使用 HTML 标签名。
cssp { /* 选择所有的 <p> 元素 */ color: blue; } div { /* 选择所有的 <div> 元素 */ margin: 10px; }
-
类选择器 (Class Selector): 使用 . 加上类名,选择具有特定 class 属性的元素。一个元素可以有多个类名。
css.warning { /* 选择所有 class="warning" 的元素 */ font-weight: bold; color: red; } .highlight { /* 选择所有 class="highlight" 的元素 */ background-color: yellow; } .button.primary { /* 选择同时具有 button 和 primary 类的元素 */ background-color: blue; color: white; }
-
ID 选择器 (ID Selector): 使用 # 加上 ID 名,选择具有特定 id 属性的元素。ID 在一个 HTML 文档中必须是唯一的。
css#main-content { /* 选择 id="main-content" 的元素 */ padding: 20px; }
-
通用选择器 (Universal Selector): 使用 *,选择页面上的所有元素。通常用于设置全局默认值或重置样式,但性能较低,需谨慎使用。
css* { /* 选择所有元素 */ box-sizing: border-box; /* 一个常见用途 */ margin: 0; padding: 0; }
-
属性选择器 (Attribute Selector): 根据元素的属性或属性值来选择。
css[disabled] { /* 选择所有带有 disabled 属性的元素 */ opacity: 0.5; cursor: not-allowed; } input[type="text"] { /* 选择 type="text" 的 input 元素 */ border: 1px solid #ccc; } a[href^="https://"] { /* 选择 href 属性值以 "https://" 开头的 a 元素 */ color: green; } img[src$=".png"] { /* 选择 src 属性值以 ".png" 结尾的 img 元素 */ border: 2px solid pink; } a[href*="example.com"] { /* 选择 href 属性值包含 "example.com" 的 a 元素 */ font-weight: bold; }
-
组合选择器 (Combinators):
-
后代选择器 (Descendant Combinator): 使用空格 ,选择某个元素内部的所有后代元素(无论层级多深)。
cssdiv p { /* 选择 <div> 元素内部的所有 <p> 元素 */ margin-bottom: 1em; }
-
子选择器 (Child Combinator): 使用 >,只选择某个元素的直接子元素。
cssul > li { /* 选择 <ul> 元素的直接子元素 <li> */ list-style-type: square; }
-
相邻兄弟选择器 (Adjacent Sibling Combinator): 使用 +,选择紧跟在某个元素后面的同级元素。
cssh2 + p { /* 选择紧跟在 <h2> 元素后面的第一个同级 <p> 元素 */ margin-top: 0; }
-
通用兄弟选择器 (General Sibling Combinator): 使用 ~,选择某个元素之后的所有同级元素。
cssh2 ~ p { /* 选择在 <h2> 元素之后的所有同级 <p> 元素 */ color: gray; }
-
-
伪类选择器 (Pseudo-classes):
-
以单个冒号 : 开头,用于选择处于特定状态或位置的元素。
-
状态伪类: :hover (鼠标悬停), :focus (获得焦点), :active (被激活/点击), :visited (已访问链接), :disabled (禁用状态), :checked (选中状态 - 用于 radio/checkbox)
cssa:hover { text-decoration: underline; } input:focus { outline: 2px solid blue; }
-
结构伪类: :first-child, :last-child, :nth-child(n), :nth-last-child(n), :nth-of-type(n), :nth-last-of-type(n), :only-child, :only-of-type, :empty, :not(selector)
cssli:first-child { /* 选择是其父元素的第一个子元素的 li */ font-weight: bold; } tr:nth-child(even) { /* 选择表格中的偶数行 */ background-color: #f2f2f2; } p:not(.intro) { /* 选择所有不包含 intro 类的 p 元素 */ line-height: 1.6; }
-
-
伪元素选择器 (Pseudo-elements):
- 以双冒号 :: 开头(旧语法也用单冒号 :,现代推荐用双冒号以区分伪类),用于选择元素的某个特定部分,而不是元素本身。
-
::before: 在元素内容之前插入生成的内容。
-
::after: 在元素内容之后插入生成的内容。
-
::first-letter: 选择元素内第一个字母。
-
::first-line: 选择元素内第一行。
-
::selection: 选择用户用鼠标高亮选中的部分。
-
::placeholder: 选择输入框的占位符文本。
cssp::first-letter { font-size: 2em; float: left; margin-right: 0.1em; } .clearfix::after { /* 常用清除浮动技巧 */ content: ""; display: table; clear: both; } input::placeholder { color: #aaa; }
二、 CSS 优先级 (Specificity)
当多个 CSS 规则应用到同一个元素上,并且这些规则设置了相同的属性时,浏览器需要一种机制来决定哪个规则的样式最终生效。这个机制就是 优先级 (Specificity) 。
优先级由选择器的构成决定,可以理解为一个 四位的数值 (a, b, c, d) ,比较时从左到右逐位比较,数值越大的优先级越高。
- 计算规则:
- a (行内样式 - Inline Styles): 如果样式是写在 HTML 元素的 style 属性中,则 a=1,否则 a=0。 - b (ID 选择器): 计算选择器中 ID 选择器 (#id) 的数量。
- c (类、属性、伪类选择器): 计算选择器中类选择器 (.class)、属性选择器 ([type="text"]) 和伪类选择器 (:hover) 的数量。 - d (类型、伪元素选择器): 计算选择器中类型选择器 (div) 和伪元素选择器 (::before) 的数量。
注意:
- 通用选择器 * 不增加优先级 (0,0,0,0)。
- 组合器 ( , >, +, ~) 不增加优先级。
- :not() 伪类本身不增加优先级,但其括号内的选择器按正常规则计算。
- 继承的样式优先级最低,低于任何直接指定的样式(甚至低于 *)。
- 比较规则:
- 从左到右比较 (a, b, c, d) 的值。
- 首先比较 a,a 值大的优先级高。
- 如果 a 值相同,则比较 b,b 值大的优先级高。
- 如果 a 和 b 都相同,则比较 c,c 值大的优先级高。
- 如果 a, b, c 都相同,则比较 d,d 值大的优先级高。
- 如果 (a, b, c, d) 完全相同,则遵循 层叠 (Cascade) 的下一个规则。
- 特殊情况:!important
-
在样式属性值后面加上 !important 会使该声明具有最高优先级,它会覆盖任何其他来源的样式声明,包括行内样式。
-
滥用 !important 会使 CSS 难以维护和调试,应尽量避免使用。 只有在确实需要覆盖第三方库或难以修改的样式,且没有其他更好方法时才考虑。
cssp { color: blue !important; /* 这个蓝色优先级最高 */ } #main-content p { color: red; /* 这个会被 !important 覆盖 */ }
- 层叠规则 (Cascade):
浏览器决定最终应用哪个样式的完整过程被称为层叠,其顺序如下:
-
来源和重要性 (Origin and Importance):
- 浏览器默认样式 (User-agent styles)
- 用户样式表 (User styles) - 普通
- 作者样式表 (Author styles - 即我们写的 CSS) - 普通
- 作者样式表 - !important
- 用户样式表 - !important
- 浏览器默认样式 - !important (注意:!important 会颠倒作者和用户的优先级顺序)
-
优先级 (Specificity): 在同一来源内,优先级高的规则胜出(按前面讲的 a,b,c,d 计算)。
-
源顺序 (Source Order): 如果来源和优先级都相同,则后定义的规则覆盖先定义的规则(写在后面的 CSS 文件或 块中的规则,或者同一个样式表中后出现的规则,优先级更高)。
示例:
ini
<div id="content" class="main">
<p class="text">这是一个段落。</p>
</div>
css
/* 规则 1: (0,0,1,1) = 11 */
div p {
color: blue;
}
/* 规则 2: (0,0,2,0) = 20 */
.main .text {
color: green;
}
/* 规则 3: (0,1,1,0) = 110 */
#content .text {
color: red;
}
/* 规则 4: (0,1,0,1) = 101 */
#content p {
color: purple;
}
p { /* 规则 5: (0,0,0,1) = 1 */
color: black;
}
- 比较规则 1 和 5:(0,0,1,1) > (0,0,0,1),规则 1 胜出,颜色为 blue。
- 比较规则 2 和 1:(0,0,2,0) > (0,0,1,1),规则 2 胜出,颜色为 green。
- 比较规则 3 和 2:(0,1,1,0) > (0,0,2,0),规则 3 胜出,颜色为 red。
- 比较规则 4 和 3:(0,1,0,1) < (0,1,1,0),规则 3 仍然胜出,颜色为 red。
最终应用: 段落文字颜色为 red,因为 #content .text 的优先级 (0,1,1,0) 是最高的。
总结:
- 使用合适的 选择器 来定位元素。
- 理解 优先级 (Specificity) 的计算和比较规则 (a,b,c,d)。
- 知道 !important 的作用和副作用。
- 了解完整的 层叠 (Cascade) 顺序(来源 -> 优先级 -> 源顺序)。