💫

バニラCSSで作るアニメーション入門

2024/12/02に公開

こんにちは、アドベントカレンダー3日目を担当しますSomahcです!

昨日はyoshiki495さんのDeep Learningに関する内容でした。統計学的な知識はDeep Learningだけでなく論文執筆においても必要なので、復習頑張りたいと思います、、、!

さて、突然ですが、以下のサイトを見てみてください。

https://conference.pixiv.co.jp/2020/tech-fes

いかがでしたでしょうか!2020年に行われたPIXIV TECH FESのLP(ランディングページ)なのですが、アクセスした瞬間やスクロールしたタイミングでアニメーションとともにコンテンツが表示されたと思います。

このLPのフロントエンドを担当した、”CSSヤクザ”の異名で知られる@yui540さんによると、このリッチなページは「CSSアニメーション」を駆使して作られているそうです。

今回はこのページのようにリッチな動きのあるページづくりに役立つ、CSSアニメーションに入門してみたいと思います!

準備

1. Node.js をインストールしておく

JavaScriptのランタイム(実行環境)である Node.js のインストールがまだの方はインストールしておきましょう!ターミナルで以下のコマンドを実行して、バージョンが表示されたら、Node.js がインストールされています。

$ node -v
v20.18.0 (私の環境の場合)

2. Vite プロジェクトを作成する

プロジェクトを作成します。今回は高速なビルドツールとして知られる Vite を使います。以下のコマンドを実行します。

$ npm create vite@latest

対話形式でプロジェクトの設定を聞かれます。今回は基本的に Enter 連打で OK ですが、以下その説明です。

? Project name:(プロジェクトの名前は?)
プロジェクトの名前です。好きなように決めてください。

? Select a framework:(フレームワークを選択してください)
今回はVanillaを選択してください。

? Select a variant:(JavaScriptかTypeScriptを選択)
TypeScriptを選択してください。

Done. Now run:~~と表示されたら OK です!cd <プロジェクトフォルダ名>でプロジェクトフォルダに移動してnpm iを実行しパッケージをインストールします。
最後にnpm run devを実行して http://localhost:5173/にアクセスして以下の画面が表示されていたら準備完了です。

最後に、最初から用意されているCSSスタイルやスクリプトは不要なので、src/style.csssrc/main.tsの中身を全て消します。また、index.htmlの中身を少し書き換えてCSSファイルとTypeScriptファイルを読み込むようにします。今回は以下のようにしました。
また、リセットCSSを読み込んでブラウザのデフォルトのスタイルを無効化しています。特にこだわりがなければコピペで大丈夫です!

index.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8" />
        <link rel="icon" type="image/svg+xml" href="/vite.svg" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>CSSアニメーション入門</title>
        <!-- リセットCSS -->
        <link
            rel="stylesheet"
            href="https://cdn.jsdelivr.net/npm/destyle.css@1.0.15/destyle.css"
        />
        <!-- TypeScirptとCSSを読み込む -->
        <script type="module" src="/src/main.ts"></script>
        <link rel="stylesheet" href="/src/style.css" type="text/css" />
    </head>
    <body>
        <div class="wrp">
            <div class="box"></div>
        </div>
    </body>
</html>

ここまできたら git でコミットしておくといつでも戻れるようになるので安心です!

$ git init
$ git add .
$ git commit -m 'initial commit'

テキストをかっこよく表示してみる

それでは早速CSSアニメーションを実装していきます!今回は以下のようにアニメーションさせながら表示させるテキストを実装してみます。

1. 四角形を表示させる

まずは画面の真ん中に横長い四角形を表示させてみます。display: gridplace-items: centerで要素を真ん中に持っていっています。

index.html(bodyタグのみ)
<body>
    <div class="wrp">
        <div class="box"></div>
    </div>
</body>
src/style.css
.wrp {
    width: 100%;
    height: 100vh;
    display: grid;
    place-items: center;
}

.box {
    width: 250px;
    height: 50px;
    background-color: black;
}

2. 四角形を擬似要素として表示させる

次に、四角形の表示のさせ方を少し変えてみます。以下のようにCSSを書き換えます。

src/style.css
.box {
    width: 250px;
    height: 50px;
+}
+
+.box::before {
+    width: 100%;
+    height: 100%;
+    content: "";
+    display: block;
     background-color: black;
 }

画面上では変化がないと思いますが、これでOKです!
::beforeという表現は馴染みのない方がいるかもしれませんが、これは擬似要素と呼ばれるもので、特定の要素の特定の部分にスタイルを適用できるものです。擬似要素を使うことでHTML上で何も追加しなくても擬似的に要素を追加することができます。

