【HTML/CSS/JS】中級者向け!マスク画像(mask-image)を使用したフェードインアニメーションの作成方法

ホームページ作成

今回はCSSによるフェードインアニメーションだけでなく、マスク画像を使用した更にひと手間加えたアニメーションの方法を紹介します。リッチなアニメーションを採用したい場合等に効果的ですのでぜひご活用ください。

今回つくるもの

今回は画面読み込み時 / スクロール時に合わせてふんわりとフェードインしてくるようなアニメーションを作成していきます。

開発環境・前提

  • XAMPP等によるローカルサーバーでの作業
  • マスク画像の用意

今回CSSでmask-imageプロパティを使用しますが、サーバーを起動しない環境で作業する場合はマスク画像へのアクセスエラーが発生して正常に動作しない場合がありますので、ローカル―サーバーを立ち上げて作業を行うようにしてください

マスク画像はこちらの方でアップロードしますが、背景が白いのでわかりにくいかもしれません・・・

↑ここにマスク画像がありますので右クリックで保存してください

index.html

まずはindex.htmlを作成していきましょう。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Shippori+Mincho:wght@400;500;600;700;800&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="./style.css">
    <title>マスクアニメーションサンプル</title>
</head>
<body>
    <main>
        <div class="item">
            <div class="image-wrapper">
                <img class="mask" data-animate="on" src="https://images.pexels.com/photos/327483/pexels-photo-327483.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <div class="item-info">
                <h2>雰囲気のある日本庭園</h2>
                <p>
                    ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。
                </p>
            </div>
        </div>

        <div class="item">
            <div class="image-wrapper">
                <img class="mask" data-animate="on" src="https://images.pexels.com/photos/327483/pexels-photo-327483.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <div class="item-info">
                <h2>雰囲気のある日本庭園</h2>
                <p>
                    ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。
                </p>
            </div>
        </div>

        <div class="item">
            <div class="image-wrapper">
                <img class="mask" data-animate="on" src="https://images.pexels.com/photos/327483/pexels-photo-327483.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <div class="item-info">
                <h2>雰囲気のある日本庭園</h2>
                <p>
                    ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。ここに画像に関係するテキストを記載していきます。
                </p>
            </div>
        </div>

    </main>
    <script src="./animation.js"></script>
</body>
</html>

雰囲気を出すためにGoogleFontsの読み込みを行っています。

後ほど作成しますが、animation.jsというスクロール時と画面読み込み時に処理を行うjsファイルも読み込んでおきます。

今回特筆するものはimg.mask要素です。data-animateという属性は画面スクロール時のアニメーションのトリガーとして後ほどjsファイルで使用するので定義しています。

style.css

続いてstyle.cssを作成していきましょう。

@charset "UTF-8";
* {
  margin: 0;
  padding: 0;
  -webkit-box-sizing: border-box;
          box-sizing: border-box;
  font-family: "Shippori Mincho", serif;
  color: #4a4a4a;
}

main {
  width: 80%;
  margin: auto;
}

main .item {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: justify;
      -ms-flex-pack: justify;
          justify-content: space-between;
  -ms-flex-wrap: wrap;
      flex-wrap: wrap;
  width: 100%;
  margin: 10vw 0;
}

main .item .image-wrapper {
  width: 40%;
  max-width: 700px;
  min-width: 300px;
  padding: auto;
}

main .item .image-wrapper img {
  width: 100%;
  aspect-ratio: 16/10;
  -o-object-fit: cover;
     object-fit: cover;
}

main .item .item-info {
  width: 50%;
}

main .item .item-info h2 {
  font-size: calc(24px + 0.4vw);
  margin-bottom: 50px;
}

main .item .item-info p {
  line-height: 2;
}

/* 画像マスク設定部分 */
img.mask {
  z-index: 0;
  -webkit-mask-image: url(./mask.png);
          mask-image: url(./mask.png);
  mask-mode: alpha;
  -webkit-mask-position: center bottom;
          mask-position: center bottom;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-size: auto 200%;
          mask-size: auto 200%;
  opacity: 0;
}

img.mask.on {
  -webkit-animation: 1.8s mask-animation cubic-bezier(0, 0.4, 0.48, 1) 0s forwards;
          animation: 1.8s mask-animation cubic-bezier(0, 0.4, 0.48, 1) 0s forwards;
}

@-webkit-keyframes mask-animation {
  0% {
    -webkit-mask-position: center bottom;
            mask-position: center bottom;
    opacity: 0;
  }
  20% {
    opacity: 1;
  }
  to {
    -webkit-mask-position: center 0%;
            mask-position: center 0%;
    -webkit-mask-size: auto 500%;
            mask-size: auto 500%;
    opacity: 1;
  }
}

