本节摘要:基础选择器是 CSS 瞄准系统的第一课——元素选择器按标签名点名,类选择器按类名认人,ID 选择器锁定页面唯一目标,通用选择器一网打尽。本节还讲清"逗号是或、连写是与"这条最易混淆的语法,并动手实践一套可维护的类命名方法。
完成本节后,你将能够:使用四种基础选择器定位页面元素;理解类选择器和 ID 选择器的区别与各自的使用场景;掌握选择器的分组和链式写法;用一套命名约定写出可维护的类名。
元素选择器是最直觉的选择方式——直接写 HTML 标签名,就能选中页面中所有该类型的元素。
p { color: #555; line-height: 1.6; } h1 { font-size: 28px; color: #1565C0; } a { text-decoration: none; color: #1976D2; }
元素选择器的作用范围是全局的——上面的 p 规则会选中页面里的每一个段落。这在设置全局基础样式时非常有用,比如统一字体、行高和文字颜色。但如果你只想让某几个段落变红,元素选择器就太"大水漫灌"了,需要用类选择器来精确控制。
元素选择器还有一个容易被忽略的特性:它会匹配"未来才会出现的元素"。JavaScript 稍后动态插入的 <p>,一样会被 p { ... } 命中。所以全局基础样式放元素选择器里很合适——不管内容怎么变,基调不变。
四种基础选择器的定位方式
类选择器通过 HTML 元素的 class 属性来定位元素,以点号 . 开头。它是日常开发中使用频率最高的选择器,没有之一。
.highlight { background-color: #FFF9C4; padding: 4px 8px; } .text-danger { color: #D32F2F; }
<p>这段文字没有特殊样式。</p> <p class="highlight">这段文字有黄色高亮背景。</p> <p class="text-danger">这段文字是红色的,表示警告。</p>
类选择器有两个关键特性。第一,同一个类名可以在多个元素上重复使用——上面两个段落可以同时拥有 highlight 类。第二,一个元素可以同时拥有多个类名,用空格分隔:
<div class="card featured">这个卡片同时拥有 card 和 featured 两个类的样式</div>
.card { border: 1px solid #ddd; border-radius: 8px; padding: 16px; } .featured { border-color: #FFC107; box-shadow: 0 2px 8px rgba(255, 193, 7, 0.3); }
这种"一个元素叠加多个类"的模式是现代 CSS 开发的基础思路,它让样式可以像积木一样组合:card 负责"我是一张卡片",featured 负责"我被精选了",两者互不干涉、各管一段。后面学到优先级时你会看到,.card.featured(中间无空格)还能进一步选中"同时拥有这两个类"的元素——一字之差,含义完全不同。
💡 命名建议:类名应该描述"是什么"而不是"长什么样"。用
.text-danger比用.red-text更好,因为如果将来需要把警告色从红色改成橙色,类名不会变得名不副实。同理,.sidebar比.left-column稳妥——侧边栏哪天挪到右边,前者依然成立。
ID 选择器通过 HTML 元素的 id 属性来定位元素,以井号 # 开头。与类选择器最大的不同是:同一个 ID 在页面中应该是唯一的。
#main-header { background-color: #1565C0; color: white; padding: 16px 24px; } #sidebar { width: 280px; float: right; }
<header id="main-header"> <h1>网站标题</h1> </header> <div id="sidebar"> <p>侧边栏内容</p> </div>
ID 选择器的优先级比类选择器高得多(本章末节会详细计算),所以它常被误用为"强制覆盖"的手段。但在现代 CSS 开发中,ID 选择器的使用频率正在下降,原因有两层:一是唯一性限制了样式的复用能力——页面里只有一个元素能用它;二是它的高优先级会破坏层叠体系的可预测性,一旦用 ID 写了样式,后面想覆盖它就得写更长的选择器或动用 !important。大多数情况下,用类选择器就能解决问题,把 ID 留给锚点跳转和 JavaScript 取元素。
| 特性 | 类选择器 .class |
ID 选择器 #id |
|---|---|---|
| 语法前缀 | . |
# |
| 复用性 | 可被多个元素使用 | 页面中应唯一 |
| 多值 | 元素可拥有多个类 | 元素只能有一个 ID |
| 优先级 | 较低(0,0,1,0) | 较高(0,1,0,0) |
| 典型用途 | 通用样式类 | 页面唯一区块、锚点 |
通用选择器用星号 * 表示,匹配页面上的所有元素。它最常见的用途是全局重置默认样式。
* { margin: 0; padding: 0; box-sizing: border-box; }
这三行代码几乎是每个现代 CSS 文件的开场白。它清除了浏览器为各种元素设置的默认外边距和内边距,并统一了盒模型计算方式——第三行的意义要到第 3 章才能完全展开,现在先照写。
通用选择器也可以与其他选择器组合使用。例如 *.warning 等价于 .warning,.container > * 选中 .container 的所有直接子元素。
/* 选中 .container 内所有直接子元素,实现"相邻元素统一间距" */ .container > * + * { margin-top: 16px; }
这个"相邻兄弟"技巧用 * + * 实现了"除第一个子元素外,每个元素上方都添加间距"的效果——比逐个给子元素加 margin-top 巧妙得多。它的原理要用到下一节的组合选择器,这里先当个预告:A + B 选中"紧跟在 A 后面的 B",于是 * + * 就是"所有跟着某个兄弟的元素",第一个孩子前面没有兄弟,自然被排除。
当你发现多条规则有相同的声明时,可以用逗号把多个选择器写在一起,避免重复代码:
h1, h2, h3 { font-family: "Georgia", serif; color: #333; }
反过来,同一个选择器需要设置多组属性时,不要写成多个规则块——把它们合并到一个花括号里:
/* 不好的写法:两段代码管一个元素 */ .title { color: #1565C0; } .title { font-size: 24px; } /* 好的写法 */ .title { color: #1565C0; font-size: 24px; }
链式写法可以把多个选择器条件"与"在一起。比如 .card.featured 只选中同时拥有 card 和 featured 两个类的元素:
.card.featured { border: 2px solid gold; }
逗号与连写是一组必须分清的语法:
/* .card, .featured —— 或:两类元素全部生效 */ /* .card.featured —— 与:必须同时具备两个类 */
一个稍复杂的组合把两者放在一起看:
/* 选中:同时有 card 和 featured 类的元素,或者有 special 类的元素 */ .card.featured, .special { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); }
⚠️ 注意区分:逗号分隔是"或"的关系(满足任一选择器就生效),无分隔符的链式是"与"的关系(必须同时满足所有条件)。初学者最常犯的错是把
.a .b(后代,空格)、.a.b(与,无空格)、.a, .b(或,逗号)三种写法弄混——一个空格的差别,匹配结果天差地别。
把本节知识用起来,为贯穿全教程的个人主页搭内容骨架。先写结构:
<body> <header class="site-header"> <h1 class="site-title">阿明的个人主页</h1> <p class="site-subtitle">前端学习笔记与作品</p> </header> <main class="posts"> <article class="post"> <h2 class="post-title">我学会的第一条 CSS</h2> <p class="post-excerpt">从 color: red 开始……</p> </article> <article class="post featured"> <h2 class="post-title">Flexbox 初体验</h2> <p class="post-excerpt">三个属性搞定导航栏……</p> </article> </main> <footer class="site-footer"> <p>用 HTML 和 CSS 手写而成</p> </footer> </body>
再写样式,刻意用上本节的每一种选择器:
/* 元素选择器:全局基调 */ body { font-family: "Microsoft YaHei", sans-serif; color: #333; line-height: 1.6; } /* 类选择器:区块布局 */ .site-header { background: #1565C0; color: #fff; padding: 24px; } .posts { padding: 24px; } .site-footer { color: #757575; font-size: 14px; text-align: center; padding: 16px; } /* 链式选择器:精选文章特殊化 */ .post.featured { background: #FFF9C4; border-left: 4px solid #FFB300; padding: 12px 16px; } /* 分组选择器:多个标题共用一套字体 */ .post-title, .site-subtitle { font-weight: normal; letter-spacing: 0.5px; }
保存刷新后对照检查:第二篇文章有黄色背景(.post.featured 生效),页脚变灰变小,标题统一了字重。然后做两个破坏性实验:把 .post.featured 误写成 .post .featured(加空格),精选样式失效——因为 featured 不是 post 的后代而是同一元素;再把 HTML 里第二篇的 class="post featured" 改成 class="post",样式同样失效——链式选择要求两个类同时在场。两个实验分别验证了"或/与/后代"三兄弟的边界。
样式写着写着类名就乱了:red-box、box2、box2-new、final-box……这是所有初学者的必经之路。这里给出一套够用的最小命名约定,思路叫"块_元素_修饰符":块是独立组件(post),元素是块的组成部分(post-title),修饰符是状态变体(post featured 直接用第二个类表示)。
对照着重构上面的例子:site-header 是块;如果头部里还有 Logo 和导航,就写成 site-header-logo、site-header-nav;精选状态继续用 post featured 组合表示。三条规则:全小写加连字符、不用缩写拼气质(btn 可以,b 不行)、修饰用额外类而非新名字。命名约定的价值在第 4 章布局组件化时会真正显现——组件可以复制到任何页面而样式不散架。

图:四种基础选择器的语法、作用和权重对比
问:一个元素能同时被元素选择器和类选择器命中吗? 能,而且这是常态。一个 <p class="highlight"> 同时吃着 p 规则的全局样式和 .highlight 规则的特殊样式,两条规则互不干扰地叠加在它身上;只有当两条规则改同一个属性时才需要分胜负,裁决规则在本章末节。这种"多来源叠加"正是 CSS 名字里"层叠"的日常形态。
问:类名可以用中文吗?数字开头呢? 技术上,中文类名在现代浏览器里能工作,但工具链、团队协作、代码检索都会遇到别扭,工程惯例仍是英文。数字开头则真的不行——CSS 标识符不能以数字开头,.2col 是非法选择器,写成 .col-2 即可。下划线和连字符都合法,团队里统一一种就好。
问:什么时候该用 ID 选择器? 默认答案:样式里尽量不用,把 ID 留给锚点定位和脚本取元素。例外是那些"全页面真的只有一个"且不需要被覆盖样式的元素,比如 #app 根容器的少量全局设定。哪怕拿不准,先用类也不会错——类选择器的低优先级给了你日后覆盖的余地。
问:通用选择器性能很差吗? 这是一个流传很广的过时结论。现代浏览器引擎处理 * 重置毫无压力,那条全局重置代码每天在亿万页面上运行。真正影响匹配性能的是长链后代选择器配大而深的 DOM,与是否用星号无关。放心写你的重置。
选择器的功力有一半其实在 HTML 那一侧。回看个人主页的结构:site-header、post-title、post featured——这些类名不是给 CSS 的"暗号",而是对内容语义的声明。HTML 写得语义清晰,CSS 就能用最短的选择器精准命中;HTML 满屏无意义的嵌套和万能类名,CSS 就被迫写又长又脆的选择器去"按位置捞人"。
一个实用的自检方法:假想你三个月后要给"所有精选文章的标题"换颜色。如果答案是"改一个类的样式,五分钟搞定",说明结构健康;如果答案是"找到那些页面挨个改"或者"写一个四层嵌套的选择器赌它能命中",说明结构在给样式埋雷。选择器的简洁程度,是 HTML 语义质量最灵敏的试纸。
类名的数量同样值得克制。一个元素的类超过三四个,往往说明职责划分出了问题——样式没有按"结构、外观、状态"分层,而是每个小效果都起一个新类。理想状态是每个类只表达一件事,元素按需组合,像拼装零件而不是各造各的轮子。
card featured)是样式积木化的基础。下一节给选择器装上"关系透镜"——按 DOM 树的父子兄弟关系、按 HTML 属性的特征来锁定目标,定位精度再上一个台阶。