2015.04.11
css3で吹き出し作って、疑似要素がz-indexでどっか行っちゃうの直す
当ブログでは長年?画像で吹き出しを表現していたのですが、retina対応をした時に画像のぼけ具合が気になり出しました。cssで表現出来る部品はなるべくそっちにシフトしたいなーということで!
webでは吹き出しを作るための便利なジェネレーターや沢山の優れたリファレンスが公開されますが、勉強がてら自分なりにまとめてみることにしました。
まずは構成から
どうしてもcssの行数が長ーくなるのが欠点ですな…。それでも画像の方が重いんだろうと気を取り直してやってみます。
疑似要素のbefore afterを使って吹き出し部分を表現します。
ボーダーのある吹き出しにしてみる。
たのしい毒矢入門を読んだんだ。
部品となるのは、
- 本体の要素p 内容とbackgroundカラーとborder
- beforeによる前の要素 吹き出しの三角部分(pのボーダー色と同色)
- afterによる後の要素 吹き出しの三角部分(pのbackgroundと同色)
beforeとafterで三角を作り、二つの三角形の重なりをずらしてボーダーを表現します。
ボーダーが要らなければ、beforeだけでできます。
1 |
<p class="fuki">たのしい毒矢入門を読んだんだ。</p> |
ベースのp要素にbefore afterの疑似要素を追加する。
たのしい毒矢入門を読んだんだ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* p要素 */ p.fuki { color:#000; padding:20px; background: #9acd32; border:2px solid #ff8c00; border-radius: 5px; position: relative; /* position 起点 */ } /* pの疑似要素 */ p.fuki:before, p.fuki:after { /* before after 共通 */ content: " "; height: 0; width: 0; position: absolute; /* 絶対配置 */ } |
その前に三角の作り方
div#deltaを作り練習してみる。
1 |
<div id="delta">あ?</div> |
上下左右はそれぞれ極端に太さをとったボーダー。辺の端っこが斜めになってて隣の辺と合体してるのが分かります。
widthとheightを0にすることで三角ができる。
1 2 3 4 5 6 7 |
#delta { border-color: #ff8c00 #f5deb3 #d3d3d3 #87ceeb; border-style: solid; border-width: 40px 50px 20px 50px; width: 0px; height: 0px; } |
残したい辺以外のborder-colorを透明にする。
1 2 |
border-color: #ff8c00 transparent transparent transparent; /* 上 右 下 左 */ |
ボーダーの太さborder-widthを変えることで三角形の角度や長さが調整できる。
1 |
border-width: 60px 0px 0px 30px; |
これをpのbeforeとafterに応用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
p.fuki { color:#000; padding:20px; background: #9acd32; border:2px solid #ff8c00; border-radius: 5px; position: relative; } p.fuki:before, p.fuki:after { content: " "; height: 0; width: 0; position: absolute; } p.fuki:before { border-color:#ff8c00 transparent transparent; border-style:solid; border-width:20px 12px 0px 12px; } p.fuki:after { border-color:#9acd32 transparent transparent; border-style: solid; border-width: 20px 12px 0px 12px; } |
位置を調整する
三角形は出来たけど、へんな場所にあるのよね。
(解りやすいように三角を赤に変えた)
たのしい毒矢入門を読んだんだ。
beforeとafterの疑似要素をposition: relative;指定のp要素を起点として配置。bottomなどにマイナス値を使って外側に出します。
afterの三角の位置を上側に数pxずらして、下になっているボーダーカラーと同色にしたbeforeの三角をチラ見せしてボーダーを表現する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
p.fuki{ color:#000; padding:20px; background: #9acd32; border:2px solid #ff8c00; border-radius: 5px; position: relative; } p.fuki:before, p.fuki:after { content: " "; height: 0; width: 0; position: absolute; } p.fuki:before { /* ボーダー色 */ border-color:#ff8c00 transparent transparent transparent; border-style:solid; border-width:20px 12px 0px 12px; bottom: -20px; /* border-width分外側に */ left: 50%; } p.fuki:after { /* 三角内側を上に重ねる */ border-color:#9acd32 transparent transparent transparent; border-style: solid; border-width: 20px 12px 0px 12px; bottom: -16px; /* 位置をずらしてbeforeをボーダー表現 */ left: 50%; } |
たのしい毒矢入門を読んだんだ。
おお!できたよね!
こんなこともできちゃう…はずだった
beforeとafterの配置をうまく使うとカーブの付いた吹き出しも出来るよね。
疑似要素でbeforeとafterで吹き出しと同じ色の円と背景と同じ色の円を重ねてぴよっとした部分を作り、疑似要素の親のdivの後ろへz-index:-1で送る事で実現しています。
1 |
<div id="ring">えっ?毒矢?なにそれこわい。</div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#ring { color: #fff; text-align: center; padding: 50px 30px; height: 20px; width: 300px; background-color: #e9967a; border-radius: 50%; position: relative; } #ring:before,#ring:after{ position: absolute; border-radius: 50%; } #ring:before{ content: " "; background-color: #e9967a; height: 50px; width: 50px; bottom: -15px; left: 60%; z-index: -1; } #ring:after{ content: " "; background-color: #fff; height: 30px; width: 45px; bottom: -15px; left: 66%; z-index: -1; } |
z-index:-1が効かないんだ
実は↑このままのソースでは当ブログでは、疑似要素部分がこつ然と姿を消してしまいます。
z-indexが効いてないんじゃなく凄い下の重なりレベルまで潜っていっちゃってて、間にある要素のbackgroundで隠れてちゃってる模様…かといってz-indexの値を大きくしても解決しないわー。
スタックコンテキストとやらを新たに作ることで回避できます。
スタックコンテキストというのはどうも複雑で詳しくは勉強させてもらたブログを見て頂くとして、とりあえずは簡単に
- スタックレベル レイヤー(重なり)の順番
- スタックコンテキスト その範囲でだけレイヤーを入れ替えられる結界
だとでも思ってください。
疑似要素を親要素である#ringの下に重ねるには?
疑似要素の親は疑似要素をセットした要素になります。この場合は#ringです。
#ringの直接の親、または新たにdivかなんかでラップして作った#ringの親要素=疑似要素からみて先祖要素(じぃちゃん)を用意します。
1 2 3 |
<div id="ring-wrapp"><!-- じぃちゃん --> <div id="ring">えっ?毒矢?なにそれこわい。</div> </div> |
この先祖要素(じぃちゃん)を基準とした結界を作ることで、どっかに潜っていった子(疑似要素で作った吹き出し)を親(楕円)と同じ次元に呼び戻し、楕円のすぐ下に配置します。
スタックコンテキストを作るには先祖要素にstatic以外のpositionをセットします。
この場合rerativが適当かと思われます。
positionでz-indexを明示しない場合、autoが割当てられるのですが、autoは0と同じレベルです。しかし、autoはスタッキングコンテキストを作り出しません。
スタッキングコンテキストを作り出すには、z-indexでスタックレベルを明確に0と指定します。他のスタックコンテキストに影響しないなら0でなくとも整数値であれば良いです。
1 2 3 4 5 |
#ring-wrapp{ background-color:transparent; position: relative; z-index: 0; /* 新たにスタックコンテキストを設定する */ } |
なぜ親がz-index:0ではだめなのさ?
親のz-indexに0や整数値を指定してしまうと、親を基準としたスタックコンテキストが新たに生まれます。
スタックレベルは所属するスタックコンテキスト内でのみ有効なので、親の下に移動する事が出来なくなります。
子要素である疑似要素のz-index:-1はあくまで親内部でのスタックレベルとなります。
親のz-indexは、一段階外側のスタックコンテキスト内でのスタックレベルを指しているので、親が基準の場合、親と子の重なり順が変更されることがありません。
そんで先祖要素を基準としたスタックコンテキストを作り、親を含めたスタックレベルを設定するわけです。
じぃちゃんを基準としたスタックコンテキストの中では次のように扱われます。
じぃちゃん(外側の結界であるため内側のレベルに関与しない 0は外側の世界でのレベル)
親(z-index:auto = デフォルト0)
子after(z-index = -1)
子before(z-index =-1 マークアップ順)
意識の片隅に…スタックコンテキスト
この現象はhtml基準のルートスタックコンテキストしか存在しなかったことが原因です。
index:-1でルートの最下層に配置されてしまい、その上にbackgroundが設定された要素がガンガン乗っかっていたのでマスクされてしまいました。
間にある要素にbackgroundが設定されてなければ疑似要素は表示されます。
もし、positionとbackgroundを多用しているなら、ちょっとややこしいけどスタックコンテキストを意識してみるとレイアウトの自由度が上がるような気がします。
スポンサーリンク
この記事いいね。困っていたことが解決できました。
記事のとおりにやったらできました。
パターンをちょっとだけ変えて、じいちゃんはもちろん作った上で、
親のz-indexに1、
子(before擬似要素)のz-indexは指定せず(autoで0?)、
にしたのですが、子(before記事要素)の方が親よりも前面に表示されてしまいました。親のz-indexは指定できないのでしょうか?
ごめんなさい!長い間サイトを放置してしまいました。
ご質問の件ですが、
じぃちゃんにはz-index 任意の数字(結界を張る)
親のz-index はauto(スタックコンテキストを作らない)
子の要素でスタック順を調整します。子を親の背面に送りたい場合は子のz-indexに -1などマイナス値を指定して下さい。
なお、親のautoはz-index:0と同様の順序になりますので 親0 子-1 で下のスタック順になります。
5年も前の記事にコメントしてしまい大変申し訳ございません。
通常のページでは表示されるのにampページではz-indexマイナスが消えてしまう現象に陥り、困り果てながらサイトを渡り歩くこと丸2日間。
半分諦めかけていたところ、こちらのページにたどり着き、あっさりと解決することが出来ました!
じぃちゃんに感謝ですw
どうしても一言お礼が言いたくて!
本当にありがとうございました。m(_ _)m