Skip to content

层级选择器与属性选择器(Day12 1/3) ​

本页对应 Day12_CSS3,共 6 段视频,约 1 小时 5 分。

学习目标 ​

  • 能够列举并说明 HTML5 新增表单属性、表单控件类型、音视频标签及全局属性的用途,并在示例中正确选用。
  • 能够使用后代选择器、子元素选择器、相邻兄弟选择器(+)和通用兄弟选择器(~)按层级关系选中目标元素,并完成导航分隔线或元素间距场景。
  • 能够编写 [attr]、[attr=val]、[attr^=val]、[attr$=val]、[attr*=val] 五种属性选择器,并与元素选择器或类选择器进行交集组合以精确选中元素。
  • 能够使用动态伪类选择器 :focus 为表单控件设置获取焦点后的样式,并说明默认 outline 与边框的区别。
  • 能够使用目标伪类选择器 :target 为当前锚点对应元素设置样式,并说明其与 a、form 标签的 target 属性无关。
  • 能够使用语言伪类选择器 :lang() 选择指定语言元素,并准确说明其与 [lang="..."] 属性选择器在语言继承和元素自身属性设置上的区别。

知识点 ​

一、回顾:HTML5表单与CSS3新增能力 ​

为什么需要:这些内容是后面选择器、布局和移动端样式的基础,尤其表单验证、音视频标签、CSS3兼容写法经常在项目里遇到。
怎么想:先分清“HTML5新增”与“CSS3新增”。表单部分记住:required、autofocus、autocomplete、pattern、form;新增 type 有 email、number、url、tel、search、range、color、date、month、week、time、datetime-local 等。音视频优先用 video/audio,视频 MP4、音频 MP3,兼容性较好。CSS3 兼容性要按模块看,私有前缀只作了解,实际可用自动化工具处理,不必手写一堆前缀。新增长度单位重点记 rem(只看根元素字体大小)和 vw(视口宽度分成100份),移动端布局常用。颜色新增 rgba()、hsl()、hsla(),其中 a 是0到1的不透明度。
怎么做:例如 input:required 提交时验证;<video src="x.mp4" controls></video>;移动端宽度可用 width: 50vw;。
易错点:autocomplete 要配合 name 才更容易看到输入历史;tel 并不验证电话号码,主要在移动端弹数字键盘;rem 不是相对父元素,别和 em 混淆。

二、层级选择器:相邻兄弟与通用兄弟 ​

为什么需要:做导航分割线、浮动元素间距时,过去常给每个元素加边框,再单独给第一个或最后一个去掉,代码啰嗦。兄弟选择器可以“只选需要的那个”。
怎么想:后代选择器和子元素选择器是“往里找”;兄弟选择器是“往后找”。+ 找紧邻在后面的一个兄弟,~ 找后面所有兄弟。
怎么做:

css
.active + p {
  background: #900;
  color: #fff;
}

.active ~ p {
  background: #900;
  color: #fff;
}

调试时先给 .active 加个标记,观察谁被选中;把 + p 改成 + div 会发现选不中,因为紧邻的兄弟标签不匹配;页面有多个 .active 时,会分别从每个 .active 往后找。导航分割线可写成:

css
.nav a + a {
  border-left: 1px solid #999;
}

这样第一个 a 后面没有紧邻的 a,自然不会加左边框。
易错点:+ 不是“后面任意一个”,必须紧邻;不能选前面的兄弟;~ 可能重复匹配后面的元素,但样式重复设置通常无影响。组合时属性选择器、伪类通常写在后面。

三、属性选择器:按属性名和值筛选 ​

为什么需要:有时不想额外加类名,只想根据 title、alt、src 等属性选元素。
怎么想:记住5种常用写法:有某属性、等于某值、以某值开头、以某值结尾、包含某值。
怎么做:

