教你用CSS的关键帧动画去实现超酷炫的Star Wars.

2,313 阅读6分钟

动画.gif

🐟前言

《星球大战》(Star Wars)是一部经典的科幻电影系列,其标志性的开场场景——文字从屏幕底部向上滚动,就像两艘宇宙飞船一样,一直深入宇宙深处,给观众留下了深刻的印象。今天,我们将使用CSS的关键帧动画来复现这一经典效果,让你也能体验到原力的觉醒!!

对源码感兴趣的jym们可以去我的github里面自取资源wqlblue/lesson_hm: AI全栈学习

准备工作

首先,确保你有一个基本的HTML结构,并引入必要的CSS文件。我们将使用Eric Meyer的CSS重置来确保各浏览器的一致性。

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>
    <link rel="stylesheet" href="./common.css">
</head>
<body>
    <div class="starwars">
        <img src="./images/star.svg" alt="" class="star">
        <img src="./images/wars.svg" alt="" class="wars">
        <h2 class="byline">
            <span>T</span>
            <span>h</span>
            <span>e</span>
            <span>F</span>
            <span>o</span>
            <span>r</span>
            <span>c</span>
            <span>e</span>
            <span>A</span>
            <span>w</span>
            <span>a</span>
            <span>k</span>
            <span>e</span>
            <span>n</span>
            <span>s</span>
        </h2>
    </div>
</body>
</html>

CSS 重置

它的代码量太多了,我就不放在文章里了,给大家一个🔗,大家自行查看啦CSS Tools: Reset CSS

CSS核心样式

在了解他的核心样式之前

什么是关键帧动画?

关键帧动画(@keyframes)是CSS中用于创建复杂动画的一种强大工具。通过定义一系列关键帧,你可以指定动画在不同时间点的状态,浏览器会自动平滑地过渡这些状态之间的变化。

基本概念
  1. 关键帧(Keyframes)

    • 关键帧定义了动画在特定时间点的状态。
    • 使用 @keyframes 规则来定义关键帧。
  2. 动画属性(Animation Properties)

    • animation-name:指定动画的名称,对应 @keyframes 规则的名称。
    • animation-duration:动画的持续时间。
    • animation-timing-function:动画的速度曲线。
    • animation-delay:动画开始前的延迟时间。
    • animation-iteration-count:动画的重复次数。
    • animation-direction:动画的方向。
    • animation-fill-mode:动画结束后的状态。
    • animation-play-state:动画的播放状态。
基本语法

@keyframes 动画名称 {
  /* 关键帧 */
  0% {
    /* 初始状态 */
  }
  50% {
    /* 中间状态 */
  }
  100% {
    /* 最终状态 */
  }
}

元素选择器 {
  animation: 动画名称 持续时间 速度曲线 延迟时间 重复次数 方向 填充模式 播放状态;
}

下面是样式的代码啦

基础样式

/* 业务样式 */
html,
body {
    height: 100vh;
}

body {
    background: #000 url('./images/bg.jpg');
}

.starwars {
    perspective: 800px;
    transform-style: preserve-3d;
    height: 17em;
    width: 34em;
    position: absolute;
    top: 50%;
    left: 50%;
    /* 移动 自身的大小 */
    transform: translate(-50%, -50%);
    /* background: red; */
}

img {
    width: 100%;
}

.star,
.wars,
.byline {
    position: absolute;
}

.star {
    top: -0.75em;
}

.wars {
    bottom: -0.5em;
}

.byline {
    color: #fff;
    font-size: 2.25em;
    left: -2em;
    right: -2em;
    text-align: center;
    text-transform: uppercase;
    top: 42%;
}

上面代码中的

perspective: 800px;
transform-style: preserve-3d;

需要和大家补充一下

什么是 perspective

perspective 属性用于创建3D空间,使元素看起来具有深度感。它定义了观察者距离 z=0 平面的距离。

如何使用 perspective
  • 语法perspective: <length>;

    • <length>:长度值,通常使用像素单位(px)。
  • 作用:应用在父元素上,影响其所有子元素的3D变换效果。值越大,3D效果越平缓;值越小,3D效果越明显。

