第10章 CSS3变形、过渡和动画属性

习题解答

🙈 隐藏所有答案

编程题

1. 鼠标指针指向不同方块,单击不松开,出现旋转、放大、倾斜、平移效果,如图 10-25 所示。
图 10-25a 初始状态 图 10-25b 鼠标按下旋转效果

图 10-25 旋转、放大、倾斜、平移效果(左:初始;右:按下后)

这道题用 :active 伪类(鼠标按下不松开时触发)配合 transform 属性实现四种变形效果,再加上 transition 让变形过程平滑。

思路:四个方块分别绑定不同的 transform 函数——rotate()旋转、scale()放大、skew()倾斜、translate()平移。

完整代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>变形效果</title>
    <style>
        /* 公共样式:所有方块 */
        .box {
            display: inline-block;
            width: 120px;
            height: 120px;
            background: #aaa;
            margin: 40px 30px;
            vertical-align: top;
            line-height: 1.4;
            padding: 6px;
            color: #333;
            font-size: 14px;
            /* 过渡:让变形动画平滑 */
            transition: transform 0.3s ease;
            cursor: pointer;
        }

        /* 旋转:按下时顺时针旋转 45 度 */
        .rotate:active  { transform: rotate(45deg); }

        /* 放大:按下时放大 1.4 倍 */
        .scale:active   { transform: scale(1.4); }

        /* 倾斜:按下时沿 X 轴倾斜 20 度 */
        .skew:active    { transform: skewX(20deg); }

        /* 平移:按下时向右下各平移 30px */
        .translate:active { transform: translate(30px, 30px); }
    </style>
</head>
<body>
    <div class="box rotate">旋转</div>
    <div class="box scale">放大</div>
    <div class="box skew">倾斜</div>
    <div class="box translate">平移</div>
</body>
</html>

📖 参见 10.1.2 transform 属性 / 10.2.1 过渡属性

2. 将鼠标放在图片上旋转 180°,显示效果如图 10-26 所示。
图 10-26a 初始状态 图 10-26b 悬停旋转 180°

图 10-26 180° 旋转(左:正常;右:悬停后翻转)

:hover 伪类触发 transform: rotate(180deg),同时设置 transition 让旋转过程有动画效果。图中展示的是一只兔子头像,悬停后上下翻转 180°。

完整代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>图片旋转</title>
    <style>
        body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background: #fff; }

        img {
            width: 280px;
            height: 280px;
            border-radius: 50%;          /* 圆形裁切 */
            display: block;
            /* 过渡:旋转用 0.8s,缓入缓出 */
            transition: transform 0.8s ease-in-out;
            cursor: pointer;
        }

        /* 鼠标悬停:旋转 180 度 */
        img:hover {
            transform: rotate(180deg);
        }
    </style>
</head>
<body>
    <!-- 替换 src 为实际图片路径 -->
    <img src="images/rabbit.png" alt="兔子头像">
</body>
</html>

📖 参见 10.1.2 transform 属性(rotate 函数)/ 10.2.1 过渡属性

3. 将鼠标移动到图片上,该图片 360° 旋转,如图 10-27 所示。
图 10-27 360° 旋转

图 10-27 360° 旋转

这题和上一题的区别:旋转角度是 360°(转一整圈回到原位),悬停时元素看起来"原地转一圈"。图中是一个带"旋转"文字的灰色方块。

关键点:transition 持续时间要足够长,旋转才看得清楚。

完整代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>css制作旋转图片</title>
    <style>
        body { display: flex; justify-content: center; padding: 60px; }

        .outer {
            width: 200px;
            height: 200px;
            background: #ddd;
            padding: 20px;
        }

        .inner {
            width: 160px;
            height: 160px;
            background: #888;
            line-height: 160px;
            text-align: center;
            color: #fff;
            font-size: 18px;
            /* 过渡:1s 匀速旋转 */
            transition: transform 1s linear;
            cursor: pointer;
        }

        /* 悬停旋转一整圈(360 度) */
        .inner:hover {
            transform: rotate(360deg);
        }
    </style>
</head>
<body>
    <div class="outer">
        <div class="inner">旋转</div>
    </div>
</body>
</html>

📖 参见 10.1.2 transform 属性(rotate 函数)/ 10.2.1 过渡属性

4. 实现图片正反面旋转,如图 10-28 所示。
图 10-28a 背面(扑克牌背面花纹) 图 10-28b 正面(黑桃A)

图 10-28 图片反转(左:背面;右:鼠标悬停后正面)

这是经典的"翻牌"效果,需要三个关键技术配合:

  1. transform-style: preserve-3d —— 让子元素保持 3D 空间
  2. backface-visibility: hidden —— 背面不可见(翻过去就看不到了)
  3. rotateY(180deg) —— 初始让正面藏在背后,悬停时容器翻转

