直接用.spinner-border或.spinner-grow类不加控制会出视觉断裂,根本原因是其默认inline-block、宽高2rem与按钮动态高度脱节;须设按钮relative/overflow-hidden,spinner绝对居中、em单位适配、文字包span并display:none隐藏,配合opacity+visibility双过渡实现平滑切换。

直接用 .spinner-border 或 .spinner-grow 类,不加控制地塞进按钮或页面里,90% 的情况会出视觉断裂——不是动画没转,是它跟上下文根本没对齐。
按钮内 Spinner 为什么总偏移、塌陷、文字上跳
根本原因是 .spinner-border 默认是 display: inline-block,宽高硬编码为 2rem,而按钮高度由 padding + font-size 动态计算,两者盒模型完全脱节。
- 必须给
<button></button>加position: relative和overflow: hidden <div class="spinner-border"> 要插在按钮内部,并设为 <code>position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%)- 宽高必须用
em:按钮是btn-md就设width: 1.5em; height: 1.5em;btn-sm用1.2em;绝对不要写死px或用scale()缩放,否则边框模糊、旋转中心漂移 - 原按钮文字建议包在
<span></span>里,加载时设display: none(不是visibility: hidden),否则按钮宽度会突变 - 初始状态必须设
opacity: 0; visibility: hidden - 淡入:加类如
showing,其中opacity: 1(transition: opacity 0.2s),visibility: visible(transition-delay: 0s) - 淡出:移除
showing类,opacity: 0(同上),但visibility: hidden必须带transition-delay: 0.2s,确保透明后才真正不可见、不响应点击 - JS 只需切换类名,别反复操作
style,漏掉任一属性都会断链 - 遮罩的
z-index至少设为1060,推荐1070 - 必须用
position: fixed,不能absolute,否则滚动时偏移 - 背景用
rgba(0,0,0,0.5),别用纯黑 +opacity,Safari 下透明度叠加异常 - 如果 Modal 是动态创建(如 Vue/React),确保遮罩插在
最外层,别嵌在 Modal 容器里 - 宽高、边框粗细必须为偶数像素(如
4px、8px),避免 subpixel 渲染失真 - 旋转必须用
transform: rotate(),别用animation: spin直接驱动left/top - 务必加
transform: translateZ(0)或will-change: transform触发 GPU 加速 - 动画时长建议设为
0.75s或1s,太短易感知卡顿,太长用户等待焦虑上升
淡入淡出动画怎么写才不闪、不卡、不穿透
直接切 display: none/block 或靠 JS 操作 style.opacity,必然跳帧或点击穿透。真正平滑靠的是 opacity 和 visibility 双过渡 + 精确延迟触发。
全屏遮罩盖不住 Modal 怎么办
Modal 默认 z-index 是 1055,遮罩没显出来,大概率是层级不够——不是“随便调高就行”,而是得比 Modal 的 backdrop(1050)和 content(1055)都高,还得留余量防冲突。
自定义 Spinner 为什么转得卡顿或偏心
自己写的 @keyframes spin + border 容易抖动、偏心、边缘模糊,根本原因常是渲染管线没对齐:非整数像素、奇数边框、未启用 GPU 加速。
最常被忽略的不是动画本身,而是 disabled 状态同步、文字节点清理、font-size 继承链这三件事——少一个,加载动画就变成 UI bug。











