
本文详解如何通过 CSS @keyframes 实现一个 div 元素向另一个 div 的平滑形变动画,涵盖尺寸、位置、旋转、背景色等属性的连贯过渡,避免跳变,并提供可复用的计算逻辑与最佳实践。
本文详解如何通过 css `@keyframes` 实现一个 div 元素向另一个 div 的平滑形变动画,涵盖尺寸、位置、旋转、背景色等属性的连贯过渡,避免跳变,并提供可复用的计算逻辑与最佳实践。
在 Web 动画开发中,「将一个 div ‘变形’为另一个 div」并非真正替换 DOM 节点,而是通过 CSS 动画让元素从初始样式(div1)视觉上连续过渡至目标样式(div2)——包括宽高、颜色、旋转角度、定位偏移等。但许多开发者遇到的核心问题在于:动画不流畅、出现突兀跳变(jump),根本原因通常是 关键帧定义不完整或 transform/position 变化未被正确插值。
✅ 正确做法:定义完整的 0% 和 100% 关键帧
CSS 动画插值依赖于起始态与终止态的明确声明。若只写 100%,浏览器会默认从元素当前渲染状态(可能含布局偏移、静态定位)开始插值,导致 position、left/bottom 等非 transform 属性无法平滑过渡(因这些属性触发重排,且不支持硬件加速)。因此,必须显式声明 0% 状态,并统一使用 transform 控制位移与旋转。
以下是推荐方案(基于你的原始结构优化):
<style>
.center {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
#div1 {
background-color: red;
width: 100px;
height: 100px;
text-align: center;
/* 关键:初始态设为相对定位 + transform 基准 */
position: relative;
transform: translate(0, 0) rotate(0deg);
/* 启用硬件加速,提升动画性能 */
will-change: transform, width, height, background-color;
animation: transformation 2s ease-in-out forwards;
}
@keyframes transformation {
0% {
width: 100px;
height: 100px;
background-color: red;
transform: translate(0, 0) rotate(0deg);
}
100% {
width: 80px;
height: 120px;
background-color: blue;
/* 将绝对定位 left/bottom 转换为等效的 transform translate */
/* 计算逻辑见下文 → */
transform: translate(-30px, 10px) rotate(-10deg);
}
}
</style><div class="center">
<div id="div1">
<h1>DIV1</h1>
</div>
</div>
<!-- div2 仅作为参考,无需显示 -->
<div id="div2" style="display:none;">
<h1>DIV2</h1>
</div>
? 为什么 translate() 比 left/bottom 更可靠?
-
left/bottom属于布局属性,修改会触发浏览器重排(reflow),性能差且插值不自然; -
transform: translate(x, y)是合成属性,由 GPU 加速,支持亚像素插值,动画丝滑; - 所有形变动画(位移、缩放、旋转、倾斜)应优先通过
transform实现,保持单一可控维度。
? 如何精准计算 translate(x, y) 值?
你尝试用 getBoundingClientRect() 计算偏移是正确的方向,但需注意:必须基于同一坐标系(如视口 viewport)且考虑父容器影响。推荐以下稳健计算方式(JavaScript 辅助初始化):
function calculateTransform() {
const div1 = document.getElementById('div1');
const div2 = document.getElementById('div2');
const rect1 = div1.getBoundingClientRect();
const rect2 = div2.getBoundingClientRect();
// 视口坐标差值 = div2 左上角 - div1 左上角
const dx = rect2.left - rect1.left;
const dy = rect2.top - rect1.top;
// 动态注入 CSS 变量(推荐)或直接设置 style
document.documentElement.style.setProperty('--tx', `${dx}px`);
document.documentElement.style.setProperty('--ty', `${dy}px`);
}
// 页面加载后执行一次
window.addEventListener('load', calculateTransform);
// 若布局可能动态变化,可监听 resize 或使用 ResizeObserver
对应 CSS 中使用:
@keyframes transformation {
0% { transform: translate(0, 0) rotate(0deg); }
100% { transform: translate(var(--tx), var(--ty)) rotate(-10deg); }
}
⚠️ 注意事项与最佳实践
-
forwards必不可少:确保动画结束后元素保持100%样式,否则会回退; -
避免混用
position与transform:若需绝对定位效果,请统一用transform模拟,而非同时设置left+transform; -
颜色过渡需指定
background-color起止值:否则默认从transparent插值,造成闪烁; -
性能优化:对动画元素添加
will-change: transform, width, height, background-color;(生产环境慎用,仅对高频动画元素); -
无障碍友好:为动画添加
prefers-reduced-motion查询,尊重用户偏好:@media (prefers-reduced-motion: reduce) { #div1 { animation: none; } }
通过以上方法,你不仅能消除跳变,还能构建可维护、高性能、跨浏览器兼容的形变动画。核心原则始终如一:明确定义起止状态、优先使用 transform、用 JavaScript 精准计算坐标差值、并善用 CSS 变量解耦逻辑与样式。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











