scss中@mixin内定义@keyframes会导致每次@include都重复生成相同关键帧,因sass编译器确定性复制;%占位符不支持@keyframes;正确做法是统一在独立文件中静态定义@keyframes,用@use导入并配以仅控制animation属性的@mixin。

SCSS @mixin 每次@include都生成一份@keyframes
这不是 bug,是 Sass 编译器的确定性行为:@keyframes 规则只要出现在 @mixin 体内,每次 @include 就会原样复制一份到输出 CSS 中。哪怕两个组件调用的是同一个 @mixin animate-in(0.3s),编译后也会出现两段完全相同的 @keyframes in-anim { ... }。
- 关键帧名不带作用域,浏览器只认名字字符串——重复定义不会报错,但浪费体积、增加解析负担
- 无法靠 CSS 层叠去重,
@keyframes不是样式规则,没有“后声明覆盖前声明”的逻辑 - PostCSS 或其他构建工具默认也不会合并它们,得额外插件(且不一定可靠)
为什么不能用 %placeholder 替代 @mixin 封装关键帧
% 占位符不支持 @keyframes,Sass 明确禁止在 % 中写 @keyframes、@function 或 @mixin 声明。你写:
@%my-fade-keyframes { @keyframes my-fade-in { ... } }
会直接报错:Invalid CSS after "%my-fade-keyframes": expected "{", was "{"。占位符只能包裹选择器内的声明块(如 color: red),不能承载 at-rule。
真正能避免重复的关键帧组织方式
必须把 @keyframes 定义和调用彻底分离:所有关键帧统一写在 _animations.scss 中,用带项目前缀的静态名(如 @keyframes my-fade-in),再通过 @use 导入,配同名 @mixin 只控制 animation 属性参数。
- 关键帧定义只出现一次,且必须是静态字符串——不能含
#{$var}插值(顶层不允许) -
@mixin fade-in($duration: $anim-fade-duration, $easing: ease-out)里只写animation: my-fade-in $duration $easing;,不碰@keyframes - 用
@use "animations" as anim,调用时写@include anim.fade-in(0.4s);,干净隔离 - 绝对不要在组件文件里
@include一个带@keyframes的 mixin——那等于把关键帧逻辑复制进了每个组件
@import 是重复的关键推手
如果多个文件都 @import "_animations.scss",而该文件里有 @keyframes,Sass 会把它展开 N 次。即使路径相同,@import 也不做去重。2026 年起 Dart Sass 已废弃 @import,必须改用 @use:同一路径多次 @use,Sass 只执行一次加载。
最容易被忽略的一点:关键帧名一旦重复(比如两个库都用了 @keyframes fade-in),后加载的会覆盖前一个——但浏览器不会警告,动画可能突然失效或行为错乱。所以项目前缀不是风格问题,是运行时安全底线。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