@keyframes mask-animation {
  0% {
    -webkit-mask-position: center bottom;
            mask-position: center bottom;
    opacity: 0;
  }
  20% {
    opacity: 1;
  }
  to {
    -webkit-mask-position: center 0%;
            mask-position: center 0%;
    -webkit-mask-size: auto 500%;
            mask-size: auto 500%;
    opacity: 1;
  }
}

コードの解説

img.mask:マスク画像の設定やサイズなどを定義する部分になります。アニメーションでふんわり表示したいので、デフォルトではopacity:0を設定して非表示状態に設定します

@keyframes mask-animation:ふんわり表示するアニメーションの定義部分になります。opacityの調整とマスクの位置、サイズを調整することによってアニメーションを実現しています。

img.mask.on:アニメーションを実行する為のクラスになります。1.8秒間でアニメーションを実行し、アニメーションが終了後はその状態を維持したままに設定しています。onクラスを付与することでアニメーションを起動させる仕組みです

animation.js

続いてanimation.jsを作成していきます。

// 画面ロード時
window.addEventListener('load', function () {
    ScrollAnimation('.mask');
});
// スクロール時
window.addEventListener('scroll', function () {
    ScrollAnimation('.mask');
});

function ScrollAnimation(className) {
    var elements = document.querySelectorAll(className);

    // ウィンドウの高さを取得
    var windowHeight = window.innerHeight;

    // オフセットの固定値を設定
    var offset = 200; // 例: 200px

    // 要素ごとに処理
    elements.forEach(function (element) {
        // モバイル・スマートフォンの場合はoffset値を再設定
        if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
            offset = SettingOffset(element);
        }
        // 要素の位置とサイズを取得
        var elementRect = element.getBoundingClientRect();

        // 要素の中央が画面の中央にオフセット分ずれているかどうかをチェック
        var isElementInCenter = (elementRect.top + elementRect.height / 2 >= offset) &&
            (elementRect.bottom - elementRect.height / 2 <= windowHeight - offset);

        // 要素が画面の中央に来た場合
        if (isElementInCenter) {
            // data-animate属性からクラス名を取得
            var animateClass = element.getAttribute('data-animate');
            // クラスを要素に追加
            element.classList.add(animateClass);

            // delay設定を取得
            var delayClass = element.getAttribute('data-delay');
            if (delayClass) {
                element.classList.add(delayClass);
            }

            // 一度だけ実行するためにクラス"animate"を削除
            element.classList.remove('animate');
        }
    });
}

function SettingOffset(element) {
    // 要素の高さを取得
    var elementHeight = element.clientHeight;

    // 画面の高さを取得
    var windowHeight = window.innerHeight;

    // 要素の高さが画面の高さよりも大きいかどうかを確認
    if (elementHeight > windowHeight) {
        // 要素の高さの半分の数値を取得
        var halfElementHeight = elementHeight / 3;
        return (halfElementHeight) * -1;
    } else {
        return 0;
    }
}

このJavaScriptは指定したclass名を持つ要素が画面領域内にスクロールしたかどうかを検知し、画面領域内に入った場合はdata-animation属性に付与されている値をclassとして付与する挙動を行っています。

ここでは.maskというクラスを指定しているので、.maskクラスが画面領域内に入った場合に処理を行っています。

先ほどのstyle.cssでは[ on ]というクラス名にanimationの実行プロパティを設定していたので、htmlファイルの方でdata-animate=”on”という設定をしています。これにより、スクロール時に画面領域に入った場合[ on ]というクラスが付与されてアニメーションが実行される仕組みです

ScrollAnimation関数を実行する時に渡す引数を自由に変更することが出来るので、環境に合わせてスクロール監視する要素を変更できます。

まとめ

今回はマスク画像(mask-image)を使用した更にひと手間加えたアニメーションの方法を紹介しました。mask画像を用意したり、ローカル―サーバーを立ち上げたりと実装する際はコストがかかりますが、単純なCSSアニメーションだけでは再現出来ないリッチでオリジナリティのあるアニメーションを実装することが出来るので、ホームページやWebサイトを際立たせたい際はぜひご活用してみてください!

ZeroStartでは初期費用0円でお客様に合わせたオリジナルテーマを使用したホームページ作成を行っています!ホームページ作成についてご相談がございましたらお気軽にご連絡ください!

ホームページ作成の
ご相談・申込みはこちら

ZeroStartではホームページ作成における充実したノウハウを駆使し、
お客様が愛着を持てるホームページを作成致します。
ホームページ作成でご不安や不明点等お気軽にご相談ください