opacityとスタッキングコンテキストに立ち向かう

掲載日
更新日

スタッキングコンテキスト(重ね合わせコンテキスト)とは

重ね合わせコンテキスト (Stacking context) は、ビューポートまたはウェブページに面していると想定されるユーザーに対する仮想的な Z 軸に沿って並べられた HTML 要素の三次元の概念化です。

MDNより引用

cssでは、z-indexやfloat、position等を使う時に、要素同士のどっちを前面に表示するか決めるために内部的にはz軸を持っているというお話です。

このz軸は、特定のスタイルを持っていない場合は概念が存在しない(要素は一番下に張り付く)のですが、opacity等を設定するとこの概念が適用されて要素が浮かび上がります。

GitHubに上げているようなHTMLを作ってブラウザで開き、「要素1」と「要素2」が重なる位置にカーソルを合わせると、添付gifのようなチラつきが起こります。(点滅注意)

スタッキングコンテキストによってちらつきが発生する検証のGIF動画。
要素1と要素2が重なる位置にカーソルを当てるとちらつきが起きる

その原因がこのスタッキングコンテキストまわりの仕様にあり、以下のような動作をします。

  1. hover時に要素2にopacityが設定されるため、親要素が浮かび上がる。
  2. 要素2の親要素は z-index:2の要素1に負けて後ろに回る。
  3. 要素2のhoverが解除され、要素2のopacityスタイルが削除される。
  4. 再び要素2の方が上だと判定され、hoverされる。
  5. 1に戻り、hoverイベントが評価されなくなるまでループ。(チラつく。)


解決まで苦しめられたのでその備忘録です。

対策

案1. 親要素にposition: static以外 とz-indexを設定する

(※ サンプルのz-indexの値はテストなので適当にデカい数字を入れてますが、実際にやるときはちゃんと計算して設定しましょう。)

それまで浮かんでいなかった親要素が浮き上がるのが問題なので、最初から浮かせておこうという解決策。
浮き上がる親要素に最強のz-indexを設定すれば必ず一番上に来るので固定できます。


.element:hover {
     opacity: 0.6;
     position: relative; /* ここを追加 */
     z-index: 99999; /* ここを追加 */
 }

position指定入れてしまうこと自体がNG(表示位置が変わってしまう等)なケースもあるので注意。

案2. opacityの位置を合わせる

親要素を浮かせない解決をしたい時はこっちになるのかなぁと。
元からz-indexの存在する子要素でhover時にopacityを付けるようにしてもOKです。


.element>div:hover { /* ここを修正 */
    opacity: 0.6;
}

ただ、これもケースバイケースで、親要素の中に他の要素があるとその部分は透過しなくなるのでNGだったりすると思います。

もっといい解決策はありそうですが、自分はとりあえずこの二つでなんとかしました。

(おまけ)Edgeで3Dで要素の重なりが見れる

Edge ブラウザでは開発者ツールで3Dで要素の重なりを見ることができます。

Microsoft Edgeブラウザで、3D View機能を使って要素の重なりを三次元で確認しているスクリーンショット。

添付のように、要素1が要素2の上に浮き上がってきていることが視覚的に分かりやすくみられます。

記事ではシンプルな構成にしているのでこんなリッチな機能を使わずとも構いませんが、実際の画面はもっと複雑な子孫要素があり、重なった状態になっていると思うので、今回のようなスタイルのちらつきや、それ以外でもスタッキングコンテキストが複雑に絡んでいるレイアウトで悩んでるときの調査に役に立ちそうです。

参考リンク

    • BlueSkyで共有する
    • Hatenaで共有する
記事の作成者のW.Aのアイコン

この記事を書いた人

W.A
茨城県在住Webエンジニアです。 PHP、PostgreSQL、Linuxなどを業務で使用しています。 趣味ではGoやNuxt、Flutterをやってます。
  • GitHubのリンク

Comment

関連記事

  • linear-gradientで方眼紙(マス目)レイアウトを作るのサムネイル画像

    linear-gradientで方眼紙(マス目)レイアウトを作る

    掲載

    cssでレイアウト用のHTMLタグのネストをさせずに、linear-gradientを使ってシンプルな方眼紙(マス目)レイアウトを作成する方法の解説をしています。ネストしたdivタグなどを使って作成する方法もありますが、今回紹介している内容はネストが不要なので、既存のHPでタグ構成を中々修正出来ない状態でマス目レイアウトを作りたい時に役に立ちます。

  • mask-imageで簡単反転ボタンのサムネイル画像

    mask-imageで簡単反転ボタン

    掲載

    svg画像をCSSのfillやstrokeを使って色付けしようとする場合、HTMLに直接svgの埋め込みが必要です。(imgタグのsrc読み込みでは色付け出来ない。)mask-imageというCSSプロパティを使えばimgタグで埋め込んでいても、色も付けられることが分かったのでその方法と、それを使って簡単にsvgアイコンの色を反転させてインタラクティブなボタンを作れる方法を解説しています。

check コピーしました!