Skip to content

过渡与动画

本章将介绍CSS过渡和动画,让网页元素能够平滑地改变样式,创建流畅的动画效果。

CSS过渡(Transition)

过渡允许CSS属性值在一定时间内平滑地变化。

基本语法

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>过渡基本语法</title>
    <style>
        .box {
            width: 100px;
            height: 100px;
            background-color: #4CAF50;
            margin: 20px;
            
            /* transition: 属性名 持续时间 时间函数 延迟时间; */
            transition: all 0.3s ease;
        }
        
        .box:hover {
            width: 200px;
            background-color: #2196F3;
        }
        
        /* 分解写法 */
        .box-detailed {
            width: 100px;
            height: 100px;
            background-color: #FF9800;
            margin: 20px;
            
            transition-property: width, background-color;  /* 过渡属性 */
            transition-duration: 0.5s;                      /* 持续时间 */
            transition-timing-function: ease-in-out;        /* 时间函数 */
            transition-delay: 0.1s;                         /* 延迟时间 */
        }
        
        .box-detailed:hover {
            width: 200px;
            background-color: #E91E63;
        }
    </style>
</head>
<body>
    <p>鼠标悬停查看过渡效果:</p>
    <div class="box">简写形式</div>
    <div class="box-detailed">分解写法</div>
</body>
</html>

transition-property(过渡属性)

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>transition-property示例</title>
    <style>
        .box {
            width: 100px;
            height: 100px;
            background-color: #4CAF50;
            margin: 20px;
            display: inline-block;
            vertical-align: top;
        }
        
        /* 过渡所有属性 */
        .all {
            transition: all 0.3s;
        }
        
        /* 只过渡宽度 */
        .width-only {
            transition: width 0.3s;
        }
        
        /* 过渡多个属性 */
        .multiple {
            transition: width 0.3s, background-color 0.3s, transform 0.3s;
        }
        
        /* 不过渡任何属性 */
        .none {
            transition: none;
        }
        
        .box:hover {
            width: 150px;
            height: 150px;
            background-color: #2196F3;
            transform: rotate(10deg);
        }
    </style>
</head>
<body>
    <div class="box all">all:所有属性过渡</div>
    <div class="box width-only">width:只有宽度过渡</div>
    <div class="box multiple">多属性:指定属性过渡</div>
    <div class="box none">none:无过渡</div>
</body>
</html>

transition-duration(持续时间)

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>transition-duration示例</title>
    <style>
        .box {
            width: 100px;
            height: 50px;
            background-color: #4CAF50;
            margin: 10px;
            transition: width;
        }
        
        .box:hover {
            width: 300px;
        }
        
        /* 不同持续时间 */
        .fast { transition-duration: 0.1s; }
        .normal { transition-duration: 0.3s; }
        .slow { transition-duration: 1s; }
        .slower { transition-duration: 2s; }
        
        /* 不同单位 */
        .ms { transition-duration: 500ms; }  /* 毫秒 */
        .s { transition-duration: 0.5s; }    /* 秒 */
    </style>
</head>
<body>
    <div class="box fast">0.1秒</div>
    <div class="box normal">0.3秒</div>
    <div class="box slow">1秒</div>
    <div class="box slower">2秒</div>
</body>
</html>

transition-timing-function(时间函数)

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>时间函数示例</title>
    <style>
        .container {
            width: 400px;
            height: 30px;
            background-color: #f5f5f5;
            margin: 10px;
            position: relative;
        }
        
        .box {
            width: 30px;
            height: 30px;
            background-color: #4CAF50;
            position: absolute;
            left: 0;
            transition: left 2s;
        }
        
        .container:hover .box {
            left: calc(100% - 30px);
        }
        
        /* 预设时间函数 */
        .linear { transition-timing-function: linear; }        /* 线性 */
        .ease { transition-timing-function: ease; }            /* 默认,快开始慢结束 */
        .ease-in { transition-timing-function: ease-in; }      /* 慢开始 */
        .ease-out { transition-timing-function: ease-out; }    /* 慢结束 */
        .ease-in-out { transition-timing-function: ease-in-out; } /* 慢开始慢结束 */
        
        /* 贝塞尔曲线 */
        .cubic-bezier {
            transition-timing-function: cubic-bezier(0.68, -0.55, 0.27, 1.55);
        }
        
        /* 步进函数 */
        .steps-start { transition-timing-function: steps(5, start); }
        .steps-end { transition-timing-function: steps(5, end); }
    </style>
