必须用$breakpoints map,因map-get()仅支持map类型,list或变量传入返回null;键名可查、值带单位(如40em)、支持map-has-key()守卫,便于统一管理、批量遍历和ide跳转。

直接用 @media 硬写断点是维护噩梦,真正可落地的方案必须满足三点:断点数值集中管理、@content 正确注入嵌套样式、单位用 em 而非 px。
为什么必须用 $breakpoints map 而不是变量或 list
SCSS 的 map-get() 只认 map 类型。你写 $sm: 768px,调用 @include respond-to("sm") 就会返回 null;写 (576px, 768px) 这种 list,根本没法按名字查值,@include respond-to("md") 直接失效。IDE 也无法跳转到定义处,协作时谁也不知道 $md 到底对应哪一层设备。
必须声明为键值对形式:
@use "sass:map"; $breakpoints: ( "sm": 40em, "md": 48em, "lg": 64em, "xl": 80em );
- 键名推荐
"sm"而非"mobile":语义稳定,不绑定具体设备 - 值必须带单位:
40em,不能写40,否则编译报Invalid null operation -
em单位适配缩放和动态根字号,px在高 DPI 设备或用户缩放时会失效
respond-to mixin 必须只用 min-width 实现向上覆盖
用 @media (min-width: 48em) 天然支持“向上覆盖”,边界清晰。如果混用 max-width,比如同时写 @media (max-width: 47.98em) 和 @media (max-width: 63.98em),48–64em 区间两个都匹配,浏览器取后声明的规则,但你本意可能是让这个区间单独生效——这时就得手动加 and (min-width: 48em),反而更啰嗦且易错。
标准写法:
@mixin respond-to($name) {
@if map.has-key($breakpoints, $name) {
@media (min-width: map.get($breakpoints, $name)) {
@content;
}
} @else {
@warn "Unknown breakpoint #{$name}.";
}
}
- 所有断点按升序排列:
sm → md → lg → xl - 桌面端样式写在默认层(无媒体查询),移动端覆盖逻辑全交给
@include respond-to("sm")往上叠加 - 别在 mixin 内部写
max-width查询——它和min-width混用极易触发重叠或遗漏
@content 不是语法糖,是嵌套能力的关键
没有 @content 的断点 mixin 只能返回字符串,你得自己拼接样式块,既难读又易出错。加上 @content 后,它允许你在调用时传入任意样式规则,Sass 会原样注入到生成的 @media 块内部。
正确调用方式:
.card {
padding: 1rem;
@include respond-to("lg") {
padding: 1.5rem;
&__title {
font-size: 1.5rem;
}
}
}
-
@content必须出现在 mixin 定义里,且只能出现一次 - 调用时必须用大括号包裹内容:
@include respond-to("md") { ... },不能省略{} - 不能在
@content外部访问调用作用域里的局部变量——这是作用域隔离机制,不是 bug - 支持透传
&:hover、&::before等,不会破坏父选择器层级
如何安全支持 down / between 场景而不爆炸式增长 mixin 数量
写 for-mobile-up、for-mobile-down、for-mobile-only……十几个 mixin 看似清晰,实则违反 DRY。真正可维护的是用统一入口 + 参数组合:
@mixin respond-to-down($name) {
@if map.has-key($breakpoints, $name) {
$next: map.next-key($breakpoints, $name);
$val: map.get($breakpoints, $name);
$max: if($next, map.get($breakpoints, $next) - 0.02em, 9999em);
@media (max-width: $max) {
@content;
}
}
}
<p>@mixin respond-to-between($min, $max) {
@if map.has-key($breakpoints, $min) and map.has-key($breakpoints, $max) {
@media (min-width: map.get($breakpoints, $min)) and (max-width: map.get($breakpoints, $max) - 0.02em) {
@content;
}
}
}</p>
-
respond-to-down("md")生成@media (max-width: 47.98em),避免整数像素四舍五入导致的重叠或空隙 -
respond-to-between("md", "xl")明确表达区间,比两层嵌套清晰得多 - 所有边界值减
0.02em是为了规避 CSS 像素比影响下em计算的微小偏移 - 别用
max-width模拟up,像素边界容易重叠(比如48em同时被两个媒体查询捕获)
最常踩的坑不在写法本身,而在调用位置——@include respond-to() 必须写在有选择器后的大括号内部,不能直接写在顶层或变量声明后;另外,em 断点依赖根字体大小,如果项目用了动态 font-size 或缩放策略,要确认 HTML 的 font-size 基准是否稳定。











