LLMS

CSS shape()で柔軟な図形を定義する

CSS shape()関数は、path()では使えなかったパーセンテージやcalc()、CSS変数を活用した図形定義を可能にします。line、curve、smooth、arcなどのshape-commandの使い方とpath()との違いを解説します。

公開: 2026年3月8日(日)
更新: 2026年3月8日(日)

はじめに

CSSで図形を定義する方法として、circle()polygon()path()などの<basic-shape>関数があります。 しかし、それぞれに制限がありました。

  • circle() / ellipse(): 円と楕円しか描けない
  • polygon(): 直線の辺しか描けず、曲線は表現できない
  • path(): SVGのパス構文を使うため単位なしのピクセル値しか指定できず、レスポンシブに対応できない

この記事ではpath()の制限に注目します。 path()はSVGのパス構文を使うため%calc()が使えず、要素のサイズに応じて図形を変化させるにはSVGに頼る必要がありました。

/* path()は固定のピクセル値しか使えない */
clip-path: path('M 50 0 L 100 100 L 0 100 Z');

shape()はこの問題を解決する新しい<basic-shape>関数です。 CSSの単位や関数をフル活用しながら、直線・曲線・円弧を自由に組み合わせた図形を定義できます。

shape()

shape()は主にclip-pathoffset-pathプロパティで使用できます。

clip-pathで使う場合、shape()で定義した図形の内側だけが表示され、外側は切り取られます。

/* shape(<fill-rule>?, from 開始点, <shape-command>, ...) */
clip-path: shape(from 50% 0%, line to 100% 100%, line to 0% 100%, close);

<fill-rule>polygon()path()と同じく指定できます。 fromで開始点を指定し、カンマ区切りで描画コマンドを並べます。 座標は参照ボックス(clip-pathのデフォルトはborder-box)の左上隅を原点とし、<length-percentage><length>または<percentage>)で指定します。

shape-command

<shape-command>は以下のコマンドで構成されます。

  • <move-command>: 描画せずに現在位置を移動
  • <line-command>: 直線を描画
  • <horizontal-line-command>: 水平方向に直線を描画
  • <vertical-line-command>: 垂直方向に直線を描画
  • <curve-command>: ベジェ曲線を描画
  • <smooth-command>: 滑らかに接続する曲線を描画
  • <arc-command>: 楕円弧を描画
  • close: パスを閉じる

toとby

closeを除く各コマンドは、座標の指定方法としてto(絶対座標)とby(相対座標)の2種類を持ちます。

/* to: 参照ボックスの左上隅からの絶対座標 */
shape(from 0% 0%, line to 100% 100%)

/* by: 直前のコマンドの終点からの相対座標 */
shape(from 50px 50px, line by 50px 50px)
/* 終点は(100px, 100px)になる */

close

開始点まで直線を描いてパスを閉じるコマンドです。

closeは座標を取らず、現在位置からfromで指定した開始点(または直前のmoveの位置)に向かって自動的に直線を引きます。

実例は他のコマンドと合わせて紹介しています。

line-command / horizontal-line-command / vertical-line-command

直線を描きます。 lineは任意の方向に、hlineは水平方向のみ、vlineは垂直方向のみ移動します。

clip-path: shape(
  from 0% 0%,        /* 左上から開始 */
  line to 100% 0%,   /* → 右上へ */
  line to 100% 50%,  /* ↓ 右端の中央へ */
  hline to 0%,       /* ← 左端へ(水平のみ) */
  vline to 100%,     /* ↓ 下端へ(垂直のみ) */
  line to 100% 100%, /* → 右下へ */
  close              /* 左上に戻って閉じる */
);

move-command

描画せずに現在位置を移動します。 closeの後に新しいサブパスを始める場合に使います。

clip-path: shape(
  from 5% 10%,     /* 左上から開始 */
  hline to 45%,    /* → 右上へ */
  vline to 90%,    /* ↓ 右下へ */
  hline to 5%,     /* ← 左下へ */
  close,           /* 左上に戻って閉じる */
  move to 55% 10%, /* 描画せずに右側へ移動 */
  hline to 95%,    /* → 右上へ */
  vline to 90%,    /* ↓ 右下へ */
  hline to 55%,    /* ← 左下へ */
  close            /* 左上に戻って閉じる */
);

