CSS选择器是连接HTML结构与样式规则的桥梁。每写一条样式,浏览器都要先通过选择器判断这条规则应用到哪些元素上,再去渲染。很多初学者只会用类选择器一把梭,或者到处复制id,写出来的样式表越堆越乱,优先级冲突频出。想把CSS基本功打扎实,第一步就是把基本选择器吃透,搞清楚每种选择器适合什么场景,优先级如何计算,哪些写法该避免。

基本选择器有哪些类型
CSS规范中定义了多种选择器,但最基础的只有五种:通配选择器、元素选择器、类选择器、ID选择器和属性选择器。它们是所有复合选择器的 building block,后代选择器、子代选择器、伪类选择器等都是建立在这些基础之上的。
通配选择器用*表示,匹配页面上的所有元素,最常见的用途是做全局重置:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}元素选择器直接用标签名,例如p匹配所有段落,a匹配所有链接。它优先级低、复用性强,适合设置某一类元素的全局默认样式。类选择器以点号开头,比如.btn,任何元素只要加上class="btn"就会被匹配到,这是日常开发中使用频率最高的选择器。
ID选择器以井号开头,例如#header,匹配id属性等于该值的唯一元素。属性选择器则通过方括号语法匹配元素的属性,例如[type="text"]匹配所有文本输入框,在没有合适类名时非常方便。下面这个例子把五种选择器都用上了:
<style>
* { margin: 0; }
p { line-height: 1.6; }
.card { border: 1px solid #ddd; padding: 16px; }
#main-title { font-size: 24px; }
input[type="text"] { border: 1px solid #ccc; }
</style>
<div class="card">
<h1 id="main-title">标题</h1>
<p>这是一段正文内容</p>
<input type="text" placeholder="请输入">
</div>优先级是如何计算的
写CSS迟早会遇到这样的困惑:明明给元素设置了颜色,页面上的样式却没生效,或者被别的规则覆盖了。这背后就是优先级机制在起作用。浏览器按照三组数值来计算权重:ID选择器个数、类选择器(含属性选择器、伪类)个数、元素选择器(含伪元素)个数,依次比较。
例如#header .nav li的权重是1个ID、1个类、1个元素,记为(1,1,1);而.nav li是(0,1,1)。前者数值更高,所以优先生效。通配选择器*的权重为0,也就是说*和div同时设置样式时,元素选择器会赢。当权重完全相同时,写在后面的规则覆盖前面的,这就是常说的后来居上原则。
还有一个特殊存在是行内样式,也就是直接写在HTML标签style属性里的样式,它的优先级高于所有选择器。而!important则凌驾于行内样式之上。实际开发中应尽量避免使用!important,因为它会打破正常的层叠规则,一旦用上就很难再覆盖,日积月累会让样式表变得不可维护。正确做法是控制好选择器的层级深度,保持权重简洁。
属性选择器的进阶用法
属性选择器比很多人想象的强大,它不仅能精确匹配属性值,还支持模糊匹配。掌握这些用法,可以在没有类名配合的情况下精准定位元素,减少HTML中的冗余class。
[href]匹配所有带href属性的元素;[href^="https"]匹配值以https开头的;[href$=".pdf"]匹配以.pdf结尾的;[class*="btn"]则匹配class值中包含btn字样的元素。来看一个实用例子,给外部链接自动加上小图标:
/* 匹配所有以 https 开头且不以本站域名结尾的链接 */
a[href^="https://"]:not([href$="ipipp.com"])::after {
content: " ↗";
}
/* 匹配所有 PDF 下载链接 */
a[href$=".pdf"]::before {
content: "[PDF] ";
}需要注意的是,[class*="btn"]这种包含匹配是字符串层面的,btn-primary和mybtn都会命中,有时会产生误伤。如果只是想匹配class列表中的某一项,更稳妥的方式是使用.btn类选择器,或者用波浪线语法的[class~="btn"],它按空格分隔class值后再精确匹配。
常见误用与最佳实践
第一个常见问题是ID选择器滥用。ID权重太高,一旦用它写了样式,后续想覆盖就只能写更高的权重或者祭出!important,整个样式表的层叠体系会被逐渐破坏。业界主流做法是ID留给JavaScript定位元素和页面锚点使用,样式一律走类选择器。
第二个问题是选择器嵌套过深。类似.page .content .list .item .title a这种写法权重臃肿,与HTML结构强耦合,模板稍一调整样式就全部失效,浏览器匹配的开销也更大。建议单个选择器不超过三层,尽量做到类名即语义,例如.list-item-title,这样既降低权重又减少对DOM层级的依赖。
第三是通配选择器的性能顾虑。*本身确实会遍历所有元素,但现代浏览器的样式匹配引擎已经高度优化,全局重置中的*并不会造成明显性能问题。真正要警惕的是把*与后代选择器组合,例如div * .title这种写法,匹配范围难以预估,应尽量避免。
总结一下:元素选择器负责全局默认值,类选择器承担主要样式职责,ID尽量不参与样式,属性选择器用于无类名可用的场景。把这些原则落实到位,你的CSS会明显变得更整洁、更易维护,也为后续学习伪类、伪元素和组合选择器打下良好基础。