模态窗口结构封装必须用 @mixin 而非 @function,因其需生成样式规则块而非计算值;@mixin 支持嵌套、参数、@content 注入,可统一管理定位、z-index、焦点捕获、响应式及动画等完整逻辑。

模态窗口的结构封装为什么必须用 @mixin 而不是 @function
因为模态窗口涉及的是样式规则块(选择器 + 声明),不是计算值。@function 只能返回字符串、数字、颜色等数据类型,无法生成 CSS 规则;而 @mixin 本质是“可复用的样式模板”,支持嵌套、参数传入、@content 注入,天然适合封装结构。
常见错误是试图用 @function 拼接类名再手动写样式,结果导致维护断裂、响应式逻辑散落、伪元素状态难统一。
-
@mixin modal-base()应覆盖容器定位、z-index 层级、背景遮罩透明度等基础层 - 必须接收
$z-index参数——不同业务模块(如支付弹窗 vs 提示框)需要独立层级控制,硬编码z-index: 9999必然冲突 - 遮罩层
.modal-overlay的backdrop-filter需加@supports条件包裹,否则在 Safari 15.6- 会降级失败且无提示
如何用 @mixin 分离结构与行为,避免 :focus-visible 和键盘焦点混乱
原生模态框常因未管理焦点流导致键盘用户卡死在背景内容里。Sass 封装时不能只管视觉,得把 tabindex="-1"、inert 属性逻辑和焦点捕获函数绑定进 mixin 接口。
实操建议:
- 定义
@mixin modal-dialog($trap-focus: true),当$trap-focus为true时,自动注入outline: none和scrollbar-gutter: stable(防止滚动条消失导致布局偏移) - 在
@content块内强制要求写&__header, &__body, &__footer子选择器,否则focus-trapJS 库无法识别可聚焦区域 - 禁用
transition: all—— 它会让opacity和transform动画抢帧,Safari 下出现闪屏;应显式写transition: opacity 0.2s, transform 0.3s
@include modal-base 与媒体查询共存时的断点陷阱
Sass 的 @media 在 mixin 内部展开时,若未用 @content 或嵌套规则控制作用域,会导致断点样式被错误提升到全局,污染其他组件。
正确做法:
- 所有响应式逻辑必须收束在
@mixin modal-responsive($breakpoint: md)中,且该 mixin 内部用@if $breakpoint == sm { ... }显式分支,不依赖外部@media嵌套传递 - 移动端需强制
max-width: 100vw和margin: 0,但桌面端要留margin: 2rem—— 这些不能靠 CSS 后代选择器推导,必须由 mixin 参数驱动生成独立规则 - 使用
min-width而非max-width断点,避免 iOS Safari viewport 缩放后误触发小屏样式
为什么 !global 不该出现在模态 mixin 的变量声明里
像 $modal-z-index: 1000 !global 看似方便全局调用,实际会造成不可预测的覆盖:当两个团队分别引入 modal.scss 和 notification.scss,都用 !global 设 z-index,后加载的文件直接改写前者的值,DevTools 里根本看不出来源。
更安全的方案:
- 用
$modal-z-index: 1000 !default声明默认值,允许上层通过$modal-z-index: 1050覆盖,且覆盖仅限当前作用域 - 对动画时长等易变参数,用
map-get($modal-config, duration)读取,配置 map 在项目根目录统一维护,而非分散在 mixin 文件里 - 禁止在 mixin 内部用
!important—— 它会破坏 CSS 层叠优先级调试路径,遇到覆盖问题只能删代码重试
真正麻烦的从来不是写不出模态框,而是当产品要求“支付弹窗必须压在客服浮窗上,但又不能影响全站通知层级”时,你发现 z-index 全是 !global 硬编码,连 debug 都得靠注释掉半页 Sass 才能定位。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











