纯CSS沙漏动画需同时控制旋转、高度变化和裁剪边界;仅用rotate()或height会导致穿帮,必须用.sand-top与.sand-bottom双元素分别控制收窄与撑开,并配合transform-origin、clip-path及分段keyframes实现严丝合缝的视觉效果。

纯 CSS 能做出视觉可信的沙漏动画,但必须同时控制旋转、高度变化和裁剪边界——只靠 rotate() 或只缩 height 都会穿帮。
为什么沙漏动画不能只用 transform: rotate()
单纯旋转整个容器,只是把沙漏“转圈”,沙子不会流动;旋转单个沙斗又容易位移出界。真实沙漏的关键是「上半沙斗顺时针收窄 + 下半沙斗逆时针撑开」,这需要两个独立元素分别控制:.sand-top 和 .sand-bottom。如果只写一个 @keyframes rotate 套在父容器上,你会看到沙子原地打转,或者上下沙斗错位分离。
常见错误现象:
- 沙子区域随旋转整体偏移,脱离玻璃容器边界
- 动画中途出现“撕裂感”,上下沙斗接缝处露白
- 小尺寸下晃动明显,尤其在移动端 Safari 中
height 动画必须配 transform-origin 和 clip-path
仅靠 height: 100% → 0% 会让沙子塌成一条线,失去锥形收腰效果。必须叠加 transform: rotate(45deg) 并指定旋转基点,让收缩过程沿沙斗边缘发生。
立即学习“前端免费学习笔记(深入)”;
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
实操要点:
-
.sand-top要加transform-origin: bottom center,否则收缩时顶部会翘起 -
.sand-bottom要加transform-origin: top center,否则底部会内陷 - 必须用
clip-path: polygon(...)固定沙斗轮廓,防止height改变时内容溢出 - 避免用
scaleY():它会压缩内部伪元素(如模拟沙粒的::before),比例失真
动画时间与翻转节奏怎么对齐
一次完整计时周期 = 沙子从顶流到底 + 沙漏物理翻转 + 沙子从底回顶。CSS 里通常把整个循环设为 --rotateTime: 10s,其中:
- 0%–45%:上半沙斗从满到空(
height: 100% → 0%),下半保持空 - 45%–55%:快速翻转 180°(视觉上沙漏倒置)
- 55%–100%:下半沙斗从空到满(
height: 0% → 100%),上半保持空
关键细节:
- 翻转帧(50%)必须精确落在
transform: rotate(180deg),不能靠 easing 模拟 - 两段
height动画要用ease-in-out,模拟重力加速/减速,linear 看着生硬 - 若嵌入按钮或弹层,务必加
will-change: transform, height,但仅在动画开始前动态添加,结束后立刻移除
嵌入页面时最容易被忽略的渲染陷阱
沙漏动画卡顿,90% 不是代码写错,而是触发方式和层级失控。
- 别在
:hover里直接写animation: ...—— 鼠标反复进出会反复重绘,改用transition+ 类名切换 - 父容器必须有明确
height且overflow: hidden,否则height收缩时内容可能撑破边界 - Chrome 旧版对
transform-origin: 50% 50%解析异常,统一写center更稳 - Safari 对
height + transform同时动画更友好,iOS 15 下scaleY有偶发闪烁
真正难的不是写出动画,而是让每次翻转都严丝合缝地咬合在玻璃容器边缘——差 1px 就穿帮,少一句 transform-origin 就晃动。这些细节不调试到真机上跑一遍,根本看不出问题。


















