CSS講座 / 枠線・角丸・影を使い分ける

borderはボックスの枠、border-radiusは角の丸み、box-shadowは配置寸法を増やさずに描く影を指定します。親の角丸が子を自動的に切り抜くとは限らず、影が切れる場合は祖先のoverflowも確認します。

枠の太さ・形・色を指定する

.card { border: 2px solid #3d6b89; }

border短縮形は幅、線の種類、色をまとめます。solidは実線、dashedは破線、dottedは点線です。styleがnoneなら幅や色だけを指定しても期待した枠は出ません。一辺だけならborder-bottomやborder-block-endを使います。

borderはcontent-boxでは外側へ足され、border-boxでは指定寸法の内側です。outlineやbox-shadowは配置上の空間を増やしません。固定幅のborder-boxで枠を太くすると外幅を保って内容幅が減ります。ボックスモデルとMDNのborderを確認できます。

装飾の枠や影と、キーボードの現在位置を示すフォーカス輪郭は役割が違います。見た目を整えるために操作表示を消さないでください。

角丸の長さとパーセント

.round { border-radius: 12px; }

.circle { width: 80px; height: 80px; border-radius: 50%; }

.oval { width: 160px; height: 80px; border-radius: 50%; }

12pxのような長さは角の半径を指定します。四隅を別々に指定する方法もありますが、まず一値で比べます。50%を幅と高さが同じ枠へ使うと円、異なる枠では楕円になります。パーセントの横半径は幅、縦半径は高さが基準です。

親を丸くしても子の画像が必ず切れるわけではありません。画像自身にも角丸を付けるか、必要なら親でoverflowを切ります。ただしhiddenにすると子の影やフォーカスも境界で切れる場合があります。MDNのborder-radiusで半径の計算を確認できます。

影の値を分解して読む

.shadow { box-shadow: 0 8px 24px 4px rgb(0 0 0 / 16%); }

最初の0は横移動、次の8pxは縦移動、24pxはぼかし半径、4pxは広がり、最後が色と不透明度です。横の正値は右、縦の正値は下へ移動し、負値は反対です。広がりの正値は大きく、負値は小さくします。

最初の二つの長さは必要で、ぼかしや広がりは省略できます。ぼかし半径に負値は使えません。insetなら内側、通常は外側の影です。複数の影を重ねる前に一つの移動と寸法を分けて試します。

影は次のカードをぼかしの分だけ押しのけません。隣の内容を覆うならmarginやレイアウトのgapで本当の間隔を確保します。MDNのbox-shadowを参照できます。

影を切っている親を探す

.frame { padding: 12px; overflow: visible; }

.frame.clip { overflow: hidden; }

.frame .card { box-shadow: 0 18px 20px 8px rgb(0 0 0 / 25%); }

最後の二カードは別の.frameに入り、子の影は同じです。一方の親ははみ出しを見せ、もう一方は切ります。影は親の12pxのpaddingを超えるため、hiddenの親では境界で切れます。

自分自身のoverflow:hiddenと、親が子の外側の影を切る状況を混同しないでください。この例は後者です。影が見えない場合はカードの値だけでなく親のoverflowと枠も調べます。overflowの表示と切り取りで比較できます。

一つの値だけを変えて確認する

次をUTF-8のborders.htmlとして保存します。枠、角丸、外側・内側の影、円と楕円、親による切り取りを同じファイルで比較します。

<!doctype html>

<html lang="en">

<head>

  <meta charset="utf-8">

  <meta name="viewport" content="width=device-width, initial-scale=1">

  <title>Comparing borders, corners, and shadows</title>

  <style>

    * { box-sizing: border-box; }

    body { margin: 24px; color: #333; font: 16px/1.6 sans-serif; background: #f6f8fa; }

    .card { width: 100%; max-width: 320px; margin-block: 24px; padding: 20px; background: white; }

    .border { border: 2px solid #3d6b89; }

    .round { border: 2px solid #3d6b89; border-radius: 12px; }

    .shadow { border-radius: 12px; box-shadow: 0 8px 24px 4px rgb(0 0 0 / 16%); }

    .inset { box-shadow: inset 0 0 12px 2px rgb(0 0 0 / 20%); }

    .shape { width: 80px; height: 80px; margin-block: 16px; border-radius: 50%; background: #6eb898; }

    .oval { width: 160px; }

    .frame { width: 100%; max-width: 320px; padding: 12px; margin-block: 24px; background: #dce8f1; overflow: visible; }

    .frame .card { margin: 0; max-width: none; height: 100px; box-shadow: 0 18px 20px 8px rgb(0 0 0 / 25%); }

    .clip { overflow: hidden; }

  </style>

</head>

<body>

  <h1>Card boundaries and shadows</h1>

  <div class="card border">Card with a border only</div>

  <div class="card round">Border and rounded corners</div>

  <div class="card shadow">Outer shadow</div>

  <div class="card inset">Inset shadow</div>

  <h2>50% Edges: Circles and Ovals</h2><div class="shape" role="img" aria-label="80×80 won"></div><div class="shape oval" role="img" aria-label="160×80 ellipse"></div>

  <h2>Parent: overflow: visible</h2><div class="frame"><div class="card">Child shadow visible outside the parent</div></div>

  <h2>Parent: overflow: hidden</h2><div class="frame clip"><div class="card">Child shadow clipped at the parent boundary</div></div>

</body>

</html>
  1. .borderの2pxを8pxへ変え、広い画面で外幅を保って内側が狭くなることを確認して戻します。
  2. .shapeの幅だけ80pxから160pxへ変え、高さ80pxのまま円が楕円になることを確認して戻します。
  3. .shadowの横移動を20px、縦を-8pxにし、ぼかし24pxは保って方向だけを比較します。続いてぼかし0の輪郭と比べ、元へ戻します。
  4. 広がり4pxを-4pxへ変え、影が小さくなるか確認します。
  5. 二番目の.frameをhiddenからvisibleへ変え、親の外の影が戻ることを確認して元へ戻します。

影が薄い場合は色の不透明度と背景の差、一部だけ切れる場合は親の境界を見ます。角から子が出るなら子自身の角丸も比較し、効果の強さより内容と操作の明確さを基準に判断します。