Skip to content

动画与过渡

CSS 动画和过渡可以让网页元素产生动态效果,提升用户体验。

过渡(Transition)

过渡用于在两个状态之间平滑切换。

基本语法

css
.element {
    transition: property duration timing-function delay;
}

transition-property

指定要过渡的属性:

css
div {
    transition-property: all;        /* 所有属性 */
    transition-property: width;      /* 单个属性 */
    transition-property: width, height, background-color; /* 多个属性 */
}

transition-duration

设置过渡时间:

css
div {
    transition-duration: 0.3s;
    transition-duration: 300ms;
    transition-duration: 0.3s, 0.5s; /* 多个属性对应不同时间 */
}

transition-timing-function

设置过渡速度曲线:

css
div {
    transition-timing-function: ease;        /* 慢-快-慢(默认) */
    transition-timing-function: linear;      /* 匀速 */
    transition-timing-function: ease-in;     /* 慢开始 */
    transition-timing-function: ease-out;    /* 慢结束 */
    transition-timing-function: ease-in-out; /* 慢开始和结束 */
    transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); /* 自定义 */
}

transition-delay

设置过渡延迟:

css
div {
    transition-delay: 0.5s;
}

transition 简写

css
div {
    transition: all 0.3s ease 0s;
    transition: width 0.3s, height 0.5s ease-in-out;
}

过渡示例

css
.button {
    background-color: #007bff;
    color: white;
    padding: 10px 20px;
    border: none;
    border-radius: 4px;
    transition: background-color 0.3s ease, transform 0.2s ease;
}

.button:hover {
    background-color: #0056b3;
    transform: scale(1.05);
}

变换(Transform)

变换用于对元素进行旋转、缩放、倾斜、移动。

2D 变换

translate(移动)

css
div {
    transform: translate(50px, 100px);  /* x, y */
    transform: translateX(50px);
    transform: translateY(100px);
}

scale(缩放)

css
div {
    transform: scale(2);              /* 放大2倍 */
    transform: scale(0.5);            /* 缩小一半 */
    transform: scale(2, 1.5);         /* x, y 分别缩放 */
    transform: scaleX(2);
    transform: scaleY(1.5);
}

rotate(旋转)

css
div {
    transform: rotate(45deg);         /* 顺时针旋转45度 */
    transform: rotate(-45deg);        /* 逆时针旋转 */
}

skew(倾斜)

css
div {
    transform: skew(10deg, 20deg);    /* x, y 倾斜 */
    transform: skewX(10deg);
    transform: skewY(20deg);
}

matrix(矩阵)

css
div {
    transform: matrix(1, 0, 0, 1, 0, 0);
}

3D 变换

translate3d

css
div {
    transform: translate3d(50px, 100px, 200px);
    transform: translateZ(100px);
}

scale3d

css
div {
    transform: scale3d(1, 1.5, 2);
    transform: scaleZ(2);
}

rotate3d

css
div {
    transform: rotate3d(1, 1, 1, 45deg);
    transform: rotateX(45deg);
    transform: rotateY(45deg);
    transform: rotateZ(45deg);
}

perspective(透视)

css
.parent {
    perspective: 1000px;  /* 透视距离 */
}

.child {
    transform: rotateY(45deg);
}

transform-style

css
.parent {
    transform-style: flat;         /* 2D(默认) */
    transform-style: preserve-3d;  /* 3D */
}

backface-visibility

css
div {
    backface-visibility: visible;  /* 背面可见(默认) */
    backface-visibility: hidden;   /* 背面隐藏 */
}

transform-origin

设置变换原点:

css
div {
    transform-origin: center center;  /* 默认 */
    transform-origin: top left;
    transform-origin: 50% 50%;
    transform-origin: 20px 30px;
}

关键帧动画(Animation)

关键帧动画可以创建更复杂的动画序列。

@keyframes

定义动画关键帧:

css
@keyframes slideIn {
    from {
        transform: translateX(-100%);
        opacity: 0;
    }
    to {
        transform: translateX(0);
        opacity: 1;
    }
}

