対象読者
- 「このシャドウはCSSで再現可能かな?」とお悩みのデザイナーの方
- 「このシャドウどうやってCSSで再現しよう、、」とお悩みのフロントエンドの方
注意
- Sass芸(Sassの@for等を利用して、複雑な形を再現したりする行為)ではなく、無理なく使える範囲を狙います
- IEには疲れたのでこの記事中では存在しないことにします
- 作例はPug + Stylusで作成しています
htmlの要素にシャドウをつけたいという欲求
に対する一番シンプルな答えは、CSSのbox-shadowプロパティですね。
これを利用することで、要素のフレームの周囲にシャドウ効果を追加
できます。
ただ、これはCSSの中でも扱いが難しいプロパティかと思います。
苦い顔をしてしまう方も多いのではないでしょうか?
box-shadowの憂鬱
というのも、Adobe XDなど、デザインツールは矩形でなくとも様々な効果を設定することができるためです。
一方のCSSはボックスモデルに基づき、矩形の領域をベースにスタイリングを行いますから、デザインの再現に無理が発生してきます。
その際、box-shadowは、同じくボックスモデルの周囲を装飾するborderと比べ、左右上下での調整が効きにくく、綺麗に表現するには工夫が必要な場面が出てきがちです。
CSSにおけるシャドウ効果は一筋縄ではいかない、、、そう、影
があるということです。
※個人の感想です
この記事では、そんなシャドウ効果の一端をご紹介します。
Lv.1 矩形の要素
box-shadow
を設定するのみです。
See the Pen Lv1.box-shadow by haradabox (@haradabox) on CodePen.
問題ないですね。
Lv.2 凸形の要素(タブ風UI)
タブ選択で表示するコンテンツの切り替えができるUIを考えます。
選択しているタブと、コンテンツの周囲をシャドウで囲いたい、、、という欲求です。
ここからややこしくなってきます。
まず下記をご覧ください。
無邪気に
See the Pen Lv2.box-shadow--faild by haradabox (@haradabox) on CodePen.
タブ要素、コンテンツ要素共に周囲にシャドウを付けていますが、タブ要素にコンテンツ要素のシャドウが被ってしまっています。
これではいけませんね。
少し考えて
擬似要素とz-indexを利用し、被っているシャドウを消しました。
.box
position: relative;
z-index: 0;
&__tab-item
&.--current
position: relative;
box-shadow: 0 1px 3px 0 #333;
background-color: #fff;
// コンテンツのシャドウを隠す
&::after {
position: absolute;
bottom: 0;
left: 0;
height: 3px;
width: 100%;
content: "";
background-color: #fff;
z-index: 3;
}
&__body
position: relative;
z-index: 2;
background-color: #fff;
box-shadow: 0 1px 3px 0 #333;
See the Pen Lv2.box-shadow by haradabox (@haradabox) on CodePen.
よろしそうですね。
Lv.3 凹形の要素(チケット風UI)
お次は凹形の要素です。
チケットのような、切り欠きのある形を再現します。
惜しい
See the Pen Lv3.box-shadow--failed by haradabox (@haradabox) on CodePen.
丸い切り欠きの表現に、before擬似要素 + borderを使いました。
それっぽくはありますが、もうちょいいけそうですね?
それなりに
before擬似要素ではinsetのbox-shadowで円形のシャドウを作成します。
そして、背景色のbox-shadowを加えた、after擬似要素で、不要な箇所をマスクします。
See the Pen Lv3.box-shadow by haradabox (@haradabox) on CodePen.
よりそれっぽくなりました。
Lv.4 ギザギザ形の要素(アイコンと一体に)
Sass芸縛りプレイなので、rotateとskewを駆使して、、、という案は無視します。
となればSVGなんですが、、、
どうやってシャドウをつければいいのだっけ?
drop-shadowはボックスモデルに対して影がつくので、、、
See the Pen Lv4.box-shadow--svg-fail by haradabox (@haradabox) on CodePen.
まあこうなりますよね。
filterを使う
SVGには強い味方、filter: drop-shadowがあります。
表示したいSVGを前面に、シャドウ用のSVGを背面に配置し、シャドウで囲みたい部分(コンテンツなど)を挟み込みます。
また、filter: drop-shadowのプロパティはbox-shadowとは異なるため、数値は微調整します。
.box
position: relative;
z-index: 0; // シャドウが親要素の後ろに入り込まないように付与
&__inner
position: relative;
border-radius: 8px;
padding: 50px;
background: #fff;
box-shadow: 0 1px 3px 0 #333;
z-index: auto; // 指定なしでもOKですが、回り込ませる対象としてわかりやすいかなーということで付与
&__icon
width: 100px;
position: absolute;
top: 0;
left: 0;
transform: translate(-30px, -30px);
&.--shadow
z-index: -1; // シャドウ用のSVG画像を.box__innerの後ろに回り込ませる
.svg-icon.--shadow
filter: drop-shadow( 0 1px 1px #444); // filterでSVG画像に沿ったシャドウを付与
See the Pen Lv4.box-shadow--svg by haradabox (@haradabox) on CodePen.
私は満足です。
おまけ: ロングシャドウ
完璧ではないのですが、お蔵にするには勿体無いので、記載しておきます。
それがこちらです
.box
position: relative;
z-index: 0;
&__inner
position: relative;
background: #fff;
z-index: auto;
&::before
content: "";
position: absolute;
top: -1px;
left: 0;
width: 300px;
height: 100%;
transform: skew(0, 45deg);
transform-origin: 0 0;
background: linear-gradient(90deg, rgba(200,200,200,1) 0%, rgba(255,255,255,1) 100%);
z-index: -1;
&::after
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 300px;
box-sizing: border-box;
transform: skew(45deg);
transform-origin: 0 0;
background: linear-gradient(180deg, rgba(200,200,200,1) 0%, rgba(255,255,255,1) 100%);
z-index: -1;
See the Pen extra.long-shadow by haradabox (@haradabox) on CodePen.
before擬似要素/after擬似要素でシャドウを作成します。 それぞれがシャドウを付与したい要素のheight/widthに依存し、skewで歪めることで汎用性のあるシャドウにしています。グラデーションの角度調整(グラデーションの終端が要素の形になってしまう)が課題ですね。
まとめ
シャドウ効果はこんな感じで工夫が求められることが多いです。
しかしながら、裏を返せば工夫の発揮しどころ、実装を楽しめるポイントでもあります。
「他にもこんなシャドウ再現できまっせ」、ありましたら是非コメントをば!