
本文详解如何通过 CSS @keyframes 实现一个 div 元素向另一个 div 的平滑形变动画,涵盖尺寸、位置、旋转、颜色等属性的无缝过渡,并解决常见“跳变”问题和 translate 偏移计算不准的痛点。
本文详解如何通过 css `@keyframes` 实现一个 div 元素向另一个 div 的平滑形变动画,涵盖尺寸、位置、旋转、颜色等属性的无缝过渡,并解决常见“跳变”问题和 translate 偏移计算不准的痛点。
要让 #div1 平滑“变形”为 #div2(即在视觉上完成位置、大小、旋转、背景色的连续过渡),核心在于:动画必须明确定义起始态(0%)与终止态(100%),且所有参与动画的属性需在两个关键帧中完整声明。你最初尝试的动画只定义了 100%,导致浏览器无法推断初始状态,从而引发突兀跳变——这是 CSS 动画中最常见的误区。
✅ 正确做法:完整声明 keyframes + 使用 transform 替代 layout 属性
避免直接动画 position、left、bottom 等触发布局重排(reflow)的属性。应统一使用 transform: translate() 控制位移,配合 width/height/background-color/transform: rotate() 实现高性能合成动画(GPU 加速)。
首先,获取 #div2 相对于 #div1 的相对偏移量(推荐用 JavaScript 动态计算,确保响应式兼容):
function calculateTransform() {
const div1 = document.getElementById('div1');
const div2 = document.getElementById('div2');
const rect1 = div1.getBoundingClientRect();
const rect2 = div2.getBoundingClientRect();
// 计算 translateX/Y:使 div1 的中心点移动至 div2 的中心点
const centerX1 = rect1.left + rect1.width / 2;
const centerY1 = rect1.top + rect1.height / 2;
const centerX2 = rect2.left + rect2.width / 2;
const centerY2 = rect2.top + rect2.height / 2;
const tx = centerX2 - centerX1;
const ty = centerY2 - centerY1;
// 应用到 CSS 变量,供 keyframes 使用
document.documentElement.style.setProperty('--tx', `${tx}px`);
document.documentElement.style.setProperty('--ty', `${ty}px`);
}
// 页面加载及 resize 后重新计算
window.addEventListener('load', calculateTransform);
window.addEventListener('resize', calculateTransform);
然后,在 CSS 中定义完整动画(含 0% 和 100%):
:root {
--tx: 0px;
--ty: 0px;
}
#div1 {
background-color: red;
width: 100px;
height: 100px;
text-align: center;
/* 关键:启用 transform 动画优化 */
will-change: transform, width, height, background-color;
animation: morph 2s ease-in-out forwards;
}
@keyframes morph {
0% {
width: 100px;
height: 100px;
background-color: red;
transform: translate(0, 0) rotate(0deg);
}
100% {
width: 80px;
height: 120px;
background-color: blue;
transform: translate(var(--tx), var(--ty)) rotate(-10deg);
}
}
⚠️ 注意事项:
forwards必不可少:确保动画结束后元素保持在100%状态,否则会回退;will-change提升性能:提示浏览器对这些属性做 GPU 缓存;- 避免
position: absolute冲突:动画中的#div1保持文档流内定位(如 flex 容器中),仅靠transform移动,不破坏布局;- 颜色过渡需
background-color可动画:CSS 支持该属性的插值(无需额外 polyfill);- 若需更精细控制(如 easing 分段),可增加
25%、50%等中间帧,但务必保证所有动画属性全程存在。
✅ 最终效果验证要点
- ✅ 无初始跳变(因 0% 显式定义)
- ✅ 位移精准(基于中心点对齐,非左上角硬编码)
- ✅ 旋转与缩放同步(
transform复合函数保证顺序一致) - ✅ 响应式安全(
getBoundingClientRect()动态适配视口变化)
通过这一模式,你不仅能复现 div1 → div2 的形变,还可扩展至任意两个 DOM 元素间的视觉映射动画——真正实现「状态驱动」而非「像素硬编码」的现代 CSS 动画实践。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