transform-style: preserve-3d;

什么是 transform-style

transform-style 属性用于控制子元素是否保留3D变换效果。默认情况下,子元素会被扁平化,失去3D效果。

如何使用 transform-style
  • 语法transform-style: flat | preserve-3d;

    • flat:子元素被扁平化,失去3D效果(默认值)。
    • preserve-3d:子元素保留3D变换效果。
  • 作用:应用在父元素上,确保子元素在3D空间中保持其3D变换效果。

关键帧动画

Star 动画
.star {
    /* 动画名字 + keyframes 定义动作 */
    animation: star 10s ease-out infinite;
}

@keyframes star {
    0% {
        opacity: 0;
        transform: scale(1.5) translateY(-0.75em);
    }

    20% {
        opacity: 1;
    }

    89% {
        opacity: 1;
        transform: scale(1);
    }

    100% {
        opacity: 0;
        transform: translateZ(-1000em);
    }
}
Wars 动画

.wars {
    /* 动画名字 + keyframes 定义动作 */
    animation: wars 10s ease-out infinite;
}

@keyframes wars {
    0% {
        opacity: 0;
        transform: scale(1.5) translateY(0.5em);
    }

    20% {
        opacity: 1;
    }

    90% {
        opacity: 1;
        transform: scale(1);
    }

    100% {
        opacity: 0;
        transform: translateZ(-1000em);
    }
}

大家可能会有疑惑,为什么不用群组选择器直接将 warsstar这两个类一起共享相同的样式属性。 然而,在某些情况下,分开定义每个选择器可能更有意义,特别是当它们的动画效果有细微差异时,我们在.wars的关键帧动画里,设置的关键帧有一个不予star里的相同,他们分别是89%,90%,因为飞船不可能同步启动,这样可以造就视觉上面的层次感,这是我们前端应该学会的想象力,想象飞船的穿越!

Byline 动画
.byline {
    animation: movie-byline 10s linear infinite;
}

.byline span {
    animation: spin-letters 10s linear infinite;
}

.byline span {
    display: inline-block;
}

@keyframes movie-byline {
    0% {
        transform: translateZ(5em);
    }

    100% {
        transform: translateZ(0em);
    }
}

@keyframes spin-letters {
    0%,
    10% {
        opacity: 0;
        transform: rotateY(90deg);
    }

    30% {
        opacity: 1;
    }

    70%,
    86% {
        transform: rotateY(0);
        opacity: 1;
    }

    95%,
    100% {
        opacity: 0;
    }
}

上面代码中要给.byline span设置display:block的原因是inline元素不支持transform,所以将display属性设置为inline-block; 设置好了之后就可以开始旋转啦, transform: rotateY(90deg);

rotateYtransform 属性的一个函数,用于沿Y轴旋转元素。Y轴是垂直轴,从上到下方向。

同理

  • rotateX 函数用于沿X轴旋转元素。X轴是从左到右的方向。
  • rotateZ 函数用于沿Z轴旋转元素。Z轴是从屏幕内到屏幕外的方向。

当里面的参数是正数就是顺时针旋转,反之则是逆时针。

补充

其实我们还可以让他更加细腻

增加时间差

为了进一步提升动画的真实性和视觉效果,我们可以通过在特定的关键帧之间引入细微的时间差来增加动画的细腻度。具体而言,在51%和52%的关键帧之间添加微妙的时间差,可以模拟出飞船接近屏幕中心时的轻微摇摆或晃动感。这种晃动不仅增加了动画的动态层次,还让观众感受到飞船穿越空间时可能遇到的波动或气流影响,从而使整个场景更加生动逼真。例如,当飞船逐渐驶向画面中央时,通过在51%处设置一个轻微向左的位移,紧接着在52%处设置一个向右的位移,可以创造出一种微妙的摇晃效果,进而增强观众的沉浸体验。这种细节上的调整虽小,但往往能带来意想不到的效果,使得动画作品的整体质量得到显著提升。

🐟END

关键帧动画是一个很好玩的CSS样式,大家可以多多琢磨,有时候增加一点细微的差别就会让你的动画看起来更加逼真,这就是代码的魅力!!