transitionをかけたホバーアクションのopacityがちらつく問題を解消する

公開日 : 最終更新日 :

  • コーディング


こんにちは!AndHAコーディング部です。

突然ですが新人コーダーさん!コーディング勉強中の皆さん!
こんな不具合に遭遇したことありませんか?

transitionをかけたホバーアクションのopacityがちらつく!

新人コーダーの私も、何かと悩まされていました…
そこで今回は、この問題をどうにか解消していきたいと思います。

ちらつく問題について

アニメーションがちらつく問題

Webサイトの制作をしていると、避けて通れないボタンやリンクなどのパーツ。ホバーしたときの動きを指定することがほとんどですよね。

中でも、「opacity: 0.7」などと透過を指定したうえで、「transition: .3s」などとふわっとアニメーションするような指定を加えることが結構多く、コーダーさんには避けて通れないところかと思います。

そんなよくある動きなのに!かなりの高確率でこんな事象が発生します。

ホバーするとopacityがちらつくボタン

わかりますでしょうか?
ホバーしたときに、透過アニメーションが一瞬ちらつくんです!

原因はChromeのバグ

これ、結論から言うとChromeブラウザで発生するバグのようです。
試しにFirefoxで表示してみたところ、ちらつきは発生しませんでした。

[Safari・Chrome・Firefoxでありがちなバグの対処法について(主にCSS) | Blog | 株式会社イロコト | アニメ・ゲームなどのエンタメ系Web制作&運用会社]

前提知識として

「z-index」という指定が存在するように、Webサイトは三次元空間で構成されており、「レイヤー」という概念が存在します。
その「レイヤー」を生成するプロパティのひとつが、今回の問題でもある「opacity」。

公式ドキュメントのMDNでも述べられていますが、レイヤーはメモリー管理の面ではコストのかかる処理です。つまり、多用するとWebのパフォーマンスが低下し、表示速度などに影響してくるということ。濫用するべきものではない、とも述べられています。
[ページの生成: ブラウザーの動作の仕組み – ウェブパフォーマンス | MDN]

ちらつく問題を解消する方法4選

ここからは、筆者がこの問題について解決策を調べた結果をまとめていきます。
今回使用するサンプルコードは下記の通りです。追記するプロパティは、.button{}の中に記述していきます。

<div>
  <a href="#" class="button">ボタン</a>
</div>
.button {
  display: block;
  width: 200px;
  padding: 20px;
  text-align: center;
  text-decoration: none;
  color: white;
  background-color: blue;
  transition: opacity 0.3s;
}
.button:hover {
  opacity: 0.7;
}

解決策1:backface-visibilityをhiddenにする

opacityの対象となる要素に下記を指定します。

backface-visibility: hidden;

backface-visibilityプロパティをhiddenにしたボタン

なんと、治りました!!
しかし、筆者が試したときには、うまくいく日といかない日があり…バグだから仕方ないのでしょうかね。

backface-visibilityとは、要素がユーザーに対して裏側を向いたときに、裏面を可視にするかどうかを設定するプロパティです。詳しくは公式ドキュメントを参照してみてください。
[backface-visibility – CSS: カスケーディングスタイルシート | MDN]

解決策2:will-changeを設定する

opacityの対象となる要素に下記を指定します。

will-change: opacity;

will-changeプロパティの記述を追加したボタン

こちらも、治りました!しかも、backface-visibilityのようなブラウザの気まぐれ?はなく、試した中では百発百中で治りました。

will-changeとは、ブラウザに対してアニメーションの予測を伝えるためのプロパティです。
こちらも、詳しくは公式ドキュメントを参照してみてください。
[will-change – CSS: カスケーディングスタイルシート | MDN]

ただこのwill-changeプロパティ、注意することもあります。
公式でも述べられているように、この処理「高コスト」なんです。多用しすぎるとページのパフォーマンス低下につながります。
使ってはいけない処理ではないですが、なるべく使う場面はここぞというときに限定しましょう。

また、先日サポートが終了したIE(Internet Explorer)には非対応となっています。もう重視されることはないかもしれませんが、一応頭に入れておきましょう。

解決策3:transformにtranslate3dを指定する

opacityの対象となる要素に下記を指定します。

transform: translate3d(0, 0, 0);

こちらも、無事ちらつきが治りました。また、will-change同様、百発百中でした。
transformプロパティは馴染み深いために予想がつく方が多いかもしれませんが、「translate3d」は、三次元空間の移動を指定するものです。例によって、公式ドキュメントを参照しましょう。
[translate3d() – CSS: カスケーディングスタイルシート | MDN]

この「translate3d」ですが、この処理を行うことで「GPUアクセラレーション」が有効になり、アニメーションが滑らかになると言われています。
ただこちらもwill-change同様、パフォーマンス低下につながりますので多用は控えましょう。

解決策4:opacityをやめる

opacityで透過を指定するのをやめ、background-colorをrgbaで指定するのです。
サンプルコードは下記になります。

.button {
  display: block;
  width: 200px;
  padding: 20px;
  text-align: center;
  text-decoration: none;
  color: white;
  background-color: rgba(0, 0, 255, 1.0); /* rgbaで背景色を指定 */
  transition: background-color 0.3s;
}
.button:hover {
  background-color: rgba(0, 0, 255, 0.7); /* rgbaで透過を指定 */
}
背景色をrgbaで指定したボタン

rgbaの値で透過を指定したことで、ちらつきもなく透過が効いています!
今回のような単純な色ベタのボタンであれば最も簡単な方法といえるでしょう。

これは、rgbaではopacityのようにレイヤー構造が生成されないためバグが発生しないものと考えられます。

まとめ

いかがでしたでしょうか。

今回取り上げた課題がそもそもブラウザ側のバグということもあり、解消する方法もハック的なものになってしまいますが、自分自身も毎度気になる部分ではありますので今回まとめてみました。

この情報が、皆様のお役に立ちますように。
それでは、また!

合わせて読みたい!