/* 或使用百分比 */
@keyframes bounce {
    0%, 100% {
        transform: translateY(0);
    }
    50% {
        transform: translateY(-30px);
    }
}

animation 属性

animation-name

指定动画名称:

css
div {
    animation-name: slideIn;
}

animation-duration

设置动画时间:

css
div {
    animation-duration: 1s;
}

animation-timing-function

设置动画速度曲线:

css
div {
    animation-timing-function: ease;
    animation-timing-function: linear;
    animation-timing-function: ease-in-out;
    animation-timing-function: steps(5, end);
}

animation-delay

设置动画延迟:

css
div {
    animation-delay: 0.5s;
}

animation-iteration-count

设置动画次数:

css
div {
    animation-iteration-count: 1;      /* 播放1次 */
    animation-iteration-count: 3;      /* 播放3次 */
    animation-iteration-count: infinite; /* 无限循环 */
}

animation-direction

设置动画方向:

css
div {
    animation-direction: normal;       /* 正向(默认) */
    animation-direction: reverse;      /* 反向 */
    animation-direction: alternate;    /* 正反交替 */
    animation-direction: alternate-reverse; /* 反正交替 */
}

animation-fill-mode

设置动画填充模式:

css
div {
    animation-fill-mode: none;         /* 默认 */
    animation-fill-mode: forwards;     /* 保持结束状态 */
    animation-fill-mode: backwards;    /* 保持开始状态 */
    animation-fill-mode: both;         /* 两端都保持 */
}

animation-play-state

设置动画播放状态:

css
div {
    animation-play-state: running;     /* 播放(默认) */
    animation-play-state: paused;      /* 暂停 */
}

animation 简写

css
div {
    animation: name duration timing-function delay iteration-count direction fill-mode;
    
    animation: slideIn 1s ease 0s 1 normal forwards;
    animation: bounce 0.5s ease-in-out infinite alternate;
}

常用动画效果

淡入淡出

css
@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

.fade-in {
    animation: fadeIn 0.5s ease-in-out;
}

弹跳效果

css
@keyframes bounce {
    0%, 20%, 50%, 80%, 100% {
        transform: translateY(0);
    }
    40% {
        transform: translateY(-30px);
    }
    60% {
        transform: translateY(-15px);
    }
}

.bounce {
    animation: bounce 1s ease infinite;
}

旋转加载

css
@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

.spinner {
    animation: spin 1s linear infinite;
}

脉冲效果

css
@keyframes pulse {
    0% {
        transform: scale(1);
    }
    50% {
        transform: scale(1.1);
    }
    100% {
        transform: scale(1);
    }
}

.pulse {
    animation: pulse 1s ease-in-out infinite;
}

摇晃效果

css
@keyframes shake {
    0%, 100% { transform: translateX(0); }
    10%, 30%, 50%, 70%, 90% { transform: translateX(-10px); }
    20%, 40%, 60%, 80% { transform: translateX(10px); }
}

.shake {
    animation: shake 0.5s ease-in-out;
}

性能优化

使用 transform 和 opacity

这两个属性不会触发重排,性能更好:

css
/* 推荐 */
.element {
    transition: transform 0.3s, opacity 0.3s;
}
.element:hover {
    transform: scale(1.1);
    opacity: 0.8;
}

/* 不推荐 */
.element {
    transition: width 0.3s, height 0.3s, left 0.3s, top 0.3s;
}

will-change

提示浏览器将要变化的属性:

css
.element {
    will-change: transform, opacity;
}