</head>
<body>
    <p>鼠标悬停在容器上查看动画效果:</p>
    
    <div class="container">
        <div class="box linear"></div>
        <span style="margin-left: 40px;">linear(线性)</span>
    </div>
    
    <div class="container">
        <div class="box ease"></div>
        <span style="margin-left: 40px;">ease(默认)</span>
    </div>
    
    <div class="container">
        <div class="box ease-in"></div>
        <span style="margin-left: 40px;">ease-in(慢开始)</span>
    </div>
    
    <div class="container">
        <div class="box ease-out"></div>
        <span style="margin-left: 40px;">ease-out(慢结束)</span>
    </div>
    
    <div class="container">
        <div class="box ease-in-out"></div>
        <span style="margin-left: 40px;">ease-in-out</span>
    </div>
    
    <div class="container">
        <div class="box cubic-bezier"></div>
        <span style="margin-left: 40px;">cubic-bezier(弹跳效果)</span>
    </div>
</body>
</html>

transition-delay(延迟时间)

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>transition-delay示例</title>
    <style>
        .box {
            width: 100px;
            height: 100px;
            background-color: #4CAF50;
            margin: 10px;
            display: inline-block;
            transition: all 0.3s;
        }
        
        .box:hover {
            background-color: #2196F3;
            transform: scale(1.1);
        }
        
        /* 不同延迟时间 */
        .delay-0 { transition-delay: 0s; }
        .delay-1 { transition-delay: 0.1s; }
        .delay-2 { transition-delay: 0.2s; }
        .delay-3 { transition-delay: 0.3s; }
        .delay-4 { transition-delay: 0.4s; }
    </style>
</head>
<body>
    <p>鼠标悬停查看延迟效果:</p>
    <div class="box delay-0">延迟0s</div>
    <div class="box delay-1">延迟0.1s</div>
    <div class="box delay-2">延迟0.2s</div>
    <div class="box delay-3">延迟0.3s</div>
    <div class="box delay-4">延迟0.4s</div>
</body>
</html>

过渡示例

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>过渡效果示例</title>
    <style>
        .container {
            padding: 20px;
        }
        
        /* 按钮悬停效果 */
        .btn {
            padding: 12px 24px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            transition: all 0.3s ease;
        }
        
        .btn:hover {
            background-color: #45a049;
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
        }
        
        /* 卡片悬停效果 */
        .card {
            width: 200px;
            padding: 20px;
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
            transition: all 0.3s ease;
            display: inline-block;
            margin: 10px;
        }
        
        .card:hover {
            transform: translateY(-10px);
            box-shadow: 0 10px 20px rgba(0,0,0,0.2);
        }
        
        /* 图片放大效果 */
        .image-container {
            width: 200px;
            height: 150px;
            overflow: hidden;
            border-radius: 8px;
            display: inline-block;
            margin: 10px;
        }
        
        .image-container img {
            width: 100%;
            height: 100%;
            object-fit: cover;
            transition: transform 0.5s ease;
        }
        
        .image-container:hover img {
            transform: scale(1.1);
        }
        
        /* 展开菜单 */
        .menu {
            width: 200px;
        }
        
        .menu-item {
            padding: 10px 15px;
            background-color: #f5f5f5;
            border-bottom: 1px solid #ddd;
            cursor: pointer;
            transition: all 0.3s ease;
        }
        
        .menu-item:hover {
            background-color: #4CAF50;
            color: white;
            padding-left: 25px;
        }
        
        /* 输入框聚焦效果 */
        .input-group {
            margin: 10px;
        }
        
        .input-group input {
            padding: 10px;
            border: 2px solid #ddd;
            border-radius: 4px;
            font-size: 16px;
            transition: all 0.3s ease;
        }
        
        .input-group input:focus {
            outline: none;
            border-color: #4CAF50;
            box-shadow: 0 0 10px rgba(76, 175, 80, 0.3);
        }
    </style>
