🌈

【CSS】グラデーションをTransitionのように滑らかに遷移させる方法

2022/09/16に公開

はじめに

マウスホバーなどのアクション時にデザインを滑らかに変更させたいとき、大抵の場合はtransitionを使うと思います。cssに「transition : 0.5s;」と記載すれば、0.5秒かけてデザインが遷移します。
ですが背景色にlinear-gradient(グラデーション)を使用すると、transitionが使用できません。
今回はこれらを解決して、グラデーション背景をアニメーションで遷移させる方法をまとめます。

下記が完成したものになります。ボタンを押すとグラデーションが滑らかに変化します。

今回はjQueryを使用して、JavaScriptからCSSを簡単に変化できるように組み立てていきます。

完成したもの

詳しくは下記のCodeSandBoxから見ていただければと思います。実際に動作確認しながら見られるのでおすすめです。
通常はJSファイルでコードを書いて、htmlにscriptタグでインポートしているのですが、CodeSandBoxで上手く動かなかったので、今回はscriptタグでhtmlに直接書き込んでいます。
https://codesandbox.io/s/gradationchange-bv9xwe?file=/index.html

html
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Gradation Switch</title>
    <link rel="stylesheet" href="style.css" />
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
  </head>

  <body>
    <div class="main">
      <input
        type="button"
        class="button"
        value="Gradation Switch"
        onclick="buttonClick()"
      />
    </div>

    <script>
      let setOpacity = 1;

      function GradationSwitch(opacity) {
        let setCSS =
          "<style>.main::before{ opacity: " + setOpacity + "; }</style>";
        $(".main").append(setCSS);
      }

      function buttonClick() {
        if (setOpacity == 0) {
          setOpacity = 1;
        } else {
          setOpacity = 0;
        }
        GradationSwitch(setOpacity);
      }
    </script>
  </body>
css
html {
  height: 100%;
}

body {
  height: 100%;
  margin: 0;
}

.main {
  width: 100%;
  height: 100vh;

  z-index: 0;
  position: relative;
  display: block;
  text-decoration: none;
  text-align: center;
  margin: 0 auto;
}

.main:before {
  content: "";
  background: linear-gradient(to right, rgb(216, 72, 146), rgb(214, 173, 106));
  width: 100%;
  height: 100vh;

  position: absolute;
  left: 0;
  z-index: -1;
  opacity: 1;
  transition: opacity 0.5s;
  margin: 0 auto;
}

.main:after {
  content: "";
  background: linear-gradient(to right, rgb(72, 216, 144), rgb(106, 209, 214));
  width: 100%;
  height: 100vh;

  position: absolute;
  left: 0;
  z-index: -2;
  margin: 0 auto;
}

.button {
  font-size: 24px;
  color: #fff;
  border: 4px solid #fff;
  background: transparent;
  line-height: 2;
  width: 300px;
  height: 120px;

  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  -webkit-transform: translate(-50%, -50%);
  -ms-transform: translate(-50%, -50%);
  transition: 0.5s;
}

.button:hover {
  border: 4.3px solid #fff;
  width: 310px;
  height: 130px;
}

ポイント

まず、全体の構造を簡単に説明します。
今回作った背景は2種類のグラデーションとなっており、z-indexを使用して表示の優先度をあらかじめ決めています。デフォルトでは両方とも画面いっぱいに表示されていますが、オレンジ色のグラデ背景はz-indexの優先度が高いので、緑色のグラデ背景は隠れて見えません。
そして、ボタンを押した際にオレンジ色のグラデ背景の透明度を少しずつ下げることで、緑の背景が見えるようになるのが今回の制作物の仕組みです。

①jQueryのインポート

一応初心者向けの記事なので書きます。headタグにCSSとjQueryをインポートしておきます。
scriptタグがjQueryです。今回jQueryは、JSからCSSのデザインを簡単に変更するために使用します。

html
  <head>
    <title>hoge</title>
    <link rel="stylesheet" href="style.css" />
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
  </head>

