FlowingDev

CSSの`box-shadow`を徹底解説:Web上で光と奥行きを描くテクニック

CSSの`box-shadow`がWebページに奥行きと階層構造を生み出す仕組みを学びましょう。単純なドロップシャドウから一歩進んで、リアルでレイヤー化されたライティングエフェクトを作成する方法を解説します。

ツールを試す: ボックスシャドウジェネレーター

ズバリ一言で

CSSのbox-shadowプロパティを使えば、要素のフレームから1つ以上の影を落として、Webページに奥行きや高さ、内側への輝きといった錯覚を作り出せるんだ。

こいつが解決する問題

初期のWebデザインというフラットランド(平坦な世界)では、すべてがツライチだった。奥行きもなければ、高さもない。何かを目立たせたければ、大きくするか、もっと明るい色にするしかなかった。ボタンをクリックできそうに見せるために影をつけたいなんて思ったら、そりゃもう地獄の始まりさ。

当時の「解決策」といえば、Photoshopを立ち上げて、ドロップシャドウ付きのボックスを作り、画像として書き出すこと。そして、その画像を要素の背景として使うんだ。控えめに言っても、これはひどいハックだった。画像は重く、サイトの表示を遅くする。高解像度スクリーンではピクセルがギザギザに見える。ボックスのサイズを変えたくても、画像はうまく拡大縮小できない。おまけに、デザイナーが影を「ぼんやりした灰色」から「もうちょいぼんやりした灰色」に変えたいと言い出したら、またPhotoshopに戻って最初からやり直し。脆くて、非効率で、メンテナンスの悪夢だったわけだ。

そこへ、CSS3がスーパーヒーローのように颯爽と登場した。box-shadowプロパティは、開発者にコードで影を生成する手段を与えてくれた。突如として、影はもはや不格好なビットマップの成果物ではなくなり、動的で、スケーラブルで、アニメーションも可能なドキュメントの一部になったんだ。

当初、開発者たちはPhotoshopで作っていたのと同じ単純なドロップシャドウを作るためにこれを使った。でも、box-shadowの真の力は、古いやり方を再現することだけじゃなく、新しいやり方を可能にすることにあった。Googleのマテリアルデザインのようなデザインシステムの礎となり、影と高さを使って階層を伝え、触れるような紙のようなインターフェースを作り出すのに使われるようになったんだ。box-shadowは、画像で奥行きを偽装する問題を解決し、ブラウザ上で直接、光と影を描き出すための、ネイティブでコードベースな方法を与えてくれたってわけ。

内部の仕組み

一見すると、box-shadowはシンプルに見える。でも、優れたマジックがそうであるように、そのエレガントさの裏には驚くほどの奥深さが隠されている(ダジャレのつもりだよ)。

1つの影の解剖学

1つの影は、ブラウザにどこに配置し、どれくらいぼかし、どれくらいの大きさにし、何色にするかを伝える一連の値で定義される。

基本的な構文は box-shadow: offset-x offset-y blur-radius spread-radius color; だ。これを分解してみよう。

パラメータ 機能 値の例
offset-x 影を水平方向に移動させる。正の値で右へ、負の値で左へ。 10px
offset-y 影を垂直方向に移動させる。正の値で下へ、負の値で上へ。 10px
blur-radius ぼかし具合を制御する。0だとシャープでくっきりした影に。値を大きくすると、よりソフトで拡散したぼかしになる。 20px
spread-radius 影の元となるシェイプを拡大または縮小する。正の値で要素より影が大きくなり、負の値で小さくなる。 5px
color 影の色。rgba(0, 0, 0, 0.1)のような半透明色を使うのがリアルな効果の鍵。 rgba(0,0,0,0.5)

厳密にはoffset-xとoffset-yだけが必須だけど、ぼかしや色のない影なんて、影とは言えないよね。

/* シンプルな影: 下へ10px、右へ10px、ぼかし20px、50%不透明度の黒 */
.card {
  box-shadow: 10px 10px 20px rgba(0, 0, 0, 0.5);
}

insetキーワード:ボックスの内側へ

デフォルトでは、影は要素の外側に落とされ、まるで要素がページの上に浮いているかのように見える。でも、先頭にinsetキーワードを追加することで、これを完全にひっくり返すことができるんだ。

.pressed-button {
  /* この影は要素のパディングボックスの*内側*に描かれる */
  box-shadow: inset 5px 5px 10px rgba(0, 0, 0, 0.2);
}

insetシャドウは、要素のborderの内側、背景の上に描画される。これは「押された」ボタンの効果や、凹んで見える入力フィールド、画像へのビネット効果などを作るのに最適だ。ページの上に積み上げるんじゃなくて、ページに彫り込むような感じだね。

影のレイヤー化:リアルな奥行きを生み出す秘訣

ここからが真の腕の見せ所だ。box-shadowプロパティは、カンマ区切りで複数の影のリストを受け付けることができる。これこそが、2008年頃の不格好なPhotoshopエフェクトっぽくない、自然に見える影を作るための秘訣なんだ。

現実世界の影は、単一で均一な塊じゃない。机の上の物を思い浮かべてみてほしい。たいてい、そのすぐ下には小さくて暗く、シャープな影(本影、umbra)があり、その周りにはより大きく、ソフトで、透明な影(半影、penumbra)が広がっている。

これは、複数のbox-shadow定義を重ねることで再現できる。ブラウザはそれらを積み重ねて表示し、リストの最初の影が一番上にくる。

.super-card {
  box-shadow:
    /* レイヤー1 (上): 「本影」用の、きゅっと締まった暗い影 */
    0 4px 6px -1px rgba(0, 0, 0, 0.1),
    /* レイヤー2 (下): 「半影」用の、より広くソフトな影 */
    0 2px 4px -1px rgba(0, 0, 0, 0.06);
}

この短いスニペットが作り出す影は、単層のどの影よりもはるかにリアルだ。2つか3つ(あるいはそれ以上!)の繊細な影を組み合わせることで、UIをより触感的に、そして洗練されたものに見せる、説得力のある奥行きと高さの錯覚を生み出せる。このテクニックは多くのモダンなデザインシステムの基礎となっていて、ツールがこれらのレイヤー化されたスタックを自動生成してくれることも多い。

現場での実話

「浮遊する」アクションボタン事件

あるスタートアップが、人気のモバイルアプリのWeb版を開発していた。その特徴的なUI要素は、右下に浮かぶフローティングアクションボタン(FAB)だった。このタスクを任された若手開発者は、安易にbox-shadow: 0 5px 10px black;を適用した。デザインレビューで、リードデザイナーは顔をしかめた。「浮いているように見えないわね」と彼女は言った。「なんだか奇妙な黒いシミみたい」。ボタンはページの上に浮いているのではなく、くっついてしまっているように見えた。

イライラした開発者は、高度なシャドウテクニックを掘り下げた。そして、レイヤー化を発見したんだ。単一のきつい影を3層のスタックに置き換えることで、問題を解決したんだ。1つ目はボタンのすぐ下にある非常に小さく、比較的暗い影で、ボタンを地面に固定する役割。2つ目は中くらいの、少し明るい影で、その形状を定義する。3つ目は大きく、非常に透明で、強くぼかした影で、周囲に光が拡散する様子をシミュレートした。結果は劇的だった。ボタンは本当に浮いているように見え、柔らかく複雑な影を落とし、本物の高さの感覚を与えた。

教訓: リアルな奥行きは、本物の光を模倣することから生まれる。サイズ、ぼかし、不透明度が異なる繊細な影を重ねることが、要素を「浮かせる」ための鍵なんだ。

パフォーマンス消失ミステリー

あるデータ分析会社が、美しい新しいダッシュボードをローンチした。そこには様々な指標を示すカードが並んでいて、それぞれにホバーすると影が大きくなってカードが持ち上がるという、しゃれたエフェクトがついていた。開発用のハイエンドなラップトップでは、バターのように滑らかだった。しかし、サポートチケットが殺到し始めた。「新しいダッシュボード、めちゃくちゃ遅い!」「スクロールするとPCのファンがジェット機みたいに回る!」

パフォーマンスチームが調査に乗り出した。ブラウザの開発者ツールを使うと、ユーザーがスクロールしたりカードにホバーしたりするたびに、タイムラインプロファイラが真っ赤になるのが見えた。ブラウザは「ペイント」に膨大な時間を費やしていた。犯人は?各カードのホバー時に、とてつもなく巨大な単一の影が設定されていたのだ:box-shadow: 0 50px 100px -20px rgba(0,0,0,0.5);。巨大なぼかし半径(100px)のせいで、ブラウザはアニメーションのフレームごとに画面の広大な領域を再描画しなければならなかった。

解決策は2つあった。まず、そのコストの高い単一の影を、はるかに小さいぼかし半径で同様の見た目を実現する、より最適化された複数レイヤーの影に置き換えた。次に、ホバーエフェクトでは、box-shadow自体ではなくtransform: scale(1.05)プロパティをトランジションさせるようにした。これはブラウザがアニメーションさせるのにずっとコストが低い。ジャンク(カクつき)は消え、ユーザーはハッピーになった。

教訓: タダ飯なんてない。大きくてぼやけた影の視覚的な魅力には、相応のパフォーマンスコストが伴うんだ。特に影をアニメーションさせるときは、ぼかし半径に注意しよう。