</head>
<body>
    <h3>按钮效果</h3>
    <button class="btn">悬停查看效果</button>
    
    <h3>卡片效果</h3>
    <div class="card">
        <h4>卡片标题</h4>
        <p>悬停查看效果</p>
    </div>
    
    <h3>图片放大</h3>
    <div class="image-container">
        <img src="https://picsum.photos/200/150" alt="图片">
    </div>
    
    <h3>菜单效果</h3>
    <div class="menu">
        <div class="menu-item">首页</div>
        <div class="menu-item">产品</div>
        <div class="menu-item">关于</div>
        <div class="menu-item">联系</div>
    </div>
    
    <h3>输入框效果</h3>
    <div class="input-group">
        <input type="text" placeholder="点击聚焦查看效果">
    </div>
</body>
</html>

CSS动画(Animation)

动画可以创建更复杂的序列动画效果。

@keyframes规则

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>keyframes规则示例</title>
    <style>
        /* 定义动画 */
        @keyframes change-color {
            /* 起始状态 */
            from {
                background-color: #4CAF50;
            }
            /* 结束状态 */
            to {
                background-color: #2196F3;
            }
        }
        
        /* 使用百分比定义多个关键帧 */
        @keyframes rainbow {
            0% { background-color: red; }
            25% { background-color: yellow; }
            50% { background-color: green; }
            75% { background-color: blue; }
            100% { background-color: purple; }
        }
        
        /* 多属性动画 */
        @keyframes move-and-scale {
            0% {
                transform: translateX(0) scale(1);
                background-color: #4CAF50;
            }
            50% {
                transform: translateX(100px) scale(1.2);
                background-color: #2196F3;
            }
            100% {
                transform: translateX(0) scale(1);
                background-color: #4CAF50;
            }
        }
        
        .box {
            width: 100px;
            height: 100px;
            margin: 20px;
            display: inline-block;
            vertical-align: top;
        }
        
        .anim1 {
            animation: change-color 2s infinite alternate;
        }
        
        .anim2 {
            animation: rainbow 3s infinite;
        }
        
        .anim3 {
            animation: move-and-scale 2s infinite;
        }
    </style>
</head>
<body>
    <div class="box anim1">颜色变化</div>
    <div class="box anim2">彩虹效果</div>
    <div class="box anim3">移动缩放</div>
</body>
</html>

animation属性

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>animation属性示例</title>
    <style>
        @keyframes slide {
            from { transform: translateX(0); }
            to { transform: translateX(200px); }
        }
        
        .box {
            width: 50px;
            height: 50px;
            background-color: #4CAF50;
            margin: 10px;
        }
        
        /* 简写形式 */
        .shorthand {
            /* animation: name duration timing-function delay iteration-count direction fill-mode; */
            animation: slide 2s ease-in-out 0.5s infinite alternate;
        }
        
        /* 分解写法 */
        .detailed {
            animation-name: slide;              /* 动画名称 */
            animation-duration: 2s;             /* 持续时间 */
            animation-timing-function: ease;    /* 时间函数 */
            animation-delay: 0.5s;              /* 延迟时间 */
            animation-iteration-count: infinite; /* 播放次数 */
            animation-direction: alternate;     /* 播放方向 */
            animation-fill-mode: forwards;      /* 填充模式 */
            animation-play-state: running;      /* 播放状态 */
        }
    </style>
