Skip to content

CSS 选择器(Day6 4/4) ​

本页对应 Day06_CSS,共 5 段视频,约 54 分钟。

学习目标 ​

  • 能区分并正确书写交集选择器与并集选择器,说明二者匹配条件、分隔符差异,并通过示例验证选择结果。
  • 能使用标签名、类名、ID及层级选择器组合成交集选择器,正确处理标签名在前、伪类在后等书写位置限制。
  • 能使用 :link、:visited、:hover、:active 设置元素状态样式,说明各伪类触发条件及适用元素范围。
  • 能按 link → visited → hover → active 顺序书写多个伪类选择器,并解释该顺序对样式覆盖和用户体验的影响。
  • 能计算组合选择器权重:先比较 ID 数量,再比较类与伪类数量,最后比较标签名数量;权重相同时后写覆盖先写。
  • 能识别并集选择器不合并权重、行内样式优先级最高,并使用浏览器开发者工具检查伪类状态与样式覆盖关系。

知识点 ​

交集选择器:两个条件必须同时满足 ​

为什么需要:有时只想选中“既是 p 标签、又带 item 类名”的元素,单写 p 或 .item 都会选多。
怎么想:把多个选择器紧挨着写,表示“并且”。p.item 就是标签名是 p,类名是 item,缺一不可。
怎么做:

html
<div class="wrapper">
  <p class="item">段落一</p>
  <p class="item active">段落二</p>
