主题
层级选择器与属性选择器(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。
课堂画面






代码示例
示例一:层级(兄弟)选择器
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)。
常见错误
现象:用
A + A做导航分割线,结果第一个导航也被加上边框。→ 原因:误以为+会选中“每个 A 自身”。→ 修法:明确+选的是“前一个选择器匹配元素后面紧邻的兄弟”,第一个 A 前面没有兄弟,自然不会命中;先检查实际选中范围再加样式。现象:写
.item + div想选后面的兄弟,结果一个都没选上。→ 原因:+要求“紧邻”且后一个选择器必须匹配,中间隔了其他元素或标签/类名不匹配都会失败。→ 修法:确认相邻关系与后一个选择器的匹配条件;需要选后面所有匹配兄弟时改用~。现象:属性选择器单独使用时被质疑“必须配合标签或类名”。→ 原因:把“可以组合”误当成“必须组合”。→ 修法:属性选择器可单独用;需要精确限定时再与标签、类、伪类交集组合,并通常写在其他选择器后面。
现象:写
img[title]却把带title的p也选进来,或反过来漏选。→ 原因:没有区分“只写属性选择器”和“与标签交集”的选中范围。→ 修法:需要只选图片就写img[title];需要不限标签就只写[title],先用边框验证再写正式样式。现象:给
div写:focus没效果,误以为选择器写错。→ 原因:普通div默认不可聚焦,:focus没有实际触发条件。→ 修法:用于input、textarea等可聚焦表单控件;需要验证时用鼠标点击和 Tab 键分别测试,并处理默认outline。现象:把
:target与a[target]、form[target]混为一谈。→ 原因:只看到同名英文,忽略上下文语义完全不同。→ 修法::target只与 URL 锚点对应的当前目标元素有关;不要拿target属性经验套用。现象:用
[lang="zh-CN"]与:lang(zh-CN)得到不同结果,误判其中一个失效。→ 原因:前者看元素自身是否写了该属性,后者看语言语义并考虑继承。→ 修法:需要“自身写了属性”用属性选择器;需要“语言环境匹配”用:lang(),并用父子元素对比验证。
练习
写一个横向导航,用相邻兄弟选择器只给“除第一个以外”的导航项加左侧分割线;再改成通用兄弟选择器,观察选中范围差异,并说明为什么最终视觉效果仍可成立。
准备若干
img和p,分别写出:具有title的图片、title以“高”开头的元素、title包含“乐”的元素、title以“乐”结尾的图片、title精确等于“高考乐”的图片。要求至少两题不能误选p。写一个包含
input和textarea的表单,实现聚焦时边框变红加粗,同时去掉浏览器默认焦点轮廓;用鼠标点击和 Tab 键各验证一次。写 5 个
section锚点区块和固定顶部导航,使用:target给当前锚点区块加高亮;再写一个.section:target的交集版本,比较两者选中范围。用同一组父子元素分别测试
[lang="zh-CN"]和:lang(zh-CN),记录被选中的元素,并用一句话说明两者差异。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 回顾 | 13:29 |
| 2 | 层级选择器 | 21:03 |
| 3 | 属性选择器 | 15:57 |
| 4 | 动态伪类选择器 | 03:04 |
| 5 | 目标伪类选择器 | 06:32 |
| 6 | 语言伪类选择器 | 05:49 |
小结
选择器分类可以重排,但判断标准仍是“先看选中谁,再看样式写给谁”。
兄弟选择器的高频价值在“除第一个外”的批量处理,尤其适合分割线、间距这类场景。
属性选择器既能独立使用,也能与其他选择器交集组合;组合时优先放在后面,避免选中范围失控。
动态伪类要建立在可交互、可聚焦的元素上,普通容器写
:focus往往没有实际意义。:target必须结合 URL 锚点理解,不能与同名 HTML 属性混用经验。:lang()与[lang]的差异本质是“语义继承”与“自身属性书写”的差异。兼容性别死记硬背,现代项目中先保证选择器语义正确、范围可验证,再考虑工具化兼容处理。