必须联动 transform: rotate() 和 height 动画并设置 transform-origin:上半沙斗用 rotate(45deg) + height 100%→0% + transform-origin: bottom center,下半沙斗用 rotate(-45deg) + height 0%→100% + transform-origin: top center,才能实现稳定、逼真的沙漏收腰效果。

用 transform: rotate() 和 height 动画模拟沙漏收腰效果
沙漏动画本质是两段对称的三角形(或锥形)区域,中间窄、上下宽,靠旋转 + 高度变化制造“流沙下落”错觉。不能只靠 rotate(),否则只是转圈;也不能只缩 height,会塌成一条线。必须两者联动:上半部分顺时针转 + 向下收缩,下半部分逆时针转 + 向上收缩。
- 用两个
div分别代表上半沙斗和下半沙斗,包裹在同一个容器里 - 上半部分设
transform: rotate(45deg),再用height从 100% 动画到 0%,视觉上像沙子“流走” - 下半部分设
transform: rotate(-45deg),height从 0% 到 100%,同步反向“填满” - 动画时间需一致,且用
ease-in-out模拟重力加速度变化,生硬的linear看着假
为什么必须用 transform-origin 控制旋转基点
默认旋转中心是元素中心,但沙漏要绕顶部或底部边缘转,否则会位移出界。上半沙斗得让旋转轴落在底部边沿,下半沙斗得落在顶部边沿,才能保持整体不跳动。
- 上半沙斗加
transform-origin: bottom center - 下半沙斗加
transform-origin: top center - 如果漏掉这句,动画过程中元素会左右晃动,尤其在小尺寸容器里特别明显
- 注意:Chrome 旧版对
transform-origin的解析有偏差,建议统一用center而非50% 50%避免兼容问题
@keyframes 里写 height 还是 scaleY?
优先用 height,不是 scaleY。虽然 scaleY 性能更好,但它会等比压缩内容(比如里面的伪元素沙粒),破坏视觉比例;而 height 只改变高度,边界清晰可控。
-
height动画需确保父容器有明确height或overflow: hidden,否则收缩时内容可能溢出 - 若用
scaleY,必须配合transform-origin: top(上半)或bottom(下半),否则缩放中心错位 - 实测 Safari 对
height+transform同时动画的渲染更稳定,scaleY在 iOS 15 下偶现闪烁
实际部署时容易被忽略的细节
沙漏动画常被嵌入按钮或状态提示中,一动就卡顿,问题往往不在动画本身,而在触发时机和层级。
立即学习“前端免费学习笔记(深入)”;
- 避免在
:hover里直接写完整动画,改用transition+ 类名切换,防止鼠标快速进出反复触发 - 给沙漏容器加
will-change: transform, height,但仅限动画开始前加,结束后立刻移除,否则长期占用 GPU 内存 - 如果沙漏放在
position: absolute元素里,记得父级设overflow: hidden,否则旋转时边缘会露出来 - 移动端需加
-webkit-backface-visibility: hidden,不然 iOS 上旋转角度稍大就糊