</div>
<p class="item">段落三</p>
css
.wrapper { padding: 20px; width: 600px; background: #ccc; }
p { width: 560px; background: #aaa; }
p.item { background: #900; color: #fff; }
.wrapper p.item { /* 从 .wrapper 后代中找既是 p 又是 .item 的元素 */ }
.item.active { font-size: 2em; }

p.item 只命中前两个在 .wrapper 里的 p;外面那个只有类名、标签名不对,不命中。交集还能和层级组合:.wrapper p.item。类名和类名也能交集:.item.active,顺序无所谓。
易错点:标签名参与交集时必须写前面,.item p 不是交集;写成 p .item 中间加空格就变成后代选择器。标签名和标签名不能做交集,因为一个元素只有一个标签名。

并集选择器:逗号分隔,各选各的 ​

为什么需要:想让多个不同选择器共享同一组样式,比如所有标题都不加粗。
怎么想:逗号表示“或者”,选择器一选中的、选择器二选中的,全都要。
怎么做:

css
p, li { border: 2px solid #900; }
h1, h2, h3, h4 { font-weight: normal; }

也可以混着写:.item, p。
易错点:并集不是把多个选择器合成一个整体去比权重,而是拆开各自计算。h1, h2 不能算成“两个标签名”来压别人。

伪类选择器:根据状态选元素 ​

为什么需要:超链接有未访问、已访问、鼠标悬停、按下未抬起等状态,普通选择器选不到“状态”。
怎么想:伪类就是“当元素处于某种状态时”再选中它。四个常用状态::link 未访问超链接,:visited 已访问超链接,:hover 鼠标悬停,:active 鼠标按下未抬起。
怎么做:

css
a:link { color: pink; }
a:visited { color: #099; }
a:hover { color: #990; }
a:active { color: red; }

.news li:hover { background: #ccc; color: #fff; }

:hover、:active 不挑元素,其他元素也能用;但通常写成交集,如 a:hover、.news li:hover,否则 :hover 会命中任何被悬停的元素。
易错点::link、:visited 主要针对超链接;伪类与其他选择器做交集时,伪类要写在后边,a:hover 不能写成 :hover a。调试时可在开发者工具里给元素强制 :hover、:active 状态,观察哪些规则命中、哪些被删除线覆盖。

多个伪类一起写:顺序影响体验 ​

为什么需要:一个超链接可能同时满足 :visited 和 :hover,样式冲突时后写的覆盖先写的。
怎么想:权重相同,就看书写顺序。越不容易发生的状态,越应写后面,让用户操作后能看到反馈。
怎么做:按 LVHA 写:

css
a:link { color: pink; }
a:visited { color: #099; }
a:hover { color: #990; }
a:active { color: red; }

易错点:把 :hover 写在 :visited 前,鼠标放上去仍显示已访问颜色;把 :active 写在 :hover 前,按下时会被 :hover 覆盖。记忆法可记“love hate”:L-V-H-A。语法上并非强制,但为了用户体验应这样排。

选择器权重:先比 ID,再比类/伪类,再比标签 ​

为什么需要:多个规则选中同一元素且样式冲突时,必须知道谁生效。
怎么想:逐级比较数量:先比 ID 数量,多者赢;ID 相同再比“类 + 伪类”数量;还相同再比标签名数量;最后仍相同,后写的覆盖先写的。
怎么做:

css
.news-item { color: red; }
ul li { color: green; }          /* 类干不过 .news-item */

#book { background: #990; }
.news li.news-item.active { background: #099; } /* ID 数量多,赢 */

伪类和类权重相同。并集要拆开各自算;行内 style 优先级最高。
易错点:不要用 100/10/1 硬加分数,遇到多个 ID 时按“逐级数量比较”更稳;权重相同才看先后,且只覆盖冲突属性,不冲突的样式会层叠保留。

作业说明与完成范围 ​

本节笔记是两次作业提交:一是“背景图片固定案例”,二是“列表效果案例”。笔记只给了案例链接和一条关键提示:ul、ol 自带 40px 左内边距 padding-left。转写稿主要讲的是交集选择器、并集选择器、伪类选择器、伪类书写顺序和选择器权重,与“背景图片固定”没有直接对应内容;其中可直接用于本节作业的,是列表默认缩进、list-style 重置以及 :hover 调试这一段。因此下面不虚构背景固定案例的课堂调试过程,只按作业目标给出验收思路;列表部分则结合转写稿中的做法展开。

本节笔记未提供图片,故不虚构图片;下面保留笔记中的两个作业链接,并给出列表练习中可复用的代码。

作业一:背景图片固定案例 ​

为什么需要:页面滚动时,如果背景图跟着内容一起滚,视觉上会比较“晃”;把背景图固定住,可以让内容在背景上滚动,形成层次感。这个作业要练的是背景相关属性,而不是单纯换一张图。

怎么想:先明确“固定”指的是背景图相对视口固定,不是让整个容器固定。实现时通常给带背景图的容器设置背景图片、背景位置、背景尺寸,再设置 background-attachment: fixed。检查时滚动页面,观察内容是否移动、背景图是否保持不动。

怎么做:按笔记链接完成页面:

https://example.fuming.site/HTML&CSS/04-%E8%83%8C%E6%99%AF%E5%9B%BE%E5%9B%BA%E5%AE%9A.html

完成后重点自检:背景图路径是否正确;容器是否有足够高度让页面产生滚动;滚动时背景是否固定;背景图是否被裁切或重复。由于转写稿没有该案例的具体代码,这里不补造课堂写法,只保留作业目标与验收点。

易错点:只写 background-image 而忘记 background-attachment: fixed;容器没有高度,页面滚不起来,看不出效果;图片路径写错;把 fixed 误解成“容器固定”;背景图尺寸没有配合 background-size,导致只看到局部。提交前一定要实际滚动页面验证。

作业二:列表效果案例 ​

为什么需要:列表默认带有项目符号和左缩进,直接做新闻列表或导航时往往不符合设计稿。作业要练的是:会重置列表默认样式,会控制列表项间距,会用 :hover 做鼠标悬停反馈。

怎么想:转写稿里说得很清楚:列表往右缩进“其实就是一内边距,是 ul 自带的左内边距”。所以只写 list-style: none 只能去掉小圆点,不能去掉缩进;还要把 padding-left 归零。笔记也提示:ul、ol 自带 40px 左内边距 padding-left。想清楚这两层,列表重置就不会只做一半。

怎么做:按链接完成列表页:

https://example.fuming.site/HTML&CSS/05-%E5%88%97%E8%A1%A8.html

可复用转写稿中的列表练习写法:

css
.news {
  list-style: none;
  padding-left: 0;
  width: 600px;
}

.news li {
  padding: 10px;
}

.news li:hover {
  background: #ccc;
}

转写稿中的调试过程是:鼠标放到哪个 li 上,哪个 li 变色;鼠标离开后样式恢复。也可以在开发者工具中给元素临时加上 :hover 状态,检查选择器是否选中、样式是否生效。

易错点:只写 list-style: none,忘记 padding-left: 0;把 padding-left 写成 margin-left;:hover 前面不加限定,导致页面其他元素也被影响;选择器写错层级,例如把 .news li:hover 写成 .news:hover li;忘记检查鼠标离开后的恢复状态。提交前用开发者工具确认默认缩进来源,并实际悬停测试。

课堂画面 ​

课堂画面 1

课堂画面 2

课堂画面 3

课堂画面 4

课堂画面 5

代码示例 ​

示例一:交集选择器与并集选择器 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>交集选择器与并集选择器</title>
<style>
  /* 并集选择器:逗号分隔,各算各的,谁符合谁生效 */
  h1, h2, h3, h4 {
    font-weight: normal;
  }

  .wrapper {
    width: 600px;
    padding: 20px;
    background-color: #ccc;
  }

  p {
    width: 560px;
    padding: 10px;
    background-color: #ccc;
  }

  /* 交集选择器:标签名 p 且 类名 item,缺一不可 */
  p.item {
    background-color: #900;
    color: #fff;
  }

  /* 交集选择器与后代选择器组合:wrapper 后代中,既是 p 又是 .item */
  .wrapper p.item {
    background-color: #099;
  }

  /* 类名与类名组合:顺序无所谓,.active.item 效果一样 */
  .item.active {
    font-size: 2em;
  }
</style>
</head>
<body>
  <h1>标题一(不再加粗)</h1>
  <h2>标题二(不再加粗)</h2>

  <div class="wrapper">
    <p>普通段落</p>
    <p class="item">wrapper 内的 item 段落</p>
    <p class="item active">wrapper 内的 item + active 段落</p>
  </div>

  <p>wrapper 外的普通段落</p>
  <p class="item">wrapper 外的 item 段落</p>
  <p class="item active">wrapper 外的 item + active 段落</p>
</body>
</html>

关键行与易错点

  • p.item 之间没有任何分隔符,表示“标签名是 p 且 类名是 item”;写成 p .item(加空格)就变成后代选择器,意思完全变了。
  • 有标签名参与交集组合时,标签名只能写在前面:p.item 合法,.itemp 会被当成类名,.item + 空格 + p 则是后代选择器。
  • 类名与类名组合(.item.active)顺序无所谓,因为两个都有 . 作分隔符。
  • .wrapper p.item 权重(1 类 + 1 类 + 1 标签)高于 p.item(1 类 + 1 标签),所以 wrapper 内的 item 段落背景最终是 #099,不是 #900——这就是“权重高者胜”。
  • 并集选择器 h1, h2, h3, h4 只是简写,权重各自计算,不会叠加。

示例二:伪类选择器(超链接四态 + 列表 hover) ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>伪类选择器</title>
<style>
  /* 书写顺序:link → visited → hover → active,即 love hate 记忆法 */
  a:link    { color: #f0f; }   /* 未访问过的超链接 */
  a:visited { color: #099; }   /* 已访问过的超链接 */
  a:hover   { color: #990; }   /* 鼠标悬停 */
  a:active  { color: #f00; }   /* 鼠标按下不松手 */

  .news {
    width: 600px;
    list-style: none;   /* 去掉小圆点 */
    padding: 0;         /* 去掉 ul 自带的 40px 左内边距 */
  }

  .news li {
    padding: 10px;
  }

  /* 后代选择器 + 交集:.news 后代的 li,且鼠标悬停其上 */
  .news li:hover {
    background-color: #ccc;
    color: #fff;
  }
</style>
</head>
<body>
  <a href="https://www.baidu.com">百度</a>
  <a href="https://www.douban.com">豆瓣</a>
  <a href="https://www.360.com">360</a>
  <a href="https://www.4399.com">4399</a>

  <ul class="news">
    <li>新闻列表第一条新闻消息</li>
    <li>新闻列表第二条新闻消息</li>
    <li>新闻列表第三条新闻消息</li>
  </ul>
</body>
</html>

关键行与易错点

  • :link / :visited 只对超链接有意义;:hover / :active 是不挑元素的,任何元素都能用(如上例的 li:hover)。
  • 伪类与其他选择器做交集组合时,伪类必须写在后面(a:hover 可以,:hovera 不成立),这和标签名必须写前面的规则刚好相反。
  • 直接裸写 :hover 相当于 *:hover,会让页面所有元素都响应,实际开发一定要加交集限定,如 .news li:hover。
  • 四个伪类同时写时按 LVHA(link → visited → hover → active) 顺序,否则会被同权重的后写规则覆盖:例如 a:visited 写在 a:hover 后面,鼠标移上去颜色根本不变。
  • ul、ol 自带 40px 的 padding-left(列表缩进),要清掉就写 padding: 0,同时 list-style: none 去掉项目符号。

示例三:组合选择器权重比较 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>选择器权重</title>
<style>
  ul {
    width: 600px;
    padding: 0;
    list-style: none;
  }

  li {
    padding: 10px;
    margin-top: 10px;
    background-color: #ccc;
  }

  /* 权重:1 个类 = 10 */
  .news-item {
    color: #f00;
  }

  /* 权重:2 个标签名 = 2,干不过上面的 10,写后边也没用 */
  ul li {
    color: #080;
  }

  /* 权重:3 类 + 1 标签 = 31 */
  .news li.news-item.active {
    background-color: #099;
  }

  /* 权重:1 个 ID = 100,碾压上面所有组合 */
  #book {
    background-color: #990;
  }
</style>
</head>
<body>
  <ul class="news">
    <li class="news-item">第一条新闻</li>
    <li class="news-item active" id="book">第二条新闻</li>
    <li class="news-item">第三条新闻</li>
  </ul>
</body>
</html>

关键行与易错点

  • 权重速记:ID = 100,类 / 伪类 = 10,标签名 = 1,通配符 * 不计;伪类和类权重相同。
  • 比较规则是“逐级 PK”:先比 ID 数量,多者胜就结束;ID 打平再比类 + 伪类数量;还打平再比标签名数量;全打平则后写的覆盖先写的(仅限有冲突的样式,不冲突的会层叠共存)。
  • ul li 虽然写在 .news-item 后面,但权重 2 < 10,所以文字还是红色——权重不够,位置再靠后也没用。
  • .news li.news-item.active 虽然类名堆到 31,仍然干不过一个 #book 的 100,所以第二条背景最终是 #990。
  • 并集选择器(逗号)不参与合并计算,要拆开各自算权重;只有后代、子元素、交集这类组合才把权重加在一起。
  • 行内 style 和 !important 不属于选择器权重体系,优先级更高,不要和这里的比较规则混为一谈。

常见错误 ​

  • 现象:p .item 选中了错误元素或完全失效 → 原因:交集选择器中间多写空格,变成后代选择器 → 修法:写成 p.item,选择器之间无分隔符。
  • 现象:a :hover 悬停时父级/后代异常,目标链接不生效 → 原因:伪类前多空格,条件被拆成后代关系 → 修法:限制元素时紧贴写 a:hover,需要多条件时用交集组合。
  • 现象:超链接 :hover、:active 明明写了却不显示 → 原因:四个伪类顺序不当,同权重时后写规则覆盖前写规则 → 修法:按 :link、:visited、:hover、:active 的顺序检查并调整。
  • 现象:组合选择器权重判断错误,以为多个标签名能压过一个类名 → 原因:把权重当成固定十进制相加 → 修法:先比 ID 数量,再比类+伪类数量,再比标签名数量;仍相同才由后写覆盖。
  • 现象:并集选择器整体参与权重比较,导致样式覆盖判断错误 → 原因:把逗号两侧当成一个组合选择器 → 修法:并集拆开,各自计算各自权重。
  • 现象:列表案例左侧缩进、对齐与设计稿不一致 → 原因:忽略 ul、ol 默认 padding-left: 40px → 修法:显式重置或重设 padding-left,再调整 list-style 与间距。

练习 ​

  1. 写一个交集选择器,只选中同时具有 item 和 active 两个类名的 li,为其设置背景色与文字颜色;验收:只有同时具备两个类名的列表项变化。
  2. 完成新闻列表悬停高亮:鼠标移到哪个 li,哪个 li 变色;验收:使用 :hover 交集写法,不能影响整个列表或其他后代元素。
  3. 给同一组超链接分别设置未访问、已访问、悬停、按下四种状态颜色;然后故意把 :active 放到 :hover 前面,观察并记录差异,再恢复合理顺序。
  4. 比较以下两组选择器权重并说明判断到哪一步结束:#book 与 .news li.item.active;.news li:hover 与 ul li。
  5. 修复一个列表案例:去掉 ul/ol 默认 40px 左内边距造成的异常缩进,同时保留可读的项目符号与行距;验收:列表左对齐符合页面容器,不出现双重缩进。

原视频对照 ​

#视频时长
1交集选择器07:44
2并集选择器02:17
3伪类选择器15:17
4伪类选择器书写顺序12:03
5选择器权重17:20

小结 ​

  • 交集选择器靠“紧挨”表达同时满足,标签名参与时位置不能随意。
  • 伪类用于状态选择,限制具体元素时通常要与其他选择器做交集。
  • 超链接四伪类的书写顺序主要影响用户体验,不是语法硬性要求。
  • 组合选择器权重比较应逐级看 ID、类+伪类、标签名数量,不要按十进制换算。
  • 并集选择器要拆开分别计算权重,不能把逗号两侧合并比较。
  • 列表默认样式会干扰布局,作业中应显式处理 padding-left、list-style 等。
  • 调试工具可强制元素进入 :hover、:active 状态,便于定位伪类规则是否命中。