实践示例

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>动画与过渡示例</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: Arial, sans-serif;
            padding: 20px;
            background-color: #f5f5f5;
        }
        
        .container {
            max-width: 800px;
            margin: 0 auto;
        }
        
        h2 {
            margin: 30px 0 15px;
            color: #333;
        }
        
        /* 过渡按钮 */
        .btn {
            padding: 12px 24px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            transition: all 0.3s ease;
            margin: 5px;
        }
        
        .btn-primary {
            background-color: #007bff;
            color: white;
        }
        
        .btn-primary:hover {
            background-color: #0056b3;
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(0, 123, 255, 0.4);
        }
        
        .btn-outline {
            background-color: transparent;
            color: #007bff;
            border: 2px solid #007bff;
        }
        
        .btn-outline:hover {
            background-color: #007bff;
            color: white;
        }
        
        /* 卡片悬停 */
        .card {
            background: white;
            border-radius: 8px;
            padding: 20px;
            margin: 10px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            transition: transform 0.3s ease, box-shadow 0.3s ease;
        }
        
        .card:hover {
            transform: translateY(-5px);
            box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
        }
        
        .cards {
            display: flex;
            flex-wrap: wrap;
        }
        
        /* 加载动画 */
        .spinner {
            width: 40px;
            height: 40px;
            border: 4px solid #f3f3f3;
            border-top: 4px solid #007bff;
            border-radius: 50%;
            animation: spin 1s linear infinite;
            margin: 20px auto;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        /* 脉冲效果 */
        .pulse-box {
            width: 100px;
            height: 100px;
            background: linear-gradient(135deg, #667eea, #764ba2);
            border-radius: 50%;
            margin: 20px auto;
            animation: pulse 1.5s ease-in-out infinite;
        }
        
        @keyframes pulse {
            0%, 100% { transform: scale(1); opacity: 1; }
            50% { transform: scale(1.1); opacity: 0.8; }
        }
        
        /* 弹跳效果 */
        .bounce-box {
            width: 60px;
            height: 60px;
            background-color: #28a745;
            border-radius: 8px;
            margin: 20px auto;
            animation: bounce 1s ease infinite;
        }
        
        @keyframes bounce {
            0%, 100% { transform: translateY(0); }
            50% { transform: translateY(-20px); }
        }
        
        /* 3D 翻转 */
        .flip-container {
            perspective: 1000px;
            width: 200px;
            height: 120px;
            margin: 20px auto;
        }
        
        .flip-card {
            width: 100%;
            height: 100%;
            position: relative;
            transform-style: preserve-3d;
            transition: transform 0.6s;
        }
        
        .flip-container:hover .flip-card {
            transform: rotateY(180deg);
        }
        
        .flip-front, .flip-back {
            position: absolute;
            width: 100%;
            height: 100%;
            backface-visibility: hidden;
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 18px;
            font-weight: bold;
        }
        
        .flip-front {
            background: #007bff;
            color: white;
        }
        
        .flip-back {
            background: #28a745;
            color: white;
            transform: rotateY(180deg);
        }
        
        /* 淡入动画 */
        .fade-in {
            animation: fadeIn 1s ease-in-out;
        }
        
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(20px); }
            to { opacity: 1; transform: translateY(0); }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>动画与过渡示例</h1>
        
        <h2>按钮过渡效果</h2>
        <button class="btn btn-primary">主要按钮</button>
        <button class="btn btn-outline">轮廓按钮</button>
        
        <h2>卡片悬停效果</h2>
        <div class="cards">
            <div class="card">
                <h3>卡片 1</h3>
                <p>悬停查看效果</p>
            </div>
            <div class="card">
                <h3>卡片 2</h3>
                <p>悬停查看效果</p>
            </div>
            <div class="card">
                <h3>卡片 3</h3>
                <p>悬停查看效果</p>
            </div>
        </div>
        
        <h2>加载动画</h2>
        <div class="spinner"></div>
        
        <h2>脉冲效果</h2>
        <div class="pulse-box"></div>
        
        <h2>弹跳效果</h2>
        <div class="bounce-box"></div>
        
        <h2>3D 翻转效果</h2>
        <div class="flip-container">
            <div class="flip-card">
                <div class="flip-front">正面</div>
                <div class="flip-back">背面</div>
            </div>
        </div>
    </div>
</body>
</html>