IE10+にも対応したCSSで作る吹き出しの三角形部分に影を適用する
色んなブログで紹介されているCSSだけでできる吹き出しのデザイン。これに box-shadow
で影をつけても三角形部分に影は適用されません。実は filter
プロパティの drop-shadow
を使えば三角形部分にも影をつけることができますが、残念なことにIEには対応していません。そこでSVGを使って対応してみたいと思います。
SVGで box-shadow
を表現
まず、三角形に影をつける前に、SVGで影をどのように表現するのか紹介します。
<div class="box-shadow"></div>
.box-shadow {
width: 100px;
height: 100px;
background-color: #fff;
box-shadow: 0 0 30px #000;
}
CSSで100×100の白い正方形に影をつけた図形をSVGで表現してみます。
<svg width="100" height="100">
<filter id="shadow" x="-100%" y="-100%" width="300%" height="300%">
<feGaussianBlur in="SourceAlpha" result="GaussianBlur" stdDeviation="10"/>
<feMerge>
<feMergeNode in="GaussianBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<polygon points="0,0 100,0 100,100 0,100" fill="#fff" filter="url(#shadow)"/>
</svg>
ガウシアンフィルタで影を表現します。stdDeviation
の値はCSSで指定した box-shadow
の 30px
を3で割った値の 10
を指定します。
svg {
overflow: visible;
}
Chromeではデフォルトで <svg>
要素に overflow: hidden
が指定されていて影が表示されないので visible
を指定してください。ちなみにこれで6時間くらいハマりました。
透明度を指定する場合
box-shadow: 0 0 30px rgba(0, 0, 0, .6);
黒で透明度60%の影をつけたいときどうすればよいか。
<svg width="100" height="100">
<filter id="shadow" x="-100%" y="-100%" width="300%" height="300%">
<feColorMatrix in="SourceAlpha" result="ChangeAlpha" type="matrix" values="0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 .6 0"/>
<feGaussianBlur in="ChangeAlpha" result="GaussianBlur" stdDeviation="10"/>
<feMerge>
<feMergeNode in="GaussianBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<polygon points="0,0 100,0 100,100 0,100" fill="#fff" filter="url(#shadow)"/>
</svg>
<feColorMatrix>
の values
に行列を指定して変換します。.6
は透明度60%のことで、この数値を変えれば透明度を自由に変更することができます。
色を変更する場合
box-shadow: 0 0 30px rgb(220, 151, 51);
たとえばこのようにオレンジ色の影をつけたいときはどうすればよいか。
<svg width="100" height="100">
<filter id="shadow" x="-100%" y="-100%" width="300%" height="300%" color-interpolation-filters="sRGB">
<feColorMatrix in="SourceAlpha" result="ChangeAlpha" type="matrix" values="0 0 0 0 .862745
0 0 0 0 .592157
0 0 0 0 .2
0 0 0 1 0"/>
<feGaussianBlur in="ChangeAlpha" result="GaussianBlur" stdDeviation="10"/>
<feMerge>
<feMergeNode in="GaussianBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<polygon points="0,0 100,0 100,100 0,100" fill="#fff" filter="url(#shadow)"/>
</svg>
先ほどと同じように <feColorMatrix>
を使います。今回の場合は透明度は変更しないので 1
としています。行列に新たに3つの値が設定されています。それらは box-shadow
で指定したRGBそれぞれを255で割った値を指定します。例えば、.862745
は220/255の結果です。これで、box-shadow
と同じ色を表現できます。
また、<filter>
要素に color-interpolation-filters="sRGB"
を指定します。これを指定しないと正しくRGBA値で変換されません。
SVGで三角形を作成
<svg width="200" height="100" viewBox="0 0 100 50">
<polygon points="50,50 0,0 100,0" fill="#f1c40f"/>
</svg>
<polygon>
要素で三角形の各点をプロットします。
吹き出しを作成
<div class="balloon">
吹き出し
<svg class="balloon-triangle" viewBox="0 0 100 50">
<polygon points="50,50 0,0 100,0" fill="#f1c40f"/>
</svg>
</div>
.balloon {
display: inline-block;
position: relative;
padding: .6em 2.4em;
border-radius: .25em;
box-shadow: 0 0 9px rgba(0, 0, 0, .55);
background-color: #f1c40f;
}
.balloon-triangle {
position: absolute;
left: 50%;
bottom: -11px;
width: 24px;
height: 12px;
overflow: visible;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
三角形に影を適用
<div class="balloon">
吹き出し
<svg class="balloon-triangle" viewBox="0 0 100 50">
<filter id="shadow" x="-100%" y="-100%" width="300%" height="300%" color-interpolation-filters="sRGB">
<feColorMatrix in="SourceAlpha" result="ChangeAlpha" type="matrix" values="0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 .55 0"/>
<feGaussianBlur in="ChangeAlpha" result="GaussianBlur" stdDeviation="9"/>
<feMerge>
<feMergeNode in="GaussianBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<polygon points="50,50 0,0 100,0" fill="#f1c40f" filter="url(#shadow)"/>
</svg>
</div>
正方形の場合、stdDeviation
は3で割った値にしていましたが、三角形の場合は 9px
ならそのまま 9
と指定します。ここらへんの計算方法がよくわかっていません。
また、三角形部分の周り全部に影が表示されてしまっています。上の影は必要ないので修正します。
三角形上部の影を消去
<div class="balloon">
吹き出し
<svg class="balloon-triangle" viewBox="0 0 100 50">
<filter id="shadow" x="-100%" y="0" width="300%" height="300%" color-interpolation-filters="sRGB">
<feColorMatrix in="SourceAlpha" result="ChangeAlpha" type="matrix" values="0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 .55 0"/>
<feGaussianBlur in="ChangeAlpha" result="GaussianBlur" stdDeviation="9"/>
<feMerge>
<feMergeNode in="GaussianBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<polygon points="50,50 0,0 100,0" fill="#f1c40f" filter="url(#shadow)"/>
</svg>
</div>
<filter>
要素の y
に 0
を指定すれば上の影はカットされます。
もし、インラインSVGが嫌ならData URI化して backgrond
に埋め込むと良いです。
CSS本執筆しました!!!
CSS本出します!1/29発売予定
— たかもそ@CSS本1/29発売!! (@takamosoo) 2018年12月31日
自分がCSS学びたての頃にもっとはやく知りたかったテクニックを載せています。CSSの基礎知識について解説していないので、中級者〜向けとなります。CSS入門書を読んではみたものの、思い通りに作れない人にオススメです。
よろしくお願いします。https://t.co/fkz1dM03Pj pic.twitter.com/suYyaPqwIs