1. 先搞清楚选择器在这行里的真实分量
写CSS最让人崩溃的瞬间是什么?不是布局调不动,也不是动画卡顿,而是你明明写了一大段样式,页面却一点反应都没有。去翻代码,选择器写得也没错,浏览器控制台也没有报错,但样式就是死活不生效。这种时候,八成问题就出在CSS选择器上——要么优先级算错了,要么元素根本没被选中,要么被后面的规则覆盖了。
很多小白前端一听到“选择器”三个字就开始慌,觉得它是CSS里面最难啃的一块骨头。其实你完全不用慌。选择器说到底就一句话:告诉浏览器,你这条样式规则到底要作用于页面上的哪些元素。它就像点名,点到了谁,谁就执行对应的样式。
但为什么这么简单的事,会让那么多人绕晕?因为选择器的种类实在太多了,光是组合起来的花样就够写一篇长文。而且它背后还牵着一套优先级规则,谁权重高谁说了算,这套规则在项目一大之后就会频繁跟你过招。
这篇内容就把CSS选择器从基础到进阶全部捋一遍:元素选择器、类选择器、ID选择器、属性选择器、伪类和伪元素,还有组合关系选择器,以及最常见的优先级坑。每个部分我都会写上实际的代码示例,附上我在真实项目中踩过的坑和排查方法。不管你是刚入行的前端小白,还是写了几年但因为一直在用框架、很少手写原生CSS的开发者,这篇都能帮你把选择器这块的知识补齐。
我把选择器按功能做了一个总览分类,你可以先有个整体印象:
| 分类 | 代表选择器 | 作用 |
|---|---|---|
| 基础选择器 | div、.class、#id、* |
按标签、类名、ID、全部元素选择 |
| 属性选择器 | [type="text"]、[data-*] |
按元素属性及其值选择 |
| 关系选择器 | A B、A > B、A + B、A ~ B |
按元素之间的结构关系选择 |
| 伪类选择器 | :hover、:nth-child()、:not() |
按状态、位置、逻辑条件选择 |
| 伪元素 | ::before、::after |
选中元素的特定部分或生成内容 |
真正理解了这张表,你再看任何复杂的CSS代码,都能一眼拆出来别人用了哪些选择器、为什么要这样写。后面每一个分类我都会展开讲,并且告诉你哪些用法在实际开发里面真正高频,哪些看着炫酷但实际上很少用得上。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础选择器:先把“选谁”这件事做对
基础选择器是所有选择器的底子,后面那些复杂的选择器都是在这个基础上做组合和变形。你如果只想记住一部分,那就把基础选择器彻底吃透,因为日常开发中80%以上的场景靠它就能解决。
2.1 元素(标签)选择器
元素选择器就是直接用HTML标签名来选中元素,比如:
css复制p {
color: #333;
line-height: 1.8;
}
这样页面上所有的<p>标签都会变成灰色文字、加大行高。它的特点是作用范围最广,但精确度最低。你用得越多,页面里同类标签被“一刀切”的风险就越大。
实际项目中我建议元素选择器只用来做两件事:一是重置或者定义全局的基础样式,比如给body设置字体和背景色;二是配合类选择器做局部覆盖的时候使用。不要用元素选择器去给某个特定区域的样式做定制,否则后面一定会出现“我想改这里结果别的地方也变了”的灵异事件。
2.2 类选择器:前端样式的主力军
类选择器用英文点号开头,比如:
css复制.card {
border: 1px solid #e5e5e5;
border-radius: 8px;
padding: 16px;
}
然后在HTML里用class="card"来引用。你可以给同一个元素挂多个类名,比如class="card active",这样.card定义结构样式、.active定义状态样式,两者互不干扰,这也是类选择器的最大优势——组合和复用非常灵活。
类选择器是CSS里用得最频繁的,几乎所有组件库的样式方案都建立在类选择器之上。这里有个我踩过的坑:项目里有个同学喜欢用“语义化类名”,每个类名都起了七八个单词那么长,结果HTML又长又难读,CSS里到处都是这些长类名。后来我们统一采用短语义加模块命名的方式,比如.login-form、.login-form__title这种,代码可读性才上来。类名这件事,后面我在第六部分再细说。
2.3 ID选择器:能用,但要克制
ID选择器用井号开头:
css复制#header {
height: 64px;
}
HTML里id="header"对应。它的问题在于,页面中一个ID只能使用一次,这决定了ID选择器天然不具备复用性。而且ID选择器的优先级非常高,一把就压过类选择器,这会导致覆盖样式非常困难。你要想在一个使用ID选择器写死的样式上做微调,就只能再上更重的优先级手段,很容易把自己逼进死角。
我个人的习惯是:ID选择器只用来做两件事。一是锚点定位,比如#article作为页面内跳转目标;二是给JavaScript提供钩子,处理交互逻辑。至于样式,尽量别碰ID。因为CSS类选择器的优先级相对好控制,组件用类名来定义样式,后续不管怎么迭代,改动成本都低。