css
[title] { border: 2px solid #900; }
[title="高考乐"] { border: 2px solid #900; }
[title^="高"] { border: 2px solid #900; }
[title$="乐"] { border: 2px solid #900; }
[title*="乐"] { border: 2px solid #900; }
img[title] { border: 2px solid #900; }

实际中给图片加 title,再给两个 p 也加 title,发现 [title] 会把 p 也选上,说明它不挑标签名;写成 img[title] 才是交集组合,只选图片。
易错点:[title] 只看有没有属性,不看值;等号后的值要加引号;^= 是开头,$= 是结尾,*= 是包含;属性选择器单独可用,也可与其他选择器交集,通常写在其他选择器后面。波浪号等于、竖杠等于了解即可,实际少用。

四、动态伪类选择器::focus ​

为什么需要:表单控件获得焦点时,需要明显高亮,提示用户当前正在输入。
怎么想:focus 是“获得焦点”,鼠标点进去或按 Tab 键切换都算。它主要作用于表单控件等可聚焦元素。
怎么做:

css
input, textarea {
  padding: 10px;
  width: 400px;
  border: 1px solid #999;
  display: block;
  margin-top: 10px;
  outline: none;
}

input:focus, textarea:focus {
  border: 2px solid red;
}

调试时先点输入框,再按 Tab 切换焦点,观察边框变化。浏览器默认焦点样式是 outline,不是 border,所以要用 outline: none; 去掉自带轮廓。
易错点:不要写成 outline: no,正确是 outline: none;;不要给普通 div 乱写 :focus,它通常不能获得焦点;去掉 outline 后要自己补可见的焦点样式,别让键盘用户失去提示。

五、目标伪类选择器::target ​

为什么需要:页面内锚点跳转后,希望当前跳到的区块有高亮,告诉用户“你到这里了”。
怎么想:URL 后面的 #id 对应页面中 id 相同的元素,:target 就选中这个元素。它和 a 标签的 target 属性没有关系。
怎么做:

css
section:target {
  background: #900;
  color: #fff;
}

页面里写若干 section,分别设置 id,导航用 href="#part2" 跳转。点击后地址栏出现 #part2,对应区块被选中。也可交集组合:.section:target。
易错点:没有 hash 时不会选中;名字相同不代表含义相同,别把 :target 和 target 属性瞎联想;它选的是当前锚点对应元素,不是“鼠标点过的元素”。

六、语言伪类选择器::lang() ​

为什么需要:按语言设置样式时会遇到经典问题::lang(zh-CN) 和 [lang="zh-CN"] 有什么区别?
怎么想:属性选择器很“单纯”,只看元素自身有没有写这个属性;:lang() 看语言含义,并且语言可以继承祖先设置。
怎么做:

css
:lang(zh-CN) {
  border: 1px solid red;
}

[lang="zh-CN"] {
  border: 1px solid red;
}

调试时给某个 div 单独写 lang="en",会发现 :lang(zh-CN) 选不中它,其他继承中文语言设置的元素能选中;而 [lang="zh-CN"] 通常只选中真正写了该属性的元素。
易错点::lang() 可能选中大量继承语言设置的元素;属性选择器不继承,只看形式。这个知识点实用价值不高,但面试常问,要能说清“含义/继承”与“属性是否书写”的区别。

先定位:这一节是“回顾”,不是新开坑 ​

为什么需要:学完 HTML5 和 CSS3 的一批新增点后,如果不回顾,很容易把“属性名”和“实际效果”混在一起。怎么想:把笔记当成检查清单,逐项问“它解决什么问题、在哪个场景用、浏览器什么时候验证”。怎么做:按“HTML5 新增标签 → 表单新增功能 → 音视频 → 全局属性 → CSS3 基本语法”顺序过一遍,每项都打开页面看效果。易错点:回顾不是背名词,像 required、autocomplete、download 都要看触发时机和限制。

HTML5 新增标签:让结构有语义 ​

为什么需要:过去大量用 div,结构可读性差,也不利于语义表达。怎么想:先按“页面区域”和“特殊内容”分类,不要把它们当样式标签。怎么做:排版布局用 header、footer、nav、section、aside、article、main、figure、figcaption;状态用 meter、progress;详情用 details、summary;注音用 ruby、rt;文本标记用 mark。调试时打开页面看结构是否清楚,details/summary 是否可展开。易错点:语义标签不会自动变好看;meter 和 progress 含义不同;details 要配 summary 才有可见标题。

表单新增属性:提示、必填、焦点、历史与关联 ​

为什么需要:表单需要更少的 JS 完成提示、校验和体验优化。怎么想:把属性分成“提示类、校验类、体验类、关联类”。怎么做:placeholder 做纯提示;required 做必填/必选;autofocus 自动获取焦点;autocomplete 控制输入历史;form 让控件写在 form 外也能通过表单 id 关联;pattern 先了解,需正则。调试时提交表单看 required 是否阻止提交;autocomplete 必须给控件加 name 才容易看到历史,off 可关闭;form 的值写表单 id。易错点:required 是提交时验证;autocomplete 不是只写属性名,有 on/off,默认通常是 on;form 不是写类名。

新增表单类型与 datalist:输入更精准 ​

为什么需要:不同数据需要不同键盘、选择器和提交验证。怎么想:先分“输入框类、选择框类、日期时间类”。怎么做:输入框类有 email、number、url、tel、search;选择框类有 range、color;日期时间类有 date、month、week、time、datetime-local。datalist 做搜索框下拉提示,input 的 list 要与 datalist 的 id 一致。调试时:email/url 在提交时验证;number 可设 min/max/step,step 默认 1,也可写 0.1;tel 不验证号码,移动端主要弹数字键盘;search 有搜索语义和小叉;range 是拖动选数字,也可有 min/max/step。易错点:tel 别以为会验证电话;range 和 number 相似但交互不同;datalist 不是 select。form 上的 novalidate 会阻止自带验证,适合完全交给 JS。

音视频与全局属性:少标签解决播放和下载 ​

为什么需要:不依赖插件即可播放媒体,下载也有原生属性。怎么想:媒体标签少,重点看格式和兼容;全局属性看通用性。怎么做:用 video、audio、source;课堂强调视频常用 MP4、音频常用 MP3,兼容性好。全局属性记 hidden;a 新增 download。调试:给链接加 download 后点击看是否下载;注意它要求目标文件与当前文件同源,双击本地打开或跨服务器目标文件往往没有下载效果。同源先简单理解为 IP/域名一致,后续前后端交互再细讲。易错点:download 不是万能;hidden 不是删除元素;source 按兼容需求使用。

CSS3 基本语法:私有前缀、长度单位、颜色 ​

为什么需要:CSS3 模块多,兼容性不一致,单位和颜色也需要扩展。怎么想:私有前缀是浏览器“正在尝试支持”的写法;长度单位看参照物;颜色看透明度和色相体系。怎么做:私有前缀可写“带前缀 + 不带前缀”提高兼容,但实际项目可用自动化工具,不必手写;新长度单位 rem、vw、vh、vmax、vmin 中,rem 永远只看根元素 html 的字体大小倍数;vw 是视口宽度百分之几,vh 是视口高度;vmax/vmin 取视口宽高中的大/小值。颜色 rgba() 在 RGB 上加不透明度,取值 0–1,越大越不透明,1 完全不透明;hsl() 是色相、饱和度、亮度;hsla() 再多一个不透明度。调试:改 html 字号看 rem,缩放窗口看 vw/vh,调 rgba 的 a 看透明。易错点:rem 不是相对父元素;vw 与父元素宽度无关;rgba 的 a 不是颜色。正确术语要记:required、autofocus、autocomplete、pattern、novalidate、datalist、datetime-local、rem、vw/vh/vmax/vmin、rgba/hsl/hsla。

课堂画面 ​

课堂画面 1

课堂画面 2

课堂画面 3

课堂画面 4

课堂画面 5

课堂画面 6

代码示例 ​

示例一:层级(兄弟)选择器 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>层级选择器</title>
<style>
  .wrapper { width: 800px; }
  .wrapper .item { padding: 10px; background-color: #ccc; margin-bottom: 6px; }
  .active { background-color: #ff0; }

  /* 相邻兄弟选择器:紧跟在 .active 后面、且是 p 的那一个兄弟 */
  .active + p { background-color: #900; color: #fff; }

  /* 通用兄弟选择器:.active 后面所有的 p 兄弟 */
  /* .active ~ p { background-color: #900; color: #fff; } */

  /* 典型应用:导航分割线,一行 A 后面紧跟的 A 才加左边框 */
  .nav { width: 800px; margin-bottom: 20px; }
  .nav a { color: #333; margin: 0 15px; text-decoration: none; }
  .nav a + a { border-left: 1px solid #999; padding-left: 20px; }
  /* .nav a ~ a { border-left: 1px solid #999; padding-left: 20px; } */
</style>
</head>
<body>

<div class="nav">
  <a href="#">首页</a>
  <a href="#">商品</a>
  <a href="#">关于</a>
  <a href="#">联系</a>
</div>

<div class="wrapper">
  <div class="item">中文文字(div)</div>
  <p class="item">hello p</p>
  <div class="item active">我是 active(div)</div>
  <p class="item">hello p</p>
  <div class="item">中文文字(div)</div>
  <p class="item">hello p</p>
</div>

</body>
</html>

要点解释

  • .active + p:先找到 .active,再找它紧邻的、后面的兄弟元素,且该兄弟必须是 p。中间隔了别的元素就选不中(如把 p 换成 div 则一个都选不上)。
  • .active ~ p:先找到 .active,再找它后面所有的 p 兄弟,不要求紧邻。
  • 两种兄弟选择器都只向后找,不向前找,所以第一个兄弟永远不会被选中——这正是 .nav a + a 能一步到位给"除第一个以外"的导航加分割线的原因,不用再单独给第一个加类名去掉。
  • 易错点:+ 和 ~ 两边通常加空格(加不加效果一样,但可读性更好);~ 会让后面的元素被重复选中,但样式只设置一遍,无所谓。
  • 易错点:兄弟关系只看同一个父元素下的平级元素,不是后代。

示例二:属性选择器 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>属性选择器</title>
<style>
  img { width: 200px; }
  p { width: 1000px; background-color: #ccc; }

  /* 1. 只要写了 title 属性就选中(不管值是什么) */
  [title] { border: 2px solid #900; }

  /* 2. 属性值精确等于 */
  /* [title="高考乐"] { border: 5px solid blue; } */

  /* 3. 属性值以“高”开头 */
  /* [title^="高"] { border: 5px solid blue; } */

  /* 4. 属性值以“乐”结尾 */
  /* [title$="乐"] { border: 5px solid blue; } */

  /* 5. 属性值中包含“乐”(开头、结尾、中间都算) */
  /* [title*="乐"] { border: 5px solid blue; } */

  /* 交集写法:只选 img 且带 title 的,属性选择器写在后面 */
  /* img[title] { border: 2px solid #900; } */
</style>
</head>
<body>

<div class="wrapper">
  <!-- src 请换成你自己本地的图片路径 -->
  <img src="./image/eage001.jpg" alt="hello">
  <img src="./image/eage001.jpg" alt="hello world" title="高考乐">
  <img src="./image/eage001.jpg" alt="how are you" title="高启强">
  <img src="./image/eage001.jpg" alt="where" title="老头乐">
  <img src="./image/eage001.jpg" alt="what" title="乐极生悲">
  <img src="./image/eage001.jpg" alt="hello" title="hello">

  <p>段落</p>
  <p title="高考乐">段落</p>
  <p title="段落">段落</p>
</div>

</body>
</html>

要点解释

  • 语法核心就是中括号:[attr] 选中具有该属性的元素,不挑标签名,img 和 p 只要有 title 都会被选中。
  • 五种写法要记牢:[attr]、[attr="val"]、[attr^="val"](以…开头)、[attr$="val"](以…结尾)、[attr*="val"](包含)。^、$、* 都写在等号前面,这是语法,没有为什么。
  • 易错点:属性选择器可以单独使用,也可以和其他选择器交集组合;组合时按惯例把它写在后面(和伪类一样),如 img[title]。
  • 易错点:[title] 和 img[title] 结果不同,前者会连下面带 title 的 p 一起选中;想要精确就加标签名或类名。
  • 课上补充:[attr~="val"]、[attr|="val"] 实际几乎用不到,掌握上面 5 个即可。

示例三::focus、:target、:lang 伪类 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>动态伪类 / 目标伪类 / 语言伪类</title>
<style>
  body { margin: 0; padding-top: 60px; }

  /* ---- 动态伪类 :focus ---- */
  input, textarea {
    display: block;
    width: 400px;
    padding: 10px;
    margin-top: 10px;
    border: 1px solid #999;
    outline: none;          /* 去掉浏览器自带的焦点轮廓线 */
  }
  input:focus, textarea:focus { border: 2px solid red; }

  /* ---- 目标伪类 :target ---- */
  nav { position: fixed; top: 0; left: 0; right: 0; line-height: 40px; background-color: #ccc; }
  nav a { margin-right: 10px; }

  .section { height: 600px; border-top: 2px dashed #999; text-align: center; line-height: 600px; }

  /* 选中 URL 锚点当前对应的那个元素 */
  :target { background-color: #900; color: #fff; font-size: 80px; }
  /* 交集写法:.section:target { background-color: #900; } */

  /* ---- 语言伪类 :lang ---- */
  /* div:lang(en) 会选中语言“含义”为 en 的元素(含继承) */
  div:lang(en) { border: 2px solid #900; }
  /* 对比:div[lang="en"] 只选中自己写了 lang="en" 的元素 */
</style>
</head>
<body>

<input type="text" placeholder="点我试试 / 按 Tab 键切换">
<textarea placeholder="文本域也能获取焦点"></textarea>

<nav>
  <a href="#p01">第一部分</a>
  <a href="#p02">第二部分</a>
  <a href="#p03">第三部分</a>
  <a href="#p04">第四部分</a>
  <a href="#p05">第五部分</a>
</nav>

<div class="section" id="p01">第一部分</div>
<div class="section" id="p02">第二部分</div>
<div class="section" id="p03">第三部分</div>
<div class="section" id="p04">第四部分</div>
<div class="section" id="p05">第五部分</div>

<div class="wrapper" lang="zh-CN">
  <div>我是中文(继承祖先的 zh-CN)</div>
  <div lang="en">I am English</div>
</div>

</body>
</html>

要点解释

  • :focus:表单控件被点击或按 Tab 键切换时触发;div 之类不能获取焦点,写了也没用。浏览器默认会给焦点加一圈轮廓,那是 outline 不是 border,所以要先用 outline: none 去掉它,自定义边框才看得出效果。
  • :target:配合锚点使用,选中"当前 URL 中 #id 所对应的那个元素",元素本身不用写任何特殊类名。地址栏里没有 # 时,一个元素也选不中,这是正常现象。
  • 易错点::target 和 a 标签的 target 属性、form 的 target 属性没有任何关系,只是重名。
  • :lang(zh-CN) 与 [lang="zh-CN"] 的经典区别:[lang="zh-CN"] 只看元素自身有没有写这个属性,不继承;:lang(zh-CN) 看的是语言"含义",子元素没写会继承祖先的语言设置,因此会选中一大片元素。
  • 易错点:伪类、属性选择器与其他选择器做交集组合时,习惯上写在后面(如 .section:target、input:focus)。

常见错误 ​

  1. 现象:用 A + A 做导航分割线,结果第一个导航也被加上边框。→ 原因:误以为 + 会选中“每个 A 自身”。→ 修法:明确 + 选的是“前一个选择器匹配元素后面紧邻的兄弟”,第一个 A 前面没有兄弟,自然不会命中;先检查实际选中范围再加样式。

  2. 现象:写 .item + div 想选后面的兄弟,结果一个都没选上。→ 原因:+ 要求“紧邻”且后一个选择器必须匹配,中间隔了其他元素或标签/类名不匹配都会失败。→ 修法:确认相邻关系与后一个选择器的匹配条件;需要选后面所有匹配兄弟时改用 ~。

  3. 现象:属性选择器单独使用时被质疑“必须配合标签或类名”。→ 原因:把“可以组合”误当成“必须组合”。→ 修法:属性选择器可单独用;需要精确限定时再与标签、类、伪类交集组合,并通常写在其他选择器后面。

  4. 现象:写 img[title] 却把带 title 的 p 也选进来,或反过来漏选。→ 原因:没有区分“只写属性选择器”和“与标签交集”的选中范围。→ 修法:需要只选图片就写 img[title];需要不限标签就只写 [title],先用边框验证再写正式样式。

  5. 现象:给 div 写 :focus 没效果,误以为选择器写错。→ 原因:普通 div 默认不可聚焦,:focus 没有实际触发条件。→ 修法:用于 input、textarea 等可聚焦表单控件;需要验证时用鼠标点击和 Tab 键分别测试,并处理默认 outline。

  6. 现象:把 :target 与 a[target]、form[target] 混为一谈。→ 原因:只看到同名英文,忽略上下文语义完全不同。→ 修法::target 只与 URL 锚点对应的当前目标元素有关;不要拿 target 属性经验套用。

  7. 现象:用 [lang="zh-CN"] 与 :lang(zh-CN) 得到不同结果,误判其中一个失效。→ 原因:前者看元素自身是否写了该属性,后者看语言语义并考虑继承。→ 修法:需要“自身写了属性”用属性选择器;需要“语言环境匹配”用 :lang(),并用父子元素对比验证。

练习 ​

  1. 写一个横向导航,用相邻兄弟选择器只给“除第一个以外”的导航项加左侧分割线;再改成通用兄弟选择器,观察选中范围差异,并说明为什么最终视觉效果仍可成立。

  2. 准备若干 img 和 p,分别写出:具有 title 的图片、title 以“高”开头的元素、title 包含“乐”的元素、title 以“乐”结尾的图片、title 精确等于“高考乐”的图片。要求至少两题不能误选 p。

  3. 写一个包含 input 和 textarea 的表单,实现聚焦时边框变红加粗,同时去掉浏览器默认焦点轮廓;用鼠标点击和 Tab 键各验证一次。

  4. 写 5 个 section 锚点区块和固定顶部导航,使用 :target 给当前锚点区块加高亮;再写一个 .section:target 的交集版本,比较两者选中范围。

  5. 用同一组父子元素分别测试 [lang="zh-CN"] 和 :lang(zh-CN),记录被选中的元素,并用一句话说明两者差异。

原视频对照 ​

#视频时长
1回顾13:29
2层级选择器21:03
3属性选择器15:57
4动态伪类选择器03:04
5目标伪类选择器06:32
6语言伪类选择器05:49

小结 ​

  1. 选择器分类可以重排,但判断标准仍是“先看选中谁,再看样式写给谁”。

  2. 兄弟选择器的高频价值在“除第一个外”的批量处理,尤其适合分割线、间距这类场景。

  3. 属性选择器既能独立使用,也能与其他选择器交集组合;组合时优先放在后面,避免选中范围失控。

  4. 动态伪类要建立在可交互、可聚焦的元素上,普通容器写 :focus 往往没有实际意义。

  5. :target 必须结合 URL 锚点理解,不能与同名 HTML 属性混用经验。

  6. :lang() 与 [lang] 的差异本质是“语义继承”与“自身属性书写”的差异。

  7. 兼容性别死记硬背,现代项目中先保证选择器语义正确、范围可验证,再考虑工具化兼容处理。