</head>
<body>
    <div class="box shorthand">简写形式</div>
    <div class="box detailed">分解写法</div>
</body>
</html>

animation-iteration-count(播放次数)

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>播放次数示例</title>
    <style>
        @keyframes bounce {
            0%, 100% { transform: translateY(0); }
            50% { transform: translateY(-30px); }
        }
        
        .ball {
            width: 50px;
            height: 50px;
            background-color: #4CAF50;
            border-radius: 50%;
            margin: 20px;
            display: inline-block;
            animation: bounce 0.5s ease-in-out;
        }
        
        /* 播放次数 */
        .once { animation-iteration-count: 1; }
        .twice { animation-iteration-count: 2; }
        .three { animation-iteration-count: 3; }
        .infinite { animation-iteration-count: infinite; }
    </style>
</head>
<body>
    <p>刷新页面查看效果:</p>
    <div class="ball once">1次</div>
    <div class="ball twice">2次</div>
    <div class="ball three">3次</div>
    <div class="ball infinite">无限</div>
</body>
</html>

animation-direction(播放方向)

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>播放方向示例</title>
    <style>
        @keyframes move {
            from { transform: translateX(0); }
            to { transform: translateX(200px); }
        }
        
        .box {
            width: 50px;
            height: 50px;
            background-color: #4CAF50;
            margin: 10px;
            animation: move 1s infinite;
        }
        
        /* 正常播放 */
        .normal { animation-direction: normal; }
        
        /* 反向播放 */
        .reverse { animation-direction: reverse; }
        
        /* 先正向再反向 */
        .alternate { animation-direction: alternate; }
        
        /* 先反向再正向 */
        .alternate-reverse { animation-direction: alternate-reverse; }
    </style>
</head>
<body>
    <div class="box normal">normal</div>
    <div class="box reverse">reverse</div>
    <div class="box alternate">alternate</div>
    <div class="box alternate-reverse">alternate-reverse</div>
</body>
</html>

animation-fill-mode(填充模式)

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>填充模式示例</title>
    <style>
        @keyframes fade {
            from { 
                opacity: 0;
                transform: scale(0.5);
            }
            to { 
                opacity: 1;
                transform: scale(1);
            }
        }
        
        .box {
            width: 100px;
            height: 100px;
            background-color: #4CAF50;
            margin: 20px;
            display: inline-block;
            opacity: 0.5;
            animation: fade 2s forwards;
        }
        
        /* 动画前后保持默认样式 */
        .none { animation-fill-mode: none; }
        
        /* 动画结束后保持最后一帧 */
        .forwards { animation-fill-mode: forwards; }
        
        /* 动画开始前应用第一帧 */
        .backwards { animation-fill-mode: backwards; animation-delay: 1s; }
        
        /* 同时应用forwards和backwards */
        .both { animation-fill-mode: both; animation-delay: 1s; }
    </style>
</head>
<body>
    <p>刷新页面查看效果:</p>
    <div class="box none">none</div>
    <div class="box forwards">forwards</div>
    <div class="box backwards">backwards</div>
    <div class="box both">both</div>
</body>
</html>

animation-play-state(播放状态)

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>播放状态示例</title>
    <style>
        @keyframes spin {
            from { transform: rotate(0deg); }
            to { transform: rotate(360deg); }
        }
        
        .spinner {
            width: 50px;
            height: 50px;
            background-color: #4CAF50;
            margin: 20px;
            animation: spin 2s linear infinite;
            animation-play-state: paused;  /* 默认暂停 */
        }
        
        .spinner:hover {
            animation-play-state: running;  /* 悬停时播放 */
        }
        
        /* 控制按钮 */
        .controls {
            margin: 20px;
        }
        
        .btn {
            padding: 10px 20px;
            background-color: #2196F3;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            margin-right: 10px;
        }
    </style>
