HOME / BLOG
BLOG

CSSだけでバスケットコートを描いてみた

デフォルト画像

CSSだけで図形を描く練習は、レイアウト、疑似要素、グラデーション、比率指定をまとめて触れるので、意外と良いトレーニングになります。今回はバスケットボールコートをHTMLとCSSだけで描いてみます。画像もSVGも使いません。

完成形は、外枠、センターライン、センターサークル、ペイントエリア、フリースローサークル、スリーポイントライン、リングまでをCSSで表現する構成です。CodePenへ貼って遊べるコードも用意しています。

作るもの

  • 横長のバスケットボールコート
  • レスポンシブでも比率が崩れにくい外枠
  • 疑似要素と絶対配置で描く各ライン
  • 木目っぽい背景とアクセントカラーのリング
  • HTMLは装飾用のdivだけ、JavaScriptはなし

HTMLの考え方

今回はCSSで線を描く練習なので、HTMLはコート全体と各パーツの要素だけにします。実案件なら装飾目的の要素を増やしすぎない方が良いですが、CodePenのデモでは構造が見える方が学びやすいです。

<div class="court-demo" aria-label="CSSだけで描いたバスケットボールコート">
  <div class="court">
    <div class="center-circle"></div>
    <div class="half-line"></div>

    <div class="paint paint-left"></div>
    <div class="paint paint-right"></div>

    <div class="free-throw free-throw-left"></div>
    <div class="free-throw free-throw-right"></div>

    <div class="three-point three-point-left"></div>
    <div class="three-point three-point-right"></div>

    <div class="rim rim-left"></div>
    <div class="rim rim-right"></div>
  </div>
</div>

CSSのポイント

コート全体はaspect-ratioで比率を固定します。NBAのコート寸法に寄せて94 / 50にすると、横長の雰囲気が出ます。各ラインはposition: absoluteで配置し、円形のラインはborder-radius: 50%clip-pathを組み合わせます。

.court {
  position: relative;
  width: 100%;
  aspect-ratio: 94 / 50;
  border: 4px solid #fff;
}

.center-circle {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 18%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border: 4px solid #fff;
  border-radius: 50%;
}

CodePen埋め込み用エリア

CSSだけで描いたバスケットボールコート
ここにCodePenの埋め込みタグを貼り付けます。CodePenでPenを作成後、Embedコードをこのブロックと差し替えてください。

CodePenでPenを作ったら、上の枠をCodePenの埋め込みタグに差し替えてください。下のコードはHTML、CSS、JSの各パネルへそのまま貼れます。

HTML

<div class="court-demo" aria-label="CSSだけで描いたバスケットボールコート">
  <div class="court">
    <div class="center-circle"></div>
    <div class="half-line"></div>

    <div class="paint paint-left"></div>
    <div class="paint paint-right"></div>

    <div class="free-throw free-throw-left"></div>
    <div class="free-throw free-throw-right"></div>

    <div class="three-point three-point-left"></div>
    <div class="three-point three-point-right"></div>

    <div class="rim rim-left"></div>
    <div class="rim rim-right"></div>
  </div>
</div>

CSS

* {
  box-sizing: border-box;
}

body {
  min-height: 100vh;
  margin: 0;
  display: grid;
  place-items: center;
  padding: 24px;
  background: #111;
  font-family: system-ui, sans-serif;
}

.court-demo {
  width: min(100%, 980px);
}

.court {
  position: relative;
  width: 100%;
  aspect-ratio: 94 / 50;
  overflow: hidden;
  border: 4px solid #fff;
  border-radius: 18px;
  background:
    radial-gradient(circle at 50% 50%, rgb(255 255 255 / .08), transparent 32%),
    linear-gradient(90deg, #c87a35, #a85d26);
  box-shadow: 0 28px 80px rgb(0 0 0 / .45);
}

.court::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(90deg, rgb(255 255 255 / .08) 1px, transparent 1px),
    linear-gradient(rgb(0 0 0 / .08) 1px, transparent 1px);
  background-size: 44px 44px;
  mix-blend-mode: overlay;
}

.half-line {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 4px;
  transform: translateX(-50%);
  background: #fff;
}

.center-circle {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 18%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border: 4px solid #fff;
  border-radius: 50%;
}

.paint {
  position: absolute;
  top: 32%;
  width: 17%;
  height: 36%;
  border: 4px solid #fff;
}

.paint-left {
  left: 0;
  border-left: 0;
}

.paint-right {
  right: 0;
  border-right: 0;
}

.free-throw {
  position: absolute;
  top: 50%;
  width: 17%;
  aspect-ratio: 1;
  transform: translateY(-50%);
  border: 4px solid #fff;
  border-radius: 50%;
}

.free-throw-left {
  left: 8.5%;
  clip-path: inset(0 0 0 50%);
}

.free-throw-right {
  right: 8.5%;
  clip-path: inset(0 50% 0 0);
}

.three-point {
  position: absolute;
  top: 11%;
  width: 34%;
  height: 78%;
  border: 4px solid #fff;
  border-radius: 50%;
}

.three-point-left {
  left: -18%;
}

.three-point-right {
  right: -18%;
}

.rim {
  position: absolute;
  top: 50%;
  width: 3.4%;
  aspect-ratio: 1;
  transform: translateY(-50%);
  border: 4px solid #ff2f63;
  border-radius: 50%;
  background: rgb(255 47 99 / .14);
  box-shadow: 0 0 0 6px rgb(255 47 99 / .18);
}

.rim-left {
  left: 3.2%;
}

.rim-right {
  right: 3.2%;
}

@media (max-width: 640px) {
  .court {
    border-width: 3px;
    border-radius: 12px;
  }

  .center-circle,
  .paint,
  .free-throw,
  .three-point {
    border-width: 3px;
  }
}

JS

// JavaScriptは不要です。
// CodePenではHTMLとCSSだけを貼り付ければ動きます。

実装の分解

  • 外枠:.courtにborderを付け、aspect-ratioで比率を保つ
  • センターライン:.half-lineを中央に置き、縦線として表示する
  • センターサークル:正方形にborder-radius: 50%を指定する
  • ペイントエリア:左右端に長方形を置き、片側のborderを消す
  • フリースローサークル:円を作ってclip-pathで半分だけ見せる
  • スリーポイントライン:大きな円を外側へずらし、コート内に見える部分だけ使う

調整するときのコツ

線が太すぎる場合は、各パーツのborder-widthを統一して調整します。スマホでは線が強く見えやすいので、メディアクエリで少し細くすると見やすくなります。背景を木目っぽくしたい時は、細かいグラデーションを重ねすぎるより、薄いグリッドと影くらいに留める方が軽くまとまります。

よくある失敗

  • 親にposition: relativeがない:絶対配置の基準がずれて、ラインが画面全体基準になります。
  • pxだけで配置する:画面幅が変わった時にコートのバランスが崩れます。幅や位置は%中心にします。
  • borderの太さをバラバラにする:図形としての統一感が落ちます。
  • 装飾要素をHTMLへ増やしすぎる:実案件ではSVGの方が適する場合もあります。
  • スマホで確認しない:小さい画面では線が潰れやすいので、最小幅の見え方を確認します。

まとめ

CSSだけでも、aspect-ratio、絶対配置、border、疑似要素、clip-pathを組み合わせれば、バスケットボールコートのような図形を描けます。実務で毎回CSSだけで図形を描く必要はありませんが、CSSの配置感覚を鍛える題材としてはかなり楽しいです。