完整代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>图片正反面旋转</title>
    <style>
        body { display: flex; justify-content: center; padding: 40px; }

        /* 容器:定义透视和过渡 */
        .card-container {
            width: 260px;
            height: 380px;
            perspective: 800px;        /* 透视距离,数值越小3D感越强 */
            cursor: pointer;
        }

        /* 卡牌主体:3D 空间翻转 */
        .card {
            width: 100%;
            height: 100%;
            position: relative;
            transform-style: preserve-3d;   /* 子元素保持3D */
            transition: transform 0.8s ease-in-out;
        }

        /* 悬停时翻转 */
        .card-container:hover .card {
            transform: rotateY(180deg);
        }

        /* 正面和背面共同样式 */
        .front, .back {
            position: absolute;
            width: 100%;
            height: 100%;
            backface-visibility: hidden;    /* 背对屏幕时隐藏 */
            border-radius: 8px;
            overflow: hidden;
        }

        /* 背面:扑克牌花纹(初始可见) */
        .back {
            background: #1a1a2e;
            border: 3px solid #ccc;
            /* 用 CSS 模拟扑克背面图案 */
            background-image: repeating-linear-gradient(
                45deg,
                #1a1a2e 0px,
                #1a1a2e 8px,
                #c0392b 8px,
                #c0392b 10px
            );
        }

        /* 正面:初始旋转 180deg(藏在背后) */
        .front {
            transform: rotateY(180deg);
            background: #fff;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 100px;
            border: 3px solid #333;
        }

        /* 如果使用真实图片,取消注释并删除上面的模拟样式 */
        /* .back img, .front img { width: 100%; height: 100%; object-fit: cover; } */
    </style>
</head>
<body>
    <div class="card-container">
        <div class="card">
            <!-- 背面:可替换为 img src="images/card_back.jpg" -->
            <div class="back"></div>
            <!-- 正面:黑桃 A -->
            <div class="front">🂡</div>
        </div>
    </div>
</body>
</html>

📖 参见 10.1.4 transform-style 属性 / 10.1.6 backface-visibility 属性 / 10.2.1 过渡属性

5. 实现平移动画,如图 10-29 所示。
图 10-29a 方块在左侧 图 10-29b 方块在右侧

图 10-29 平移动画(黑色方块从左向右移动)

这道题用 @keyframes + animation 实现自动循环的平移动画。从效果图可以看到:一个深色方块从屏幕左侧移动到右侧,然后循环。

注意和第1题的区别:那题是鼠标触发的 transition 过渡,这题是自动播放的 animation 动画。

完整代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>平移</title>
    <style>
        body { margin: 0; padding: 20px; }

        .block {
            width: 120px;
            height: 120px;
            background: #222;           /* 深色方块 */
            color: #fff;
            line-height: 120px;
            text-align: center;
            font-size: 14px;
            position: relative;
            /* 绑定动画:名称 持续时间 速度曲线 循环次数 */
            animation: moveRight 2s linear infinite alternate;
        }

        /* 定义平移关键帧:从左边 0 移动到右边 */
        @keyframes moveRight {
            from { left: 0px; }
            to   { left: calc(100vw - 160px); } /* 移动到靠近右侧 */
        }
    </style>
</head>
<body>
    <div class="block">鼠标指向则平移</div>
</body>
</html>

📖 参见 10.3.1 动画属性(@keyframes / animation)

6. transition 图片旋转,使用 6 张图片旋转,如图 10-30 所示。
图 10-30 6张图片旋转散开效果

图 10-30 6张图片旋转(悬停后以中心点为原点向四周散开)

这道题和教材例10-7(扑克牌散开)很相似!6张图片叠放在同一位置,鼠标悬停时分别旋转到不同角度散开。

关键技术:transform-origin: top right(以右上角为旋转原点),配合 transition 实现平滑旋转展开效果。

完整代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>旋转练习</title>
    <style>
        body { background: #fff; }

        /* 容器:相对定位,让图片叠放 */
        #container {
            width: 200px;
            height: 150px;
            margin: 180px auto;
            position: relative;
        }

        img {
            width: 160px;
            height: 120px;
            position: absolute;
            border: 3px solid #fff;
            box-shadow: 0 2px 8px rgba(0,0,0,0.3);
            /* 旋转原点:右上角(和教材示例一致) */
            transform-origin: top right;
            /* 过渡:旋转动画 0.6s */
            transition: transform 0.6s ease-in-out;
            object-fit: cover;
        }

        /* 悬停时 6 张图分别旋转到不同角度 */
        #container:hover img:nth-of-type(1) { transform: rotate(-60deg);  }
        #container:hover img:nth-of-type(2) { transform: rotate(-120deg); }
        #container:hover img:nth-of-type(3) { transform: rotate(-180deg); }
        #container:hover img:nth-of-type(4) { transform: rotate(-240deg); }
        #container:hover img:nth-of-type(5) { transform: rotate(-300deg); }
        #container:hover img:nth-of-type(6) { transform: rotate(-360deg); }
    </style>
</head>
<body>
    <div id="container">
        <!-- 替换为实际风景图片路径 -->
        <img src="images/pic1.jpg" alt="">
        <img src="images/pic2.jpg" alt="">
        <img src="images/pic3.jpg" alt="">
        <img src="images/pic4.jpg" alt="">
        <img src="images/pic5.jpg" alt="">
        <img src="images/pic6.jpg" alt="">
    </div>
