:nth-last-child(n) 本身不能查询数量,但配合:first-child可精确匹配恰好n个子元素;例如div > span:first-child:nth-last-child(3)仅在span总数为3时生效,单独使用:nth-last-child(3)仅匹配倒数第3个元素。

用 :nth-last-child(n) 判断子元素个数是否等于某值
直接说结论::nth-last-child(n) 本身不能“查询数量”,但可以配合 :first-child 实现“当且仅当有 n 个子元素时生效”的精确匹配。常见错误是只写 :nth-last-child(3),这其实选中的是倒数第 3 个元素(不管总共有几个),不是“总共 3 个”。
正确逻辑是:如果某个元素既是第一个子元素,又是倒数第 n 个子元素,那说明它前面没元素、后面只剩 n−1 个——总数就是 n。
-
div > span:first-child:nth-last-child(3)→ 只有当span恰好有 3 个时才命中第一个span - 再加
, div > span:first-child:nth-last-child(3) ~ span就能同时选中全部 3 个(利用兄弟选择器) - 注意必须限定父容器和子元素类型,否则可能被其他同级元素干扰(比如中间夹了文本节点或注释)
为什么 :nth-child(n) 和 :nth-last-child(n) 单独用都不行
单独用 :nth-child(3) 匹配的是正数第 3 个,:nth-last-child(3) 匹配倒数第 3 个——两者都依赖位置,不反映总数。哪怕父元素只有 1 个子,:nth-last-child(3) 也完全不匹配,但你无法靠“不匹配”来触发样式回退(CSS 没有否定总数的伪类)。
真正可控的切入点只有两个交集点::first-child(唯一性) + :nth-last-child(n)(位置锚点)。缺一不可。
立即学习“前端免费学习笔记(深入)”;
- 如果父元素有 4 个子,
span:first-child:nth-last-child(3)不会匹配任何元素(因为第一个不可能是倒数第 3 个) - 如果父元素有 2 个子,同样不匹配——所以它是严格的“等于 n”,不是“大于等于”或“小于等于”
- IE 不支持
:nth-last-child,如需兼容,得用 JS 动态加 class
实际布局控制:3 列变 2 列再变 1 列的响应式 fallback
纯 CSS 控制列数常依赖 Grid 或 Flex 的 minmax(),但有时需要更确定的“刚好 N 项”行为,比如卡片列表在数据少时避免留白。这时用数量判断比媒体查询更精准。
ul.cards {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
ul.cards > li {
flex: 1 1 calc(33.333% - 0.666rem); /* 默认 3 列 */
}
/* 只有 2 个卡片时 */
ul.cards > li:first-child:nth-last-child(2),
ul.cards > li:first-child:nth-last-child(2) ~ li {
flex-basis: calc(50% - 0.5rem);
}
/* 只有 1 个卡片时 */
ul.cards > li:first-child:nth-last-child(1) {
flex-basis: 100%;
}- 每个规则只影响对应数量的场景,互不干扰
-
flex-basis覆盖默认值,不需要!important - 注意
~ li选择的是后续所有兄弟,所以 2 项时两条规则一起生效,确保两个都设为 50%
容易被忽略的 DOM 结构陷阱
这个技巧对 HTML 结构极其敏感。哪怕父元素里有空格、换行、注释节点,都可能导致 :first-child 失效(因为空白文本节点成了第一个子节点)。
- 写成
<ul><li>A</li><li>B</li></ul>是安全的;<ul>\n<li>A</li>\n<li>B</li>\n</ul>在某些浏览器下可能失效 - 如果子元素类型不统一(比如混有
<div>和<span>),要确保选择器限定准确,例如div > p:first-child:nth-last-child(2)不会误中<span> - 动态插入内容后,不会自动重算伪类匹配——DOM 变了就得靠 JS 触发重排或手动切换 class
真要用纯 CSS 做数量感知,结构干净 + 选择器精确 + 浏览器支持检查,三者缺一不可。


















