MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

CSS动画与过渡的实现:从基础属性到关键帧动画的进阶

2021-08-136.0k 阅读

CSS 动画与过渡的实现:从基础属性到关键帧动画的进阶

一、CSS 过渡(Transitions)

CSS 过渡是一种在 CSS 属性值发生变化时,实现平滑过渡效果的方式。它允许元素在两个状态之间进行平滑的动画过渡,而不需要使用 JavaScript。过渡的常见应用场景包括悬停效果、切换状态等。

1.1 过渡的基本属性

  • transition-property:指定要过渡的 CSS 属性。可以是单个属性,如 widthcolor,也可以是多个属性,用逗号分隔,如 width, color。还可以使用 all 表示所有可过渡的属性。例如:
.box {
    transition-property: width;
}
  • transition-duration:指定过渡效果持续的时间,单位为秒(s)或毫秒(ms)。例如:
.box {
    transition-duration: 0.5s;
}
  • transition-timing-function:定义过渡的时间函数,决定过渡的速度变化方式。常见的值有:
    • ease:默认值,慢速开始,然后变快,最后慢速结束。
    • linear:匀速过渡。
    • ease - in:慢速开始。
    • ease - out:慢速结束。
    • ease - in - out:慢速开始和结束。
    • cubic - bezier(n,n,n,n):通过贝塞尔曲线自定义过渡效果。例如:
.box {
    transition-timing-function: ease - in - out;
}
  • transition-delay:指定过渡效果开始前的延迟时间,单位同样为秒(s)或毫秒(ms)。例如:
.box {
    transition-delay: 0.2s;
}

1.2 复合属性 transition

为了方便设置,CSS 提供了 transition 复合属性,它允许在一个声明中设置多个过渡相关属性。语法如下:

transition: property duration timing - function delay;

例如,要对一个元素的 widthbackground - color 属性设置过渡效果,可以这样写:

.box {
    transition: width 0.5s ease - in - out 0.2s, background - color 0.3s linear;
}

1.3 过渡的触发

过渡通常在元素的状态发生变化时触发,比如 :hover:focus:active 等伪类,或者通过 JavaScript 动态改变元素的类名来触发。以下是一个 :hover 触发过渡的示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF - 8">
    <meta name="viewport" content="width=device - width, initial - scale=1.0">
    <style>
        .box {
            width: 100px;
            height: 100px;
            background - color: lightblue;
            transition: width 0.5s ease - in - out, background - color 0.3s linear;
        }

        .box:hover {
            width: 200px;
            background - color: lightgreen;
        }
    </style>
</head>

<body>
    <div class="box"></div>
</body>

</html>

在上述代码中,当鼠标悬停在 .box 元素上时,width 属性会在 0.5 秒内以 ease - in - out 的时间函数过渡到 200px,background - color 属性会在 0.3 秒内以 linear 的时间函数过渡到 lightgreen

二、CSS 动画(Animations)

CSS 动画相比过渡更加灵活和强大,它可以通过定义关键帧(keyframes)来创建复杂的动画序列。动画可以包含多个阶段,每个阶段可以设置不同的属性值,实现更为丰富的动画效果。

2.1 关键帧(Keyframes)的定义

关键帧使用 @keyframes 规则来定义。语法如下:

@keyframes animation - name {
    from {
        property1: value1;
        property2: value2;
    }
    to {
        property1: value3;
        property2: value4;
    }
}

或者使用百分比来定义关键帧:

@keyframes animation - name {
    0% {
        property1: value1;
        property2: value2;
    }
    50% {
        property1: value5;
        property2: value6;
    }
    100% {
        property1: value3;
        property2: value4;
    }
}

0% 等同于 from,表示动画的起始状态;100% 等同于 to,表示动画的结束状态。中间的百分比表示动画过程中的过渡状态。例如,定义一个使元素从左到右移动的关键帧动画:

@keyframes move - right {
    from {
        transform: translateX(0);
    }
    to {
        transform: translateX(200px);
    }
}

2.2 应用动画到元素

使用 animation 属性将定义好的动画应用到元素上。animation 也是一个复合属性,语法如下:

animation: name duration timing - function delay iteration - count direction fill - mode;
  • animation - name:指定要应用的动画名称,即 @keyframes 定义的名称。
  • animation - duration:动画持续的时间,单位为秒(s)或毫秒(ms)。
  • animation - timing - function:与过渡中的 transition - timing - function 类似,定义动画的时间函数。
  • animation - delay:动画开始前的延迟时间。
  • animation - iteration - count:定义动画播放的次数。可以是具体的数字,也可以是 infinite 表示无限循环播放。
  • animation - direction:定义动画的播放方向。常见值有:
    • normal:默认值,动画正常播放,从起始关键帧到结束关键帧。
    • reverse:动画反向播放,从结束关键帧到起始关键帧。
    • alternate:动画在奇数次播放时正常播放,偶数次播放时反向播放。
    • alternate - reverse:动画在奇数次播放时反向播放,偶数次播放时正常播放。
  • animation - fill - mode:定义动画在播放之前和之后如何应用样式。常见值有:
    • none:默认值,动画在不播放时不应用任何样式。
    • forwards:动画结束后,元素保留最后一帧的样式。
    • backwards:动画开始前,元素应用第一帧的样式。
    • both:同时具有 forwardsbackwards 的效果。

以下是一个应用动画的完整示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF - 8">
    <meta name="viewport" content="width=device - width, initial - scale=1.0">
    <style>
        .box {
            width: 100px;
            height: 100px;
            background - color: lightblue;
            animation: move - right 2s ease - in - out 0s infinite alternate forwards;
        }

        @keyframes move - right {
            from {
                transform: translateX(0);
            }
            to {
                transform: translateX(200px);
            }
        }
    </style>
</head>

<body>
    <div class="box"></div>
</body>

</html>

在这个例子中,.box 元素会在 2 秒内以 ease - in - out 的时间函数从左向右移动 200px,动画无限循环且每次播放方向交替,动画结束后元素保留最后一帧的位置(即向右移动 200px 后的位置)。

2.3 动画的单个属性设置

除了使用复合属性 animation,也可以分别设置动画的各个属性。例如:

.box {
    animation - name: move - right;
    animation - duration: 2s;
    animation - timing - function: ease - in - out;
    animation - delay: 0s;
    animation - iteration - count: infinite;
    animation - direction: alternate;
    animation - fill - mode: forwards;
}

这样设置与使用复合属性 animation 的效果是一样的,但单个属性设置在某些情况下更便于灵活调整。

三、动画与过渡的应用场景及技巧

3.1 导航栏悬停效果

在导航栏中,过渡常用于实现菜单项悬停时的平滑样式变化,如背景颜色、文字颜色、下划线等。例如:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF - 8">
    <meta name="viewport" content="width=device - width, initial - scale=1.0">
    <style>
        nav ul {
            list - style - type: none;
            margin: 0;
            padding: 0;
        }

        nav ul li {
            display: inline - block;
            margin - right: 20px;
        }

        nav ul li a {
            text - decoration: none;
            color: #333;
            transition: color 0.3s ease - in - out, border - bottom 0.3s ease - in - out;
        }

        nav ul li a:hover {
            color: #007BFF;
            border - bottom: 2px solid #007BFF;
        }
    </style>
</head>

<body>
    <nav>
        <ul>
            <li><a href="#">首页</a></li>
            <li><a href="#">关于我们</a></li>
            <li><a href="#">产品</a></li>
        </ul>
    </nav>
</body>

</html>

当鼠标悬停在导航菜单项上时,文字颜色和下划线会在 0.3 秒内以 ease - in - out 的时间函数进行平滑过渡。

3.2 加载动画

动画在加载场景中应用广泛。例如,通过关键帧动画创建一个旋转的加载图标:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF - 8">
    <meta name="viewport" content="width=device - width, initial - scale=1.0">
    <style>
        .loading {
            width: 50px;
            height: 50px;
            border: 5px solid rgba(0, 123, 255, 0.5);
            border - top - color: #007BFF;
            border - radius: 50%;
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            to {
                transform: rotate(360deg);
            }
        }
    </style>
</head>

<body>
    <div class="loading"></div>
</body>

</html>

上述代码中,.loading 元素通过 animation 属性应用了名为 spin 的关键帧动画,实现了一个不断旋转的加载图标效果。

3.3 动画与过渡的性能优化

