正在加载...

CSS 嵌套

变量给了值名字。calc 等函数算出了结果。Nesting 整理的是使用这些值的选择器:把卡片的标题、按钮和 hover 样式写在 .card 里面,而不是在整份文件里重复父选择器名。

嵌套子选择器

把一条规则写在另一条规则里面。嵌套的 class 或类型选择器会以后代方式接到父选择器上(空格组合器),除非你用 & 另作说明:

Card styles nested under one parent

css
.card {
padding: 1.25rem;
border-radius: 0.75rem;
background: var(--surface, #fff);

.title {
margin: 0 0 0.5rem;
font-size: 1.25rem;
}

.body {
color: var(--muted, #444);
line-height: 1.5;
}
}

浏览器会把它展开成 .card .title 和 .card .body。你得到的仍是普通后代选择器 — nesting 是结构和就近性的语法糖,不是新的匹配模型。

父选择器 &

当嵌套规则必须挂在与父规则同一个元素上时 — 伪类、伪元素,或父元素上的额外 class — 使用 &:

Hover and modifier on the same element

css
.button {
display: inline-flex;
padding: 0.6rem 1.1rem;
border: 0;
border-radius: 0.5rem;
background: var(--brand, #2563eb);
color: #fff;

&:hover {
background: var(--brand-hover, #1d4ed8);
}

&:focus-visible {
outline: 2px solid var(--brand, #2563eb);
outline-offset: 2px;
}

&.is-primary {
background: var(--brand-strong, #1e40af);
}
}

&:hover 就是 .button:hover。&.is-primary 就是 .button.is-primary。没有 & 时,裸写 :hover { } 在原生 CSS nesting 中无效 — & 让附着关系明确。

带 & 的组合器

当你要的是子元素、兄弟或其他显式关系 — 而不是普通的后代空格 — 把组合器写在 & 后面:

Child and adjacent patterns with &

css
.nav {
display: flex;
gap: 0.75rem;

& > .item {
padding: 0.35rem 0.6rem;
}

& > .item + .item {
border-inline-start: 1px solid #ddd;
}

/* same as nesting .item without & — descendant */
.badge {
font-size: 0.75rem;
}
}

& > .item → .nav > .item。不带 & 的嵌套 .badge → .nav .badge。要有意识地选择:无意中嵌出的深层后代是常见的 nesting 坏味道。

把 @media 嵌在组件旁

可以把 @media 这类 at-rule 嵌进样式规则里,让断点紧挨着它们要改的组件:

Responsive tweaks beside the component

css
.hero {
padding: 2rem 1.25rem;

h1 {
font-size: clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
}

@media (min-width: 48rem) {
padding: 3rem 2rem;

h1 {
max-width: 20ch;
}
}
}

展开后,媒体查询仍然包裹属于 .hero(以及 .hero h1)的声明。把它和前面 Modern Toolkit 课里的 token、clamp() 搭配使用 — nesting 只是搬动规则的位置。

嵌套模式速览

📊 原生 nesting 速查

你写 含义 何时用
.card { .title { } } .card .title 为组件下的后代设样式
.btn { &:hover { } } .btn:hover 同一元素上的伪类
.btn { &.big { } } .btn.big 同一元素上的额外 class
.nav { & > a { } } .nav > a 显式子组合器
.box { @media (…) { } } 限定在该规则选择器上的媒体查询 把断点放在组件旁

嵌套保持浅层

两三级通常仍然好读。更深的树会重现 Sass 团队遇到的「选择器金字塔」问题:难 diff、specificity 升高、样式只有塞进一个巨型父级才说得通。优先用清晰的组件根(.card、.nav),嵌套状态和近邻子元素 — 不要嵌整页。

组件打包:tokens + nest + 状态

这一小段把 toolkit 最近三个想法串在一起,而不是重讲 calc 或变量课:

Panel with tokens, nested parts, and a state

css
.panel {
--panel-pad: 1rem;
padding: var(--panel-pad);
border: 1px solid #e5e7eb;
border-radius: 0.75rem;

.heading {
margin: 0 0 0.5rem;
font-weight: 600;
}

.actions {
display: flex;
gap: calc(var(--panel-pad) / 2);
margin-block-start: var(--panel-pad);
}

&.is-compact {
--panel-pad: 0.5rem;
}

@media (max-width: 36rem) {
.actions {
flex-direction: column;
}
}
}

Token 仍是自定义属性;calc 仍在推导间距;nesting 只是把 heading、actions、紧凑状态和小屏微调放在同一处。

自己动手

  1. 把扁平规则 .card {}、.card .title {}、.card .meta {} 改写成 .card 下的 nesting。
  2. 在 .link 上写 &:hover,让只有链接(不是嵌套的 span)变色。
  3. 在 .sidebar 里嵌 @media (min-width: 40rem) 加宽 padding — 在 DevTools 里确认展开后的选择器。
  4. 把误写的嵌套 :hover { }(没有 &)改成 &:hover { },并确认它能通过校验。
  5. 把杂乱的三层 nest 压到两层:把内层块提升成自己的 class。

常见错误

  • 嵌套写 :hover { } 却不加 & — 无效或不是你想要的;用 &:hover
  • 以为裸写 .child 等于 .parent.child — 那需要 &.child
  • 盲目照搬 Sass 的 &__element BEM 写法 — 原生 nesting 遵循 CSS 选择器语法
  • 嵌五层「因为可以」 — 可读性和 specificity 都会受损
  • 以为 nesting 能取代 var() 或 calc() — 它只是把选择器和 at-rule 分组

小结

  • 嵌套子选择器,让组件样式保持就近;默认展开为后代
  • 同一元素的状态(:hover、.is-active)和显式组合器用 &
  • 把 @media 嵌在你正在调整的组件旁边
  • 嵌套保持浅层;nesting 是结构,不是 token 或数学功能
  • Modern Toolkit 下一步:container queries — 按父级尺寸设样式,而不只靠视口

🧠 测试您的知识

准备开始

测试您的知识

通过这个互动测验挑战自己,看看你对这个主题的理解程度如何

❓
6
问题
🎯
70%
及格要求
♾️
∞
时间
🔄
∞
尝试次数

📝 说明

  • 仔细阅读每个问题
  • 为每个问题选择最佳答案
  • 您可以随时重新参加测验
  • 您的进度将显示在顶部