百叶窗动画本质是CSS clip-path动态切割,用inset()或polygon()对单元素分段遮罩并逐条显示,需避免多div拼接,注意兼容性、性能及Safari渲染差异。

百叶窗动画的本质是CSS clip-path 的动态切割
纯CSS实现百叶窗效果不依赖JavaScript,核心是用 clip-path 对元素做逐条裁剪。浏览器原生支持该属性(Chrome 52+、Firefox 54+、Safari 15.4+),但IE完全不支持,Edge 16+ 可用。关键不是“画出百叶”,而是把一个图层按垂直或水平条带分段遮罩,再依次显示。
常见错误是试图用多个 div 拼接条带——这会导致重绘开销大、同步难、响应式崩坏;正确做法是单个容器 + 动态 clip-path 路径。
- 垂直百叶:用
inset()或polygon()控制每条缝隙的上下边界 - 水平百叶:同理,控制左右边界,但需注意容器宽高比和 transform-origin 配合
- 动画必须用
transition或@keyframes驱动clip-path值变化,不能靠 visibility 或 opacity 模拟
用 inset() 实现垂直百叶窗的最小可行代码
inset() 是最易读、兼容性较好的方案,适合等宽条带。假设将图片分成 8 条垂直百叶,从左到右依次展开:
img {
clip-path: inset(0 87.5% 0 0); /* 初始:只显示最左1/8 */
transition: clip-path 0.6s ease-in-out;
}
img:hover {
clip-path: inset(0 0 0 0); /* 完全显示 */
}这里 87.5% = (7/8) × 100%,即隐藏右侧 7/8 区域。要实现“逐条打开”,就得用 @keyframes 分步控制每一条的露出时机,例如:
立即学习“前端免费学习笔记(深入)”;
@keyframes blinds-vertical {
0% { clip-path: inset(0 100% 0 0); }
12.5% { clip-path: inset(0 87.5% 0 0); }
25% { clip-path: inset(0 75% 0 0); }
/* …依此类推直到 100% */
}注意:百分比值必须严格对应条带数量,8 条就得 8 个关键帧,且每个 step 间隔为 100% / 条数;任意偏差都会导致跳帧或错位。
用 polygon() 实现更精确的条带控制
当需要非等宽条带、斜向百叶或保留边框时,polygon() 更灵活,但路径坐标计算容易出错。例如单条垂直百叶从左向右扫过:
clip-path: polygon(0 0, 0% 100%, 0% 100%, 0% 0); /* 初始:完全遮罩 */ clip-path: polygon(0 0, 12.5% 0, 12.5% 100%, 0% 100%); /* 显示第一条:宽12.5%的矩形 */
问题在于:所有坐标必须用百分比,且顶点顺序必须顺时针闭合,否则部分浏览器(如旧版 Safari)会忽略该规则。调试时可临时加 outline: 1px solid red 查看实际裁剪区域。
- 每条百叶对应一个独立
polygon()形状,无法用单个动画平滑过渡,需配合steps()或 JS 控制帧序 - 移动端 Safari 对
polygon()动画支持不稳定,建议 fallback 到inset() - 若容器有
border-radius,clip-path会优先裁剪圆角外区域,视觉上可能“切掉”圆角
性能与响应式必须处理的三个细节
百叶窗动画在中低端设备上容易掉帧,尤其图片大或条数多时。不是加 will-change: clip-path 就能解决——它反而可能触发不必要的图层提升。
- 限制条带数量:超过 12 条后,动画延迟明显,建议 6–8 条为佳
- 避免在
body或滚动容器内直接应用,clip-path 会强制重绘整个层,应包裹在transform: translateZ(0)的独立图层中 - 响应式场景下,百分比坐标会随容器缩放,但
inset()的右/左值需重新计算;推荐用 CSS 自定义属性动态更新:--blinds-step: calc(100% / var(--count));
真正麻烦的是 Safari 对 clip-path 动画的渲染节奏不一致——同一段代码,在 macOS 和 iOS 上可能一卡一顺。上线前务必真机测试,别信模拟器。


















