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埋め込み用エリア
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の配置感覚を鍛える題材としてはかなり楽しいです。