</head>
<body>
    <p>悬停查看动画:</p>
    <div class="spinner"></div>
    
    <div class="controls">
        <button class="btn" onclick="document.querySelector('.spinner').style.animationPlayState='running'">播放</button>
        <button class="btn" onclick="document.querySelector('.spinner').style.animationPlayState='paused'">暂停</button>
    </div>
</body>
</html>

动画示例

加载动画

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>加载动画示例</title>
    <style>
        /* 旋转加载 */
        .spinner {
            width: 40px;
            height: 40px;
            border: 4px solid #f3f3f3;
            border-top: 4px solid #3498db;
            border-radius: 50%;
            animation: spin 1s linear infinite;
            margin: 20px;
            display: inline-block;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        /* 脉冲加载 */
        .pulse {
            width: 40px;
            height: 40px;
            background-color: #3498db;
            border-radius: 50%;
            animation: pulse 1.5s ease-in-out infinite;
            margin: 20px;
            display: inline-block;
        }
        
        @keyframes pulse {
            0% { transform: scale(0.8); opacity: 1; }
            50% { transform: scale(1.2); opacity: 0.5; }
            100% { transform: scale(0.8); opacity: 1; }
        }
        
        /* 跳动点 */
        .dots {
            display: inline-flex;
            gap: 8px;
            margin: 20px;
        }
        
        .dot {
            width: 12px;
            height: 12px;
            background-color: #3498db;
            border-radius: 50%;
            animation: bounce 1.4s ease-in-out infinite;
        }
        
        .dot:nth-child(1) { animation-delay: 0s; }
        .dot:nth-child(2) { animation-delay: 0.2s; }
        .dot:nth-child(3) { animation-delay: 0.4s; }
        
        @keyframes bounce {
            0%, 80%, 100% { transform: scale(0); }
            40% { transform: scale(1); }
        }
        
        /* 进度条 */
        .progress-bar {
            width: 200px;
            height: 4px;
            background-color: #f3f3f3;
            border-radius: 2px;
            overflow: hidden;
            margin: 20px;
        }
        
        .progress {
            height: 100%;
            background: linear-gradient(90deg, #3498db, #2ecc71);
            animation: progress 2s ease-in-out infinite;
        }
        
        @keyframes progress {
            0% { width: 0%; }
            50% { width: 100%; }
            100% { width: 0%; }
        }
    </style>
</head>
<body>
    <h3>旋转加载</h3>
    <div class="spinner"></div>
    
    <h3>脉冲加载</h3>
    <div class="pulse"></div>
    
    <h3>跳动点</h3>
    <div class="dots">
        <div class="dot"></div>
        <div class="dot"></div>
        <div class="dot"></div>
    </div>
    
    <h3>进度条</h3>
    <div class="progress-bar">
        <div class="progress"></div>
    </div>
</body>
</html>

文字动画

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>文字动画示例</title>
    <style>
        /* 打字机效果 */
        .typewriter {
            overflow: hidden;
            border-right: 3px solid #333;
            white-space: nowrap;
            animation: 
                typing 3.5s steps(20) infinite,
                blink-caret 0.75s step-end infinite;
        }
        
        @keyframes typing {
            0%, 100% { width: 0; }
            50% { width: 100%; }
        }
        
        @keyframes blink-caret {
            from, to { border-color: transparent; }
            50% { border-color: #333; }
        }
        
        /* 闪烁文字 */
        .blink {
            animation: blink 1s step-start infinite;
        }
        
        @keyframes blink {
            50% { opacity: 0; }
        }
        
        /* 彩虹文字 */
        .rainbow {
            background: linear-gradient(90deg, 
                #ff0000, #ff7f00, #ffff00, 
                #00ff00, #0000ff, #4b0082, #8f00ff);
            background-size: 400% 100%;
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            animation: rainbow 3s linear infinite;
            font-size: 24px;
            font-weight: bold;
        }
        
        @keyframes rainbow {
            0% { background-position: 0% 50%; }
            100% { background-position: 400% 50%; }
        }
        
        /* 弹跳文字 */
        .bounce-text span {
            display: inline-block;
            animation: bounce 0.5s ease infinite;
        }
        
        .bounce-text span:nth-child(2) { animation-delay: 0.1s; }
        .bounce-text span:nth-child(3) { animation-delay: 0.2s; }
        .bounce-text span:nth-child(4) { animation-delay: 0.3s; }
        .bounce-text span:nth-child(5) { animation-delay: 0.4s; }
        
        @keyframes bounce {
            0%, 100% { transform: translateY(0); }
            50% { transform: translateY(-10px); }
        }
        
        /* 淡入文字 */
        .fade-in {
            animation: fadeIn 2s ease-in-out infinite;
        }
        
        @keyframes fadeIn {
            0%, 100% { opacity: 0; }
            50% { opacity: 1; }
        }
    </style>
</head>
<body>
    <h3>打字机效果</h3>
    <p class="typewriter">这是打字机效果示例文字</p>
    
    <h3>闪烁文字</h3>
    <p class="blink">这是闪烁的文字</p>
    
    <h3>彩虹文字</h3>
    <p class="rainbow">彩虹渐变文字效果</p>
    
    <h3>弹跳文字</h3>
    <p class="bounce-text">
        <span>弹</span>
        <span>跳</span>
        <span>文</span>
        <span>字</span>
        <span>~</span>
    </p>
    
    <h3>淡入淡出</h3>
    <p class="fade-in">淡入淡出效果</p>
</body>
</html>

交互动画

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>交互动画示例</title>
    <style>
        .container {
            padding: 20px;
        }
        
        /* 心跳动画 */
        .heart {
            width: 50px;
            height: 50px;
            background-color: #e74c3c;
            transform: rotate(-45deg);
            margin: 50px;
            cursor: pointer;
            animation: heartbeat 1s ease-in-out infinite;
        }
        
        .heart::before,
        .heart::after {
            content: "";
            width: 50px;
            height: 50px;
            background-color: #e74c3c;
            border-radius: 50%;
            position: absolute;
        }
        
        .heart::before {
            top: -25px;
            left: 0;
        }
        
        .heart::after {
            left: 25px;
            top: 0;
        }
        
        @keyframes heartbeat {
            0%, 100% { transform: rotate(-45deg) scale(1); }
            50% { transform: rotate(-45deg) scale(1.1); }
        }
        
        .heart:hover {
            animation: heartbeat 0.5s ease-in-out infinite;
        }
        
        /* 摇晃动画 */
        .shake {
            width: 100px;
            height: 100px;
            background-color: #3498db;
            margin: 20px;
            display: inline-block;
            cursor: pointer;
        }
        
        .shake:hover {
            animation: shake 0.5s ease-in-out;
        }
        
        @keyframes shake {
            0%, 100% { transform: translateX(0); }
            10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
            20%, 40%, 60%, 80% { transform: translateX(5px); }
        }
        
        /* 翻转卡片 */
        .flip-card {
            width: 200px;
            height: 150px;
            perspective: 1000px;
            margin: 20px;
            display: inline-block;
        }
        
        .flip-card-inner {
            width: 100%;
            height: 100%;
            transition: transform 0.6s;
            transform-style: preserve-3d;
        }
        
        .flip-card:hover .flip-card-inner {
            transform: rotateY(180deg);
        }
        
        .flip-card-front,
        .flip-card-back {
            position: absolute;
            width: 100%;
            height: 100%;
            backface-visibility: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 20px;
            font-weight: bold;
            border-radius: 8px;
        }
        
        .flip-card-front {
            background-color: #3498db;
            color: white;
        }
        
        .flip-card-back {
            background-color: #e74c3c;
            color: white;
            transform: rotateY(180deg);
        }
        
        /* 波纹按钮 */
        .ripple-btn {
            position: relative;
            padding: 15px 30px;
            background-color: #3498db;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            overflow: hidden;
            font-size: 16px;
        }
        
        .ripple-btn::after {
            content: "";
            position: absolute;
            top: 50%;
            left: 50%;
            width: 0;
            height: 0;
            background: rgba(255, 255, 255, 0.3);
            border-radius: 50%;
            transform: translate(-50%, -50%);
            transition: width 0.6s, height 0.6s;
        }
        
        .ripple-btn:active::after {
            width: 300px;
            height: 300px;
        }
    </style>
</head>
<body>
    <h3>心跳动画(悬停加速)</h3>
    <div class="heart"></div>
    
    <h3>摇晃动画(悬停触发)</h3>
    <div class="shake">悬停摇晃</div>
    
    <h3>翻转卡片</h3>
    <div class="flip-card">
        <div class="flip-card-inner">
            <div class="flip-card-front">正面</div>
            <div class="flip-card-back">背面</div>
        </div>
    </div>
    
    <h3>波纹按钮</h3>
    <button class="ripple-btn">点击查看波纹</button>
</body>
</html>

综合示例

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>过渡与动画综合示例</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: Arial, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 40px 20px;
        }
        
        .container {
            max-width: 1000px;
            margin: 0 auto;
        }
        
        /* 卡片样式 */
        .card {
            background: white;
            border-radius: 16px;
            padding: 30px;
            margin-bottom: 30px;
            box-shadow: 0 10px 40px rgba(0,0,0,0.2);
            animation: slideUp 0.6s ease-out;
        }
        
        @keyframes slideUp {
            from {
                opacity: 0;
                transform: translateY(30px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }
        
        .card h2 {
            color: #333;
            margin-bottom: 20px;
        }
        
        /* 动画按钮组 */
        .btn-group {
            display: flex;
            gap: 15px;
            flex-wrap: wrap;
        }
        
        .btn {
            padding: 12px 24px;
            border: none;
            border-radius: 8px;
            font-size: 16px;
            cursor: pointer;
            transition: all 0.3s ease;
        }
        
        .btn-primary {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
        }
        
        .btn-primary:hover {
            transform: translateY(-3px);
            box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4);
        }
        
        .btn-outline {
            background: transparent;
            border: 2px solid #667eea;
            color: #667eea;
        }
        
        .btn-outline:hover {
            background: #667eea;
            color: white;
        }
        
        /* 加载动画展示 */
        .loaders {
            display: flex;
            gap: 30px;
            align-items: center;
            flex-wrap: wrap;
        }
        
        .spinner {
            width: 40px;
            height: 40px;
            border: 4px solid #f3f3f3;
            border-top: 4px solid #667eea;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        .dots {
            display: flex;
            gap: 8px;
        }
        
        .dot {
            width: 12px;
            height: 12px;
            background-color: #667eea;
            border-radius: 50%;
            animation: bounce 1.4s ease-in-out infinite;
        }
        
        .dot:nth-child(1) { animation-delay: 0s; }
        .dot:nth-child(2) { animation-delay: 0.2s; }
        .dot:nth-child(3) { animation-delay: 0.4s; }
        
        @keyframes bounce {
            0%, 80%, 100% { transform: scale(0); }
            40% { transform: scale(1); }
        }
        
        /* 进度条 */
        .progress-container {
            width: 100%;
            max-width: 300px;
        }
        
        .progress-bar {
            height: 8px;
            background-color: #f3f3f3;
            border-radius: 4px;
            overflow: hidden;
        }
        
        .progress-fill {
            height: 100%;
            background: linear-gradient(90deg, #667eea, #764ba2);
            animation: progress 2s ease-in-out infinite;
        }
        
        @keyframes progress {
            0% { width: 0%; }
            50% { width: 100%; }
            100% { width: 0%; }
        }
        
        /* 图片卡片 */
        .image-cards {
            display: flex;
            gap: 20px;
            flex-wrap: wrap;
        }
        
        .image-card {
            width: 200px;
            border-radius: 12px;
            overflow: hidden;
            box-shadow: 0 4px 15px rgba(0,0,0,0.1);
            transition: all 0.3s ease;
        }
        
        .image-card:hover {
            transform: translateY(-10px);
            box-shadow: 0 10px 30px rgba(0,0,0,0.2);
        }
        
        .image-card img {
            width: 100%;
            height: 150px;
            object-fit: cover;
            transition: transform 0.3s ease;
        }
        
        .image-card:hover img {
            transform: scale(1.1);
        }
        
        .image-card .content {
            padding: 15px;
            background: white;
        }
        
        /* 输入框动画 */
        .input-group {
            position: relative;
            margin-bottom: 20px;
        }
        
        .input-group input {
            width: 100%;
            padding: 15px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 16px;
            transition: all 0.3s ease;
        }
        
        .input-group input:focus {
            outline: none;
            border-color: #667eea;
            box-shadow: 0 0 20px rgba(102, 126, 234, 0.3);
        }
        
        .input-group label {
            position: absolute;
            left: 15px;
            top: 50%;
            transform: translateY(-50%);
            color: #999;
            pointer-events: none;
            transition: all 0.3s ease;
            background: white;
            padding: 0 5px;
        }
        
        .input-group input:focus + label,
        .input-group input:not(:placeholder-shown) + label {
            top: 0;
            font-size: 12px;
            color: #667eea;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="card">
            <h2>按钮动画</h2>
            <div class="btn-group">
                <button class="btn btn-primary">主要按钮</button>
                <button class="btn btn-outline">边框按钮</button>
            </div>
        </div>
        
        <div class="card">
            <h2>加载动画</h2>
            <div class="loaders">
                <div class="spinner"></div>
                <div class="dots">
                    <div class="dot"></div>
                    <div class="dot"></div>
                    <div class="dot"></div>
                </div>
                <div class="progress-container">
                    <div class="progress-bar">
                        <div class="progress-fill"></div>
                    </div>
                </div>
            </div>
        </div>
        
        <div class="card">
            <h2>卡片悬停效果</h2>
            <div class="image-cards">
                <div class="image-card">
                    <img src="https://picsum.photos/200/150" alt="图片">
                    <div class="content">
                        <h4>卡片标题</h4>
                        <p>悬停查看效果</p>
                    </div>
                </div>
                <div class="image-card">
                    <img src="https://picsum.photos/200/150?random=2" alt="图片">
                    <div class="content">
                        <h4>另一个卡片</h4>
                        <p>悬停查看效果</p>
                    </div>
                </div>
            </div>
        </div>
        
        <div class="card">
            <h2>输入框动画</h2>
            <div class="input-group">
                <input type="text" placeholder=" ">
                <label>用户名</label>
            </div>
            <div class="input-group">
                <input type="email" placeholder=" ">
                <label>邮箱地址</label>
            </div>
        </div>
    </div>
</body>
</html>

本章小结

本章我们学习了:

  1. CSS过渡:transition-property、transition-duration、transition-timing-function、transition-delay
  2. 时间函数:linear、ease、ease-in、ease-out、ease-in-out、cubic-bezier
  3. CSS动画:@keyframes规则定义动画序列
  4. 动画属性:animation-name、animation-duration、animation-iteration-count、animation-direction、animation-fill-mode
  5. 动画状态:animation-play-state控制播放和暂停
  6. 实用动画:加载动画、文字动画、交互动画

下一章

下一章我们将学习 响应式设计,了解如何适配各种设备和屏幕尺寸。