どうも フロントエンド志望のRioです。
こちらが私のポートフォリオのヒーローセクションになります。ご覧ください。
「作品を見る」と書いてある赤いボタンがご覧になれるかと思います。
ポートフォリオを作ってて、
このボタンの周りをグラデーションがぐるぐる回るかっこいいボーダーラインエフェクトを作ろうといたしましたが、
見事にに苦戦いたしましたのでその時のデバッグの過程を書いておこうと思います。…。
発生した問題
こちらの赤いボタンですが。マークアップは<button>です。
青と赤、白からなるカラフルなボーダーラインがお見えになるかと思いますが、
これは button::after で構成されています。
疑似要素と呼ばれるものですね。
button::after でカラフルなグラデーションのパネルを作ってそれを @keyframes で常時回転させています。
赤い<button>の背後でクルクルとカラフルなパネルがスピンしている状態です。
今見てもらったのは完成形で、実はこれにたどりつくまでに難解なバグに直面していました。
これがバグの状態です
button::afterが<button>の前面に進出してしまい、ボタンに覆いかぶさってしまっています。
なぜ z-index: -1 が効かないのか?(原因)
じゃあ<button>にz-index:0 を、
button::afterにz-index:-1 を設定すればいいじゃん と思うじゃないですか。
しかしそれをやってもなぜかずっと前面に覆いかぶさったままなのです。
結局訳が分からずにずっと格闘していましたが、答えを見つけました。
結論から言うと、ボタン自体に z-index を指定していたからでした。
これ、CSSの罠なんですが、::after 疑似要素って「兄弟」じゃなくて「ボタンの子要素」扱いなんですよね。
ボタン自体に z-index(たとえ z-index: 0 でも)を指定すると、ブラウザはそのボタンの中に**新しい「重ね合わせ文脈(Stacking Context)」**を作っちゃいます。
イメージで言うと、ボタンの中に新しい透明な「フォルダ」が生成される感じです。
[親要素 (wrapper)]
└── [ボタン (z-index: 0 =新しいフォルダ作成!)]
├── ボタンのテキスト
└── ::after (z-index: -1) ← フォルダ内の最背面にいくが、ボタンフォルダの外には出られない!
しかも○○::afterは基本的にその○○の上に(前面に)配置されるんですね。
それで<button>にz-indexを指定してしまうと<button>の中にStacking Contextが発生してしまって::afterはその中に閉じ込められるのでいくらz-indexを指定しようが位置が変わらないというわけです。
フォルダの中に閉じ込められた ::after にどれだけ z-index: -1 を指定しても、**「ボタンの中でのStacking Contextの中での最背面」**に行くだけで、親であるボタン本体の背景を突き破って後ろに回ることはできませんでした…。
解決策
-
ボタン自体の
z-indexを消す(ボタンの中に階層(Stacking Context)を作らせない) - ボタンをラッパー(親要素)で包む。そのラッパーに
z-indexを指定する ::afterにz-index: -1を指定する
こうすると、親要素のフォルダの中で「ボタン」と「::after」が同じ文脈(階層)(Stacking Context)で比較されるようになります。
<div class="button-wrapper">
<button class="glow-button">Hover or Active</button>
</div>
/* 1. 親要素側で重ね合わせ文脈(フォルダ)を作る */
.button-wrapper {
position: relative;
z-index: 1; /* ここで文脈をつくる! */
display: inline-block;
}
/* 2. ボタン自体には絶対 z-index を書かない! */
.glow-button {
position: relative;
/* z-index: 0; ← ❌ これを書くとフォルダが作られて積む */
padding: 12px 24px;
background: #111;
color: #fff;
border: none;
border-radius: 8px;
cursor: pointer;
}
/* 3. 親の文脈の中で ::after を背面に回す */
.glow-button::after {
content: '';
position: absolute;
top: -2px;
left: -2px;
width: calc(100% + 4px);
height: calc(100% + 4px);
border-radius: 10px;
/* カラフルな回転グラデーション */
background: conic-gradient(from 0deg, #ff007f, #7f00ff, #00f0ff, #ff007f);
z-index: -1; /* 親の文脈があるので、これでちゃんとボタンの後ろに回る! */
/* アニメーション処理 */
animation: rotate 3s linear infinite;
}
@keyframes rotate {
100% {
transform: rotate(360deg);
}
}
まとめ
z-index は単なる「数字の大きさ勝負」じゃなくて、「どの重ね合わせ文脈(フォルダ)に所属しているか」がすべて。
疑似要素(::before / ::after)を要素の後ろに回したい時は、親要素側で文脈を作るのが鉄則。
「見た目は兄弟っぽいのに構造は親子」っていう疑似要素の性質を理解してないと絶対沼りますねこれ…w
同じ現象で止まってる人の参考になれば!