在使用动画和过渡时,性能优化至关重要。以下是一些优化技巧:

  • 使用硬件加速:通过 transformopacity 属性进行动画和过渡,因为现代浏览器可以利用 GPU 对这两个属性进行硬件加速,从而提高性能。例如,避免使用 lefttop 等属性来移动元素,而是使用 transform: translateX()transform: translateY()
  • 减少动画复杂性:避免在一个元素上同时应用过多复杂的动画,尽量简化关键帧和动画属性,以减少浏览器的计算负担。
  • 合理设置动画时间:不要设置过长或过短的动画时间。过长的动画可能导致用户等待不耐烦,过短的动画可能让用户无法清晰感知。根据实际场景和用户体验来合理调整动画时间。
  • 预加载资源:如果动画涉及到图片等资源,确保这些资源提前加载,避免在动画播放过程中出现卡顿。

四、响应式设计中的动画与过渡

在响应式设计中,动画和过渡同样起着重要作用。不同屏幕尺寸下,动画和过渡效果需要进行相应的调整,以提供一致且良好的用户体验。

4.1 媒体查询与动画过渡结合

通过媒体查询,可以根据不同的屏幕宽度、高度等条件,为元素应用不同的动画和过渡效果。例如,在大屏幕上,导航栏菜单项可以有更丰富的过渡效果,而在小屏幕上,为了避免性能问题,过渡效果可以简化。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF - 8">
    <meta name="viewport" content="width=device - width, initial - scale=1.0">
    <style>
        nav ul {
            list - style - type: none;
            margin: 0;
            padding: 0;
        }

        nav ul li {
            display: inline - block;
            margin - right: 20px;
        }

        nav ul li a {
            text - decoration: none;
            color: #333;
        }

        @media (min - width: 768px) {
            nav ul li a {
                transition: color 0.3s ease - in - out, border - bottom 0.3s ease - in - out;
            }

            nav ul li a:hover {
                color: #007BFF;
                border - bottom: 2px solid #007BFF;
            }
        }
    </style>
</head>

<body>
    <nav>
        <ul>
            <li><a href="#">首页</a></li>
            <li><a href="#">关于我们</a></li>
            <li><a href="#">产品</a></li>
        </ul>
    </nav>
</body>

</html>

在上述代码中,只有当屏幕宽度大于等于 768px 时,导航菜单项才会应用过渡效果。在小屏幕上,由于性能和交互方式的考虑,没有应用过渡效果。

4.2 适配不同设备的动画性能

在移动设备上,由于硬件性能相对较弱,需要更加关注动画的性能。避免使用过于复杂的关键帧动画和大量的动画元素,尽量使用简单的过渡效果和硬件加速属性。同时,可以根据设备的性能,通过媒体查询动态调整动画的持续时间、帧数等参数。例如:

@media (max - width: 480px) {
    .box {
        animation - duration: 1s;
    }
}

在宽度小于等于 480px 的屏幕上,.box 元素的动画持续时间会被调整为 1 秒,以适应移动设备相对较弱的性能,保证动画的流畅性。

五、与 JavaScript 的交互

虽然 CSS 动画和过渡可以实现很多出色的效果,但在某些情况下,需要与 JavaScript 进行交互,以实现更复杂的功能。

5.1 动态控制动画

通过 JavaScript 可以动态控制动画的播放、暂停、停止等状态。例如,可以使用 element.style.animationPlayState 属性来控制动画的播放状态。以下是一个简单的示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF - 8">
    <meta name="viewport" content="width=device - width, initial - scale=1.0">
    <style>
        .box {
            width: 100px;
            height: 100px;
            background - color: lightblue;
            animation: move - right 2s ease - in - out infinite;
        }

        @keyframes move - right {
            from {
                transform: translateX(0);
            }
            to {
                transform: translateX(200px);
            }
        }
    </style>
</head>

<body>
    <div class="box" id="myBox"></div>
    <button onclick="pauseAnimation()">暂停动画</button>
    <script>
        function pauseAnimation() {
            var box = document.getElementById('myBox');
            box.style.animationPlayState = 'paused';
        }
    </script>
</body>

</html>

当点击按钮时,通过 JavaScript 获取 .box 元素,并将其 animationPlayState 属性设置为 paused,从而暂停动画。

5.2 根据用户交互触发动画

JavaScript 可以根据用户的各种交互事件,如点击、滚动等,触发相应的 CSS 动画。例如,当用户滚动到页面特定位置时,触发元素的动画效果:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF - 8">
    <meta name="viewport" content="width=device - width, initial - scale=1.0">
    <style>
        .box {
            width: 100px;
            height: 100px;
            background - color: lightblue;
            transform: translateY(100px);
            opacity: 0;
            transition: transform 1s ease - in - out, opacity 1s ease - in - out;
        }

        .active {
            transform: translateY(0);
            opacity: 1;
        }
    </style>