今回は.boxクラスが適用されているdiv要素と全く同じ幅・高さで背景が黒の要素を追加したので、見た目上の変化はありませんが、黒の四角形が擬似要素に置き換えられています。

3. アニメーションを実装する

お待たせしました、それではアニメーションを実装してましょう!方針としてはシンプルで、擬似要素の四角形を左から右に移動させるだけです。

以下のようにCSSを書き換えます。

src/style.css
 .box {
    width: 250px;
    height: 50px;
+   overflow: hidden;
 }
 
 .box::before {
    content: "";
    display: block;
    background-color: black;
+   animation: slideInOut 0.5s ease-in-out both;
}

+ @keyframes slideInOut {
+   0% {
+        transform: translateX(-101%);
+   }
+   100% {
+       transform: translateX(101%);
+   }
+}

これで四角形が右から現れて左に消えていくアニメーションが実装できたと思います!
ポイントはboxの擬似要素に追加したanimationプロパティです。今回はslideInOutというオリジナルのアニメーションを0.5秒かけて再生するという指定にしています。ease-in-outbothはそれぞれアニメーションの再生スピードの緩急、アニメーション開始前と終了後のスタイルの適用に関する指定です。

また、アニメーションの動きは@keyframesで定義します。今回はslideInOutという要素を左から右に動かすアニメーションを定義しています。

このアニメーションにより、box要素の真左に配置された擬似要素がアニメーションの再生によりbox要素の真右に移動しています。box要素自体にはoverflow: hiddenを指定することで、要素からはみ出ている部分は見えなくしているため、アニメーション開始前と終了後は擬似要素が見えなくなっています。

box要素に赤で枠線を表示させて、overflow: hiddenを無効化したものが以下です。よりどんなことが起きているかイメージしやすいと思います。

4. テキストを表示させる

最後に四角形が過ぎ去ったタイミングで四角形が表示されるようにします!
今回はposition: absoluteを使ってbox要素の真ん中にテキストを配置し、四角形がbox要素を覆うアニメーションの中間ポイントでテキストを瞬時に表示させるアニメーションを再生するようにしました。

index.html
<body>
    <div class="wrp">
-       <div class="box"></div>
+       <div class="box">
+           <p class="text">MYJlab</p>
+       </div>
    </div>
</body>
src/style.css
.box {
+   position: relative;
    width: 250px;
    height: 50px;
    overflow: hidden;
}

(中略)

+.text {
+    position: absolute;
+    font-size: 30px;
+    font-weight: bold;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    color: black;
+    animation: showText 0s 0.25s both; // アニメーションの開始を0.25s遅らせる
+}

+@keyframes showText {
+    0% {
+        opacity: 0;
+    }
+    100% {
+        opacity: 1;
+    }
+}

コードと完成形

最後に完成系のコードを載せておきます。

index.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8" />
        <link rel="icon" type="image/svg+xml" href="/vite.svg" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>CSSアニメーション入門</title>
        <!-- リセットCSS -->
        <link
            rel="stylesheet"
            href="https://cdn.jsdelivr.net/npm/destyle.css@1.0.15/destyle.css"
        />
        <!-- TypeScirptとCSSを読み込む -->
        <script type="module" src="/src/main.ts"></script>
        <link rel="stylesheet" href="/src/style.css" type="text/css" />
    </head>
    <body>
        <div class="wrp">
            <div class="box">
                <p class="text">MYJlab</p>
            </div>
        </div>
    </body>
</html>
src/style.css
.wrp {
    width: 100%;
    height: 100vh;
    display: grid;
    place-items: center;
}

.box {
    position: relative;
    width: 250px;
    height: 50px;
    overflow: hidden;
}

.box::before {
    width: 100%;
    height: 100%;
    content: "";
    display: block;
    background-color: black;
    animation: slideInOut 0.5s ease-in-out both;
}

.text {
    position: absolute;
    font-size: 30px;
    font-weight: bold;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: black;
    animation: showText 0s 0.25s both; // アニメーションの開始を0.25s遅らせる
}

@keyframes slideInOut {
    0% {
        transform: translateX(-101%);
    }
    100% {
        transform: translateX(101%);
    }
}

@keyframes showText {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

おわりに

いかがでしたでしょうか!テキストの表示のほかに画面転換やロード中の表示などなど、CSSアニメーションでできることはたくさんあります。これを機にCSSアニメーションの可能性を知ってもらえたら幸いです。

お疲れ様でした!

参考文献

https://www.youtube.com/watch?v=54OJ321zkYU

https://codepen.io/yui540

https://b-risk.jp/blog/2022/03/pseudo_elements/

GitHubで編集を提案

Discussion