</body>
</html>

📖 参见 10.1.3 transform-origin 属性 / 10.2.1 过渡属性(例 10-7)

7. 多张图片实现 3D 旋转效果,如图 10-31 所示。
图 10-31 3D 旋转效果

图 10-31 3D 旋转效果(图片排列成圆柱形旋转木马)

这是一个"旋转木马"(Carousel)效果。多张图片均匀分布在一个圆柱体的表面,用 @keyframes 让整个容器持续旋转。

核心思路:每张图片用 rotateY(n * 角度) translateZ(半径) 定位到圆柱面上,再让容器整体绕 Y 轴旋转。

完整代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>3D旋转</title>
    <style>
        body {
            background: #111;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            overflow: hidden;
        }

        /* 透视包裹层 */
        .scene {
            perspective: 800px;
        }

        /* 旋转容器:preserve-3d 让子元素保持3D位置 */
        .carousel {
            width: 200px;
            height: 150px;
            position: relative;
            transform-style: preserve-3d;
            /* 无限旋转动画,8s一圈 */
            animation: spin 8s linear infinite;
        }

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

        /* 每张图片 */
        .carousel img {
            position: absolute;
            width: 200px;
            height: 150px;
            border: 2px solid rgba(255,255,255,0.5);
            object-fit: cover;
            opacity: 0.85;
        }

        /* 8 张图均匀分布:每张间隔 360/8 = 45 度,translateZ 控制半径 */
        .carousel img:nth-child(1)  { transform: rotateY(  0deg) translateZ(300px); }
        .carousel img:nth-child(2)  { transform: rotateY( 45deg) translateZ(300px); }
        .carousel img:nth-child(3)  { transform: rotateY( 90deg) translateZ(300px); }
        .carousel img:nth-child(4)  { transform: rotateY(135deg) translateZ(300px); }
        .carousel img:nth-child(5)  { transform: rotateY(180deg) translateZ(300px); }
        .carousel img:nth-child(6)  { transform: rotateY(225deg) translateZ(300px); }
        .carousel img:nth-child(7)  { transform: rotateY(270deg) translateZ(300px); }
        .carousel img:nth-child(8)  { transform: rotateY(315deg) translateZ(300px); }
    </style>
</head>
<body>
    <div class="scene">
        <div class="carousel">
            <!-- 替换为实际风景图片 -->
            <img src="images/s1.jpg" alt="">
            <img src="images/s2.jpg" alt="">
            <img src="images/s3.jpg" alt="">
            <img src="images/s4.jpg" alt="">
            <img src="images/s5.jpg" alt="">
            <img src="images/s6.jpg" alt="">
            <img src="images/s7.jpg" alt="">
            <img src="images/s8.jpg" alt="">
        </div>
    </div>
</body>
</html>

📖 参见 10.1.2 transform 属性(3D变形函数)/ 10.1.4 transform-style / 10.1.5 perspective / 10.3.1 动画属性

8. transform-style 属性的应用,使被转换的子元素保留其 3D 转换,如图 10-32 所示。
图 10-32 3D 转换效果

图 10-32 3D 转换(父元素旋转,子元素保持3D空间)

这道题演示 transform-style: preserve-3d 的效果。从效果图可以看到:外框内有两个矩形(深色"HELLO"和浅色"YELLOW"),它们在3D空间中错落排列,呈现出立体感。

关键区别:

  • transform-style: flat(默认)—— 子元素压平在父元素平面上,看不到3D效果
  • transform-style: preserve-3d —— 子元素保留各自的3D位置,能看到真实的空间关系

完整代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>transform-style属性</title>
    <style>
        body { display: flex; justify-content: center; padding: 40px; }

        /* 外框 */
        .wrapper {
            width: 300px;
            height: 300px;
            border: 1px solid #999;
            position: relative;
            /* 设置透视:让3D效果可见 */
            perspective: 500px;
            /* preserve-3d:子元素保留各自3D变换 */
            transform-style: preserve-3d;
        }

        /* 子元素基础样式 */
        .box {
            position: absolute;
            width: 140px;
            height: 100px;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 18px;
            font-weight: bold;
        }

        /* 深色块:HELLO,沿X轴旋转,位于左上角 */
        .hello {
            background: #333;
            color: #fff;
            top: 40px;
            left: 30px;
            /* 沿X轴旋转 -20 度,产生3D透视感 */
            transform: rotateX(-20deg) rotateY(15deg);
        }

        /* 浅色块:YELLOW,沿Y轴旋转,位于右下角,文字翻转 */
        .yellow {
            background: #e8e8e8;
            color: #333;
            top: 150px;
            left: 100px;
            /* 沿Y轴旋转 180 度,文字反显 */
            transform: rotateY(180deg) rotateX(-20deg);
        }
    </style>
</head>
<body>
    <div class="wrapper">
        <div class="box hello">HELLO</div>
        <div class="box yellow">YELLOW</div>
    </div>
</body>
</html>

📖 参见 10.1.4 transform-style 属性 / 10.1.5 perspective 属性(例 10-8)