</head>

<body>
    <div class="box" id="myBox"></div>
    <script>
        window.addEventListener('scroll', function () {
            var box = document.getElementById('myBox');
            var windowHeight = window.innerHeight;
            var boxTop = box.getBoundingClientRect().top;
            if (boxTop < windowHeight) {
                box.classList.add('active');
            }
        });
    </script>
</body>

</html>

在上述代码中,页面滚动时,通过 JavaScript 检查 .box 元素是否进入视口,如果进入视口,则为其添加 active 类,从而触发 transformopacity 属性的过渡效果,使元素从隐藏状态平滑过渡到可见状态。

六、浏览器兼容性

在使用 CSS 动画和过渡时,需要考虑浏览器兼容性问题。虽然现代浏览器对 CSS 动画和过渡的支持已经比较良好,但仍有一些旧版本浏览器存在兼容性差异。

6.1 前缀

为了确保在不同浏览器中都能正常显示动画和过渡效果,需要使用浏览器前缀。常见的浏览器前缀有:

  • -webkit -:用于 Safari、Chrome 等 WebKit 内核浏览器。
  • -moz -:用于 Firefox 浏览器。
  • -ms -:用于 Internet Explorer 和 Edge 浏览器(旧版本)。
  • -o -:用于 Opera 浏览器(旧版本)。

例如,对于 transition 属性,需要这样写以兼容不同浏览器:

.box {
    -webkit - transition: width 0.5s ease - in - out;
    -moz - transition: width 0.5s ease - in - out;
    -ms - transition: width 0.5s ease - in - out;
    -o - transition: width 0.5s ease - in - out;
    transition: width 0.5s ease - in - out;
}

对于 @keyframes 定义的动画,同样需要添加前缀:

@-webkit - keyframes move - right {
    from {
        -webkit - transform: translateX(0);
    }
    to {
        -webkit - transform: translateX(200px);
    }
}

@-moz - keyframes move - right {
    from {
        -moz - transform: translateX(0);
    }
    to {
        -moz - transform: translateX(200px);
    }
}

@-ms - keyframes move - right {
    from {
        -ms - transform: translateX(0);
    }
    to {
        -ms - transform: translateX(200px);
    }
}

@-o - keyframes move - right {
    from {
        -o - transform: translateX(0);
    }
    to {
        -o - transform: translateX(200px);
    }
}

@keyframes move - right {
    from {
        transform: translateX(0);
    }
    to {
        transform: translateX(200px);
    }
}

6.2 检测支持性

可以使用 JavaScript 来检测浏览器是否支持 CSS 动画和过渡。例如,检测 transition 属性的支持性:

function isTransitionSupported() {
    var el = document.createElement('div');
    var transitions = {
        'transition': 'transitionend',
        '-webkit - transition': 'webkitTransitionEnd',
        '-moz - transition':'mozTransitionEnd',
        '-ms - transition':'msTransitionEnd',
        '-o - transition': 'oTransitionEnd'
    };
    for (var t in transitions) {
        if (el.style[t]!== undefined) {
            return transitions[t];
        }
    }
    return false;
}

通过上述函数,可以判断浏览器是否支持 transition 属性,并获取相应的事件名称,以便在 JavaScript 中监听过渡结束事件。

同样,对于动画也可以进行类似的检测:

function isAnimationSupported() {
    var el = document.createElement('div');
    var animations = {
        'animation': 'animationend',
        '-webkit - animation': 'webkitAnimationEnd',
        '-moz - animation':'mozAnimationEnd',
        '-ms - animation':'msAnimationEnd',
        '-o - animation': 'oAnimationEnd'
    };
    for (var a in animations) {
        if (el.style[a]!== undefined) {
            return animations[a];
        }
    }
    return false;
}

通过这些检测方法,可以在不支持的浏览器中提供替代方案,或者调整动画和过渡的实现方式,以保证网站的兼容性和用户体验。

在前端开发中,CSS 动画和过渡是提升用户体验和页面交互性的重要手段。通过深入理解其基础属性、关键帧动画的实现,结合实际应用场景进行优化,并处理好与 JavaScript 的交互以及浏览器兼容性问题,开发者可以创建出丰富多彩且性能优良的网页动画效果。无论是简单的过渡效果还是复杂的关键帧动画,都能为用户带来更加生动和吸引人的浏览体验。