在编写页面样式时,:first-child是CSS3里非常基础的结构性伪类选择器,它的作用是选中那些在其父元素中处于第一个子节点位置的元素。理解它的匹配机制,能避免很多“明明写了规则却没生效”的困惑。

一、:first-child的基本匹配规则
:first-child伪类并不关心被选中的元素是什么标签,它只关心该元素在其父元素的所有子节点中是否排在第一位。只要某个元素是父容器的第一个子元素,不论它是<div>、<p>还是<li>,都可以被:first-child命中。这一点和很多人的直觉不同,不少人以为它是“某类标签中的第一个”,其实并非如此。
从规范层面看,:first-child等价于:nth-child(1)。浏览器在解析时,会先找到元素的父节点,再检查该元素是否为父节点的子元素列表中的索引为1的节点(索引从1开始)。如果前面存在任何元素节点(包括其他标签),哪怕只差一个,匹配就会失败。下面的代码展示了最基本的用法:
<!DOCTYPE html>
<html>
<head>
<style>
p:first-child {
color: red;
font-weight: bold;
}
</style>
</head>
<body>
<p>我是父元素body的第一个子元素,我会变红</p>
<p>我是第二个p,不会匹配:first-child</p>
</body>
</html>
在上面例子中,第一个<p>位于<body>的子节点首位,因此被选中并应用红色加粗样式;第二个<p>由于不是首位,规则对其无效。这种写法常用于去掉列表第一项的上边框,或为首段文字设置首行缩进以外的特殊样式。
二、常见的匹配失效场景
开发者经常遇到:first-child“不灵”的情况,绝大多数原因都是在目标元素前面存在了别的节点。比如父容器开头放了一个<h1>标题,后面才跟着若干<p>,此时写p:first-child就永远选不中任何<p>,因为排第一的是<h1>而不是<p>。
另一个容易被忽略的点是空白文本节点与注释。在HTML解析中,标签之间的换行和空格通常不会生成独立的元素节点,因此一般不会影响:first-child;但如果在目标元素前显式写了另一个标签或脚本节点,就会实实在在挤占第一位。看下面这段容易出错的代码:
<div class="box"> <h2>标题</h2> <p>第一段</p> <p>第二段</p> </div>
此时若写css规则 p:first-child { color: blue; },第一段文字不会变蓝,因为.div.box的第一个子元素是<h2>,<p>排在后面。要选中第一个<p>,应使用 p:first-of-type,它会在同类型标签中挑第一个,而不限制整体位置。
三、与:first-of-type的对比及实践建议
:first-of-type和:first-child的核心差异在于匹配维度。:first-child看的是“父项下绝对第一”,:first-of-type看的是“父项下某标签类型的第一”。在混合标签的容器里,后者往往更实用。我们可以用一个表格理清区别:
| 选择器 | 匹配条件 | 适用场景 |
|---|---|---|
| :first-child | 父元素的首个子节点 | 容器开头固定为某元素,或纯同类列表 |
| :first-of-type | 父元素中同标签类型的首个 | 容器内有多种标签,只想选某类首个 |
在真实项目中,如果列表由后端渲染且前面可能被插入提示栏,就不要用:first-child去清除首项间距,否则提示栏出现后样式会错乱。更稳妥的写法是使用:first-of-type,或在首项上直接加辅助类名。下面给出一个兼容思路的示例:
/* 不推荐:容易受前置节点影响 */
.item:first-child { margin-top: 0; }
/* 推荐:明确同类首个 */
.item:first-of-type { margin-top: 0; }
/* 或者由JS/模板给首项加类 */
.item-first { margin-top: 0; }
总体来看,:first-child本身并不复杂,难的是在动态结构里预判它的命中结果。写样式前先在DOM树里确认目标元素的真实排位,比盲目调试更高效。
四、在组合选择器中的注意事项
当:first-child与其他选择器连写时,顺序和语义都需要留意。比如 .list > li:first-child 表示“类为list的元素的直接子元素中,且是li并且排第一”。如果写成 li:first-child .inner,则是选中那些作为父项首子的li里面的.inner子元素,两者含义完全不同。
此外,在旧版IE中结构性伪类支持不全,但现代浏览器均已良好支持:first-child。若项目还需兼顾极老环境,可用额外类名兜底。以下代码演示了组合使用方式:
<ul class="nav">
<li>首页</li>
<li>文章</li>
<li>关于</li>
</ul>
<style>
.nav > li:first-child {
border-left: none;
}
</style>
这里利用:first-child去掉导航首个项的左边框,实现视觉上的对齐。只要.nav下第一个子节点确实是<li>,规则就会稳定生效;若前面被插了别的元素,就要回过头检查DOM结构而非怀疑选择器写错。
CSS3first_child选择器修改时间:2026-08-03 08:33:29