curve-command

ベジェ曲線を描きます。 withの後に制御点を指定し、曲線の曲がり具合を決めます。 制御点が1つなら2次ベジェ、2つ(/区切り)なら3次ベジェ曲線になります。

clip-path: shape(
  from 0% 0%,                 /* 左上から開始 */
  hline to 100%,              /* → 右端へ */
  vline to calc(100% - 48px), /* ↓ 突起の始点へ */
  /* 2次ベジェ曲線: 右側の突起 */
  curve to 50% 95% with 75% 95%,
  /* 3次ベジェ曲線: 左側の突起 */
  curve to 0% calc(100% - 48px) with 40% 95% / 25% calc(100% - 48px),
  close                       /* 左上に戻って閉じる */
);

この例はツールチップのような吹き出し図形です。 底辺の突起の高さが48px固定で、全体の幅と高さは要素に追従します。 path()では実現できなかった、固定値と相対値を混在させたレスポンシブな図形です。

smooth-command

直前の曲線コマンド(curvesmooth)の制御点を自動で反転させ、滑らかに接続する曲線を描きます。 直前が曲線コマンドでない場合は、現在位置を制御点として使います。

clip-path: shape(
  from 0% 50%,                 /* 左端の中央から開始 */
  curve to 25% 0% with 10% 0%, /* 最初の山 */
  smooth to 50% 50%,           /* 滑らかに谷へ */
  smooth to 75% 0%,            /* 滑らかに次の山へ */
  smooth to 100% 50%,          /* 滑らかに右端へ */
  close
);

arc-command

楕円弧を描きます。 ofの後に楕円の半径を指定します。 1つ目が横方向(rx)、2つ目が縦方向(ry)の半径で、1つだけ指定すると円弧になります。

clip-path: shape(
  from 50% 15%,                       /* 上端の中央から開始 */
  arc to 50% 85% of 60px 55px cw, /* rx=60px, ry=55pxの楕円に沿って時計回りに弧を描く */
  close
);
  • 半径(必須): 1つなら円弧、2つなら楕円弧
  • cw / ccw(デフォルト: ccw): 時計回り / 反時計回り
  • large / small(デフォルト: small): 大きい弧 / 小さい弧
  • rotate <angle>(デフォルト: 0deg): 楕円の回転角度

largeを指定すると、同じ2点間でも大きい方の弧が選ばれます。

clip-path: shape(
  from 50% 15%,
  arc to 50% 85% of 60px 55px large cw,
  close
);

rotateを指定すると、楕円自体を回転させることができます。

clip-path: shape(
  from 50% 15%,
  arc to 50% 85% of 80px 50px cw rotate 45deg,
  close
);

path()との比較

shape()の最大の利点は、CSSの単位と関数をフルに使えることです。

.triangle {
  /* path()では固定のピクセル値しか使えない */
  clip-path: path('M 0 0 L 200 64 L 0 128 Z');

  /* shape()ならパーセンテージが使える */
  clip-path: shape(from 0% 0%, line to 100% 50%, line to 0% 100%, close);
}

path()版は座標値が固定なので要素サイズに追従しないですが、shape()版は要素の幅と高さに追従します。

path()とshape()の比較

100%

path()

固定のピクセル値のため、幅を変えると三角形が崩れる

shape()

パーセンテージのため、幅を変えても三角形を維持する

スライダーで幅を変えると、path()は固定のピクセル値のため三角形が崩れますが、shape()はパーセンテージ指定のため常に三角形を維持します。

おわりに

shape()は、path()の表現力とCSSの柔軟性を兼ね備えた関数です。 %calc()、CSS変数が使えるため、要素のサイズに追従する図形をCSSだけで定義できます。 line、curve、smooth、arcといったコマンドを組み合わせることで、直線から複雑な曲線まで幅広い図形に対応できます。 path()の固定ピクセル値に制約を感じていた場面で、shape()が有効な選択肢になります。

0
もくじ

©︎ 2024〜2026 k8o. All Rights Reserved.