「押されてない」押し込みボタン

あるUIデザイナーが、アクティブなときに「押し込まれた」ように見えるトグルフィルターのセットを欲しがっていた。開発者の最初の試みは、単純なクラス変更だった。アクティブなボタンは背景色が暗くなり、1pxの実線insetボーダーがつく。機能はするが、何かが違う。それは表面に押し込まれたボタンではなく、平らなボタンの内側に線が引かれているようにしか見えなかった。

シニア開発者がそのコードを見て、一行の提案をした。「box-shadow: inset ...を試してみて」。ボーダーでごまかす代わりに、ちゃんとしたinsetシャドウを使った。上と左にソフトで暗いinsetシャドウを、下と右に非常に明るい、ほとんど白に近いinsetシャドウを。これは、左上からの光源が「凹んだ」領域の内側に影を落とし、反対側のエッジにハイライトを作るのを完璧にシミュレートした。効果は即座に、そして説得力のあるものだった。ボタンはもはや単に「アクティブ」に見えるだけでなく、物理的に押し込まれているように見えた。

教訓: 凹んだり押し込まれたりした効果を作りたいときは、borderやbackgroundで無理やり作ろうとしないで。box-shadowのinsetキーワードこそが、その内側の影の錯覚を作り出すために特別に作られた、うってつけのツールなんだ。

よくある間違いと落とし穴

  • 真っ黒を使う: 現実世界で#000000の影を落とすものはない。本物の影は環境光に影響され、周囲の色を取り込む。大きな一歩は、rgba(0, 0, 0, 0.1)のような半透明の黒を使うこと。さらに良い一歩は、アプリのプライマリカラーや背景色の、暗く彩度を落としたバージョンを使うことだ。
  • 単一のきつい影: 単一で暗く、エッジの効いたbox-shadowは、デザインを古臭く見せる一番の近道だ。2010年ならまだしも、今日では「開発者がテキトーに作った感」が丸出しになる。レイヤー化こそが、モダンでプロフェッショナルなUIへの道だ。
  • box-shadowプロパティのアニメーション: できなくはないが、多くの場合パフォーマンスの罠になる。blur-radiusやspread-radiusのようなプロパティをアニメーションさせると、ブラウザはフレームごとにコストの高い再描画処理を強制され、カクカクしたアニメーションにつながる可能性がある。代わりにtransformやopacityをアニメーションさせる方が、たいていスムーズだ。
  • 光源を忘れる: よくある間違いは、ページ上のすべての要素に、その位置に関係なく、全く同じbox-shadow(例:10px 10px ...)を適用すること。優れたデザインは、一貫した仮想的な光源(通常は左上から)を暗示する。つまり、影は一般的に右下に落ちるべきだ(offset-yは正、offset-xは正またはゼロ)。一貫性のない影は、UIを混沌として不自然に感じさせる。
  • 下手な影なら、ない方がマシ: 素敵でレイヤー化された影を作る時間やツールがないなら、ボーダーや微妙な背景色の変更といった他のテクニックで要素を区切る方が良い場合が多い。下手な影は、影がない場合よりもデザインを安っぽく見せてしまうことがある。

なぜこいつをチェックしておくべきか

box-shadowを理解することは、フロントエンドのコードやデザインに触れる者にとって、避けては通れない。これは、モダンで直感的なインターフェースを作成するための、CSSの武器庫の中で最も強力なツールの1つだ。

  • 階層構造を作る: 影は、私たちの脳に何が重要かを伝える。より目立つ影を持つ要素は、私たちに「より近く」見え、それゆえにより重要に感じられる。これは、ページ全体を覆うモーダルダイアログから、主要なコールトゥアクションボタンまで、複雑なUIを通してユーザーの注意を導くための基本だ。
  • 境界線をソフトに定義する: box-shadowが登場する前、我々は要素を区切るのにborder: 1px solid grey;を使っていた。影は、同じ区切りをはるかにソフトで、より有機的な方法で作成することを可能にする。サイドバーとメインコンテンツの間の微妙な影は、硬い線よりも心地よく感じられる。
  • 触感のあるインターフェースを構築する: 上手に作られた影(外側も内側も)は、デジタルインターフェースに触感をあたえることができる。ボタンにはクリックできそうな感じを、入力欄には入力できそうな感じを与える。これは単なる装飾ではなく、ユーザビリティの機能的な一部なのだ。

box-shadowをマスターすること、特にレイヤー化と繊細さの技術は、単に動くものを作る開発者と、美しく動くものを作る開発者を分ける明確な指標になるんだ。

さらに深く知る

理論はOK。さあ手を動かそう — 100%ブラウザ内で。

ツールを試す: ボックスシャドウジェネレーター