②背景の用意

2種のグラデーション背景を用意します。html側ではdivタグにmainクラスを当て、このタグ内に要素を入れていきます。(mainクラスが背景色になります)

今回はbefor、afterの疑似クラスを使用していますが、potision:absoluteを使用すれば普通のクラスでも作れます。下記のコメント部分で必要な詳細がわかります。

css
.main {
  width: 100%;
  height: 100vh;

  z-index: 0;
  position: relative;
  display: block;
  text-decoration: none;
  text-align: center;
  margin: 0 auto;
}

/* デフォルトのグラデーション背景(ボタンが押されると透明になるクラス) */
.main:before {
  content: "";
  background: linear-gradient(to right, rgb(216, 72, 146), rgb(214, 173, 106));
  width: 100%;
  height: 100vh;

  position: absolute;
  left: 0;
  z-index: -1;  /* .main:afterより高く設定する */
  opacity: 1;  /* この値を0に近づけると、透明になっていく(下のafter要素が表示される) */
  transition: opacity 0.5s;  /* デザイン変更にかかる時間 */
  margin: 0 auto;
}

/* ボタンが押された後に表示されるグラデーション背景 */
.main:after {
  content: "";
  background: linear-gradient(to right, rgb(72, 216, 144), rgb(106, 209, 214));
  width: 100%;
  height: 100vh;

  position: absolute;
  left: 0;
  z-index: -2;  /* .main:beforより低く設定する */
  margin: 0 auto;
}

ここまで実装すると、背景が二つ同時に表示されています。ただ、beforeクラスの表示優先度が高いので1色の背景しか確認できません。以降の工程で変化する処理を制作します。

③ボタンの用意&透明度のコントロール

今回はボタンのオンオフでグラデーションの色を滑らかに変更させたいと思います。JavaScriptで関数としてまとめているので、他のアクションからでも呼び出せます。
(ボタンのデザインについては割愛します。)

html
<div class="main">
      <!-- inputタグのbuttonタイプを使用。クリックするとJSのbuttonClick()を呼び出し -->
      <input
        type="button"
        class="button"
        value="Gradation Switch"
        onclick="buttonClick()"
      />
    </div>

jQueryによって、$(".main").append(hoge); と記述すると.mainクラスにCSSを足すことができます。hogeの部分に<style>.main:before{ opacity: 0; }</style> と記述すると、.main:beforeクラスを透明にできます。
これを利用して、透明度を変更する関数を作っていきます。

JavaScript
      <!-- 透明度をコントロールする変数。1が表示、0が非表示 -->
      let setOpacity = 1;

      <!-- CSSのデザインを変更する関数。引数は透明度。 -->
      function GradationSwitch(opacity) {
	    
	<!-- CSSに追加されるコード。透明度の数値は毎回変わるので、用意した変数を使用 -->
        let setCSS = "<style>.main:before{ opacity: " + setOpacity + "; }</style>";
        $(".main").append(setCSS);
      }

      <!-- ボタンをクリックした際に呼ばれる関数。 -->
      function buttonClick() {
	    
	<!-- 現在の透明度によって、次は表示か非表示かを変更するスイッチ -->
        if (setOpacity == 0) {
          setOpacity = 1;
        } else {
          setOpacity = 0;
        }
        <!-- CSSのデザインを変更する関数の呼び出し -->
        GradationSwitch(setOpacity);
      }

まとめ

この方法なら、グラデーションだけでなく画像など様々な表示を滑らかに遷移させることができます。ただ、透過PNGなど透明部分がある要素では、両方のopacityをコントロールする必要が出てるので注意です。今回のように背景が一面覆われている要素に対して効果的です。

jQueryの使用とJavaScriptで関数化することによって、様々なアクションに対して呼び出せます。
もし、ホバー時だけグラデーションを変化させたいなら .(クラス名):hover{ opacity: 0; } とすればjsを使用しなくてもCSSのみで完結します。

Discussion