Web便利ツール集

CSSのbox-shadowで自然な影をつけるコツ|不自然に見える原因と対処

CSSbox-shadowUIデザインダークモード

box-shadow は値を4つ並べるだけの単純なプロパティですが、適当に設定すると「なんとなく安っぽい」見た目になります。原因はほぼ決まっているため、いくつかの原則を押さえれば改善できます。

構文の確認

box-shadow: offset-x offset-y blur spread color;
意味効果
offset-x横方向のずれ正で右、負で左
offset-y縦方向のずれ正で下、負で上
blurぼかしの半径大きいほど柔らかい
spread影の拡大・縮小正で大きく、負で小さく
color影の色通常は半透明で指定
/* 下方向に4px、8pxぼかし、黒の15% */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);

spread は省略できます。実務では省略するか、負の値で使うことが多い値です。

不自然に見える4つの原因

原因1:横方向にずらしている

現実世界の光は、ほとんどの場合「上から」当たります。 天井の照明も太陽も上にあるため、影は真下に落ちます。

box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.2);   /* 右下にずれて不自然 */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);    /* 真下。自然に見える */

offset-x は原則 0 にしてください。 これだけで印象が大きく変わります。横にずらすのは、意図的に斜光を表現したい場合だけです。

原因2:影が濃すぎる・硬すぎる

box-shadow: 0 2px 2px rgba(0, 0, 0, 0.5);   /* 濃くて硬い */
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);  /* 薄くて柔らかい */

ぼかしを大きく、透明度を低くするのが基本です。目安として、bluroffset-y2〜3倍を取ります。

offset-yblur の目安不透明度の目安
1〜2px3〜6px0.05〜0.10
4px8〜12px0.10〜0.15
8px16〜24px0.12〜0.20

「影があることに気づかないが、外すと平坦に見える」くらいが適量です。

原因3:影の色が純粋な黒

これは見落とされがちですが、効果が大きい点です。

現実の影は、周囲の光を反射してわずかに色味を帯びます。 純粋な黒(rgba(0,0,0,…))の影は、背景に色がある場合に濁って見えます。

/* 背景が青みがかった白の場合 */
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);       /* 灰色っぽく濁る */
box-shadow: 0 4px 12px rgba(30, 41, 59, 0.12);    /* 背景に馴染む */

影の色は、背景色を暗くした色相を使うと自然になります。適切な色を探すにはカラーコード変換ツールでHSLの明度だけを下げると調整しやすくなります。

原因4:影が1段しかない

現実の影には、接地面近くの濃い影と、遠くまで広がる薄い影の2種類があります。1つのシャドウでは、このどちらかしか表現できません。

box-shadow はカンマ区切りで複数指定できます。

box-shadow:
  0 1px 2px rgba(0, 0, 0, 0.08),
  0 4px 12px rgba(0, 0, 0, 0.10);
  • 1つ目:小さく濃い影 → 接地感を出す
  • 2つ目:大きく薄い影 → 浮遊感を出す

この2段構成が、質の高いUIで広く使われている手法です。 1行増えるだけで、見た目の完成度が明確に変わります。

高さ(elevation)で使い分ける

UIでは、要素の重要度=浮いている高さとして影を使い分けます。高さが上がるほど、offset-yblur を大きく、影を薄く広げます。

用途
ごく浅い(カード)0 1px 3px rgba(0,0,0,0.08)
中程度(ドロップダウン)0 4px 12px rgba(0,0,0,0.12)
高い(モーダル)0 12px 32px rgba(0,0,0,0.16)

重要なのは、サイト全体で段階を統一することです。3段階程度を決めて、それだけを使い回してください。ページごとに違う影を使うと、統一感が失われます。

CSS変数にしておくと管理が楽になります。

:root {
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.12);
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.16);
}

inset:内側の影

inset を付けると、影が内側に描画されます。

box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);

へこんだ表現に使います。入力欄、押された状態のボタン、進捗バーの溝などが該当します。

spread を負の値にして枠線のように使う応用もあります。

/* レイアウトを崩さない内側の枠線 */
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);

border と違って要素のサイズに影響しないため、ホバー時に枠線を出したい場合に便利です。border で同じことをすると、ホバーのたびにレイアウトが1pxずれます。

ダークモードでの注意

暗い背景では、黒い影はほとんど見えません。 ライトモードで作った影をそのままダークモードに適用すると、階層が完全に失われます。

対処法は2つあります。

/* 方法1:影を濃くする */
@media (prefers-color-scheme: dark) {
  .card { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); }
}

/* 方法2:背景の明度差で階層を表現する(推奨) */
@media (prefers-color-scheme: dark) {
  .card {
    background: #1e293b;   /* 地の色より明るくする */
    box-shadow: none;
  }
}

ダークモードでは、影ではなく「背景を明るくする」ことで浮いて見せるのが定石です。 暗い環境では、光が当たる面が明るくなるほうが物理的にも自然です。

パフォーマンス上の注意

box-shadow は描画コストがあるプロパティです。通常は問題になりませんが、次のケースでは注意してください。

  • 大きな blur 値を多数の要素に適用する(一覧の全カードなど)
  • スクロールやアニメーションと同時に影を変化させる

ホバー時に影を変える場合、box-shadow のアニメーションは負荷が高くなることがあります。滑らかさが必要な場面では、transformopacity の変化と組み合わせるか、影を持つ疑似要素の opacity を変える手法が使われます。

/* 影そのものを animate するより軽い書き方の例 */
.card { transition: transform 0.2s; }
.card:hover { transform: translateY(-2px); }

値を決める手順

数値を頭の中で決めるのは非効率です。視覚的に調整して、決まった値をコピーするのが早道です。

CSSボックスシャドウ生成ツールでは、各値をスライダーで調整しながらリアルタイムでプレビューでき、複数シャドウの重ねがけと inset にも対応しています。プリセットから始めて微調整するのが効率的です。

グラデーションと組み合わせて立体感を出す場合は、CSSグラデーション生成ツールも併用できます。

まとめ

  1. offset-x は 0。 光は上から当たる
  2. bluroffset-y の2〜3倍、不透明度は0.1前後
  3. 影の色は純粋な黒を避け、背景色を暗くした色を使う
  4. 2段重ねで接地感と浮遊感を両立させる
  5. サイト全体で3段階程度に統一し、CSS変数で管理する
  6. ダークモードでは影ではなく背景の明度差で階層を表す

影は「あることに気づかれない」のが正解です。目立つ影は、たいてい強すぎます。

この記事で使うツール

関連記事