纯 CSS 不支持选择器内嵌套 @media,因其是顶层 at-rule,必须与选择器平级;非法嵌套会导致整条规则失效。原生可行方案包括 @container + @media 组合及自定义属性管理断点。

纯 CSS 不支持真正的“嵌套规则”,@media 本身不能被写在选择器内部(比如 .box { @media (max-width: 768px) { ... } } 是非法语法),所谓“CSS 嵌套的 @media”实际只存在于预处理器(如 Sass、Less)或现代 CSS 嵌套规范(@container + @media 组合)中,浏览器原生不认。
为什么直接写 @media 嵌套在选择器里会报错
浏览器解析 CSS 时,@media 是顶层 at-rule,必须与选择器平级。如果你写了类似下面的代码:
.card {
padding: 1rem;
@media (max-width: 768px) {
padding: 0.5rem;
}
}这在任何标准浏览器中都会被完全忽略——整条 .card 规则都不会生效,因为语法错误导致解析中断。
常见错误现象包括:
立即学习“前端免费学习笔记(深入)”;
- 样式完全不生效,控制台无报错但 DevTools 里看不到该规则
- 后续所有 CSS 规则批量失效(因语法错误打断解析流)
- 构建工具(如 Vite、Webpack)启用 CSS 检查时抛出
Unknown word或Unexpected token
Sass/Less 中的嵌套 @media 是预处理阶段展开的
预处理器允许你写嵌套结构,但最终输出仍是扁平、合法的 CSS。它不是“运行时嵌套”,而是编译时重写。
例如 Sass 写法:
.button {
background: blue;
@media (hover: hover) and (pointer: fine) {
&:hover { background: darkblue; }
}
}会被编译为:
.button { background: blue; }
@media (hover: hover) and (pointer: fine) {
.button:hover { background: darkblue; }
}关键点:
- 必须用 Sass(
.sass或.scss)或 Less 等工具链,纯 HTML 引入.css文件无效 - 嵌套层级越深,生成的 CSS 选择器 specificity 越高,容易覆盖失控
- 不能依赖运行时条件(如用户是否真有 hover 能力),
@media (hover: hover)只是静态检测,不响应动态变化
原生 CSS 中真正可行的“嵌套式响应”:用 @container + @media
CSS 容器查询(@container)已在 Chromium 105+、Firefox 119+、Safari 16.4+ 支持,它允许你基于父容器尺寸做条件样式,配合 @media 可实现双重约束。
例如:
.sidebar {
container-type: inline-size;
}
<p>@container (min-width: 300px) {
@media (prefers-color-scheme: dark) {
.sidebar { background: #1e1e1e; }
}
}这意味着:只有当 .sidebar 容器宽度 ≥300px 且 系统启用深色模式时,才应用背景色。
注意限制:
-
@container要求父元素显式声明container-type,否则整个块无效 -
@container和@media的组合是“逻辑与”,不支持or或嵌套多层@container - 不能替代视口级响应(比如全站导航栏折叠),它只适用于模块化组件(卡片、列表项等)
更轻量、更可控的组织方式:用断点变量 + 扁平 @media
与其强求“嵌套感”,不如用 CSS 自定义属性统一管理断点,提升可维护性:
:root {
--bp-mobile: 480px;
--bp-tablet: 768px;
--bp-desktop: 992px;
}
<p>.card { padding: 1rem; }</p><p>@media (max-width: calc(var(--bp-tablet) - 1px)) {
.card { padding: 0.75rem; }
}</p><p>@media (min-width: var(--bp-desktop)) {
.card { padding: 1.25rem; }
}这种写法的优势:
- 无需构建工具,原生支持
- 断点集中定义,改一处全局生效
- 避免
@media块重复书写相同条件(比如多个组件都需max-width: 767px) - 语义清晰:
calc(var(--bp-tablet) - 1px)明确表示“小于平板”,比硬编码767px更可靠
真正容易被忽略的是:媒体查询的执行时机是“计算样式时”,不是“DOM 加载时”。如果容器尺寸靠 JS 动态撑开(比如手风琴折叠、懒加载图片后重排),@container 会响应,但 @media 不会——它只看视口,不看元素。这点在复杂交互组件里常被误判为“响应失效”。



















