CSSのcorner-shapeで角を斜めに切る・へこませる方法

​​CSS​HTML,Playwright

border-radius を付けた要素に corner-shape: bevel を足すと、丸い角が斜めにまっすぐ切った角に変わります。scoop なら角が丸くへこみ、notch なら四角くへこみます。clip-path で切り抜く方法と違い、枠線や影も切った形に沿って描かれます。

補足

検証環境は Ubuntu 24.04、Node.js 22.23.4、Playwright 1.63.0、Chromium 153 です。HTML と CSS だけのページを Playwright で開き、スクリーンショットの画素の色と getComputedStyle() の値で形を確かめました。Firefox と Safari、スマートフォンの実機での表示は試していません。各ブラウザーの対応バージョンは、互換性データ(@mdn/browser-compat-data 8.1.8)の値です。

角を斜めに切る・へこませる書き方

corner-shape は、border-radius で丸めた角の範囲を、どんな形にするかを指定するプロパティです。角を斜めに切るなら bevel、へこませるなら scoop か notch を指定します。

css
.cut {
  border-radius: 40px;
  corner-shape: bevel; /* 斜めに切る */
}

.scoop {
  border-radius: 40px;
  corner-shape: scoop; /* 丸くへこませる */
}

.notch {
  border-radius: 40px;
  corner-shape: notch; /* 四角くへこませる */
}
2列3行に並べた6つの水色の長方形。round は普通の角丸、squircle は角丸より四角に近い丸み、bevel は4つの角を斜めに切った八角形、scoop は4つの角が内側に丸くへこんだ形、notch は4つの角が四角く欠けた十字のような形、superellipse(0.5) は角丸と斜めの切り口の中間のふくらみ
border-radius: 40px の要素に、corner-shape の値をそれぞれ指定して Chromium で撮ったもの(下の文字は画像用に足したもの)

指定できるキーワードは6つです。何も指定しないときは round で、これまでの border-radius の角丸と同じ形になります。

値 角の形
round 普通の角丸(初期値)
squircle round より四角に近い丸み
square 角丸なしの直角
bevel 斜めにまっすぐ切る
scoop 内側に丸くへこませる
notch 内側に四角くへこませる

検証環境で、200×120px の要素に border-radius: 40px を付け、左上の角の近くの点が塗られているかを調べました。以下、要素の左上の角から右へ 15px、下へ 15px の点を (15,15) のように書きます。(15,15) の点は、round では塗られ、bevel では空白になりました。(25,25) は scoop では空白、(35,35) は notch だけが空白です。切り落とす範囲は bevel、scoop、notch の順に広くなります。square では、border-radius を付けていても角の点まで塗られ、直角の角になりました。

切る大きさは border-radius で決まる

corner-shape は、角の形を変えるだけです。どこまで切るかは border-radius の大きさで決まります。

border-radius を付けずに corner-shape: bevel だけを書くと、何も変わりませんでした。角から (5,5) の点まで塗られた、ただの長方形のままです。MDN にも、border-radius がないときや 0 のときは効果がないと書かれています。

border-radius: 40px の bevel では、上の辺も左の辺も角から約 40px のところから切り口が始まり、その2点をまっすぐ結ぶ線になりました。縦と横で違う半径を書くと、角度が変わります。

css
.cut-wide {
  border-radius: 60px / 30px; /* 横 60px、縦 30px */
  corner-shape: bevel;
}

この指定では、上の辺は約 60px、左の辺は約 30px のところから切り口が始まりました。border-radius: 20% のように割合で書くと、横は幅の 20%、縦は高さの 20% になります。200×120px の要素では、上の辺は約 40px、左の辺は約 24px のところから始まりました。

角ごとに形を変える

corner-shape には、border-radius と同じく1〜4個の値を書けます。4個のときは左上、右上、右下、左下の順です。

css
.card {
  border-radius: 24px;
  corner-shape: bevel square square scoop;
  /* 左上は斜め、右上と右下は直角、左下は丸くへこむ */
}

検証環境で、各角から内側へ 6px ずつ入った点の色を調べると、左上と左下だけが空白になりました。2個の値を書いた corner-shape: square bevel では、左上と右下が直角、右上と左下が斜めです。この並びも border-radius と同じです。

1つの角だけを変えたいときは、corner-top-right-shape のような角ごとのプロパティを使います。このとき、border-radius もその角だけに付けると、ほかの角は直角のままになります。

css
.notice {
  border-top-right-radius: 28px;
  corner-top-right-shape: bevel;
}

border-radius と組み合わせると、値札やチケットのような形も作れます。値札の形は、右側の2つの角だけに、横 24px・縦 50% の半径を付けて bevel にしています。上下の切り口が右の辺の真ん中で出会い、矢印の先のようになります。

css
.price-tag {
  border-radius: 0 24px 24px 0 / 0 50% 50% 0;
  corner-shape: bevel;
}

.ticket {
  border-radius: 16px;
  corner-shape: scoop;
}
縦に3つ並べた水色の図形。1つ目は「お知らせ」と書かれた横長の長方形で、右上の角だけが斜めに切れている。2つ目は「¥1,280」と書かれた値札で、右側が矢印のようにとがっている。3つ目は「入場券」と書かれたチケットで、4つの角が内側に丸くへこんでいる
右上だけを切ったカード、値札、チケット。この節の CSS を Chromium で表示したもの

値札の形では、右の辺の真ん中のすぐ内側は塗られ、右上と右下の角は空白になりました。

枠線と影も、切った形に沿う

角を斜めに切るだけなら、clip-path の polygon() でもできます。違いが出るのは、枠線や影を付けたときです。

css
/* clip-path で切る */
.clip {
  border: 5px solid #067a98;
  box-shadow: 0 0 0 8px #d85878;
  clip-path: polygon(40px 0, 100% 0, 100% 100%, 0 100%, 0 40px);
}

/* corner-shape で切る */
.corner {
  border: 5px solid #067a98;
  box-shadow: 0 0 0 8px #d85878;
  border-radius: 40px;
  corner-shape: bevel;
}
上下に並べた2つの長方形。上の clip-path で切ったものは、左上の斜めの辺に枠線がなく、中の水色がそのまま見えている。外側のピンクの影は、どの辺にも出ていない。下の corner-shape で切ったものは、斜めの辺にも濃い水色の枠線があり、外側のピンクの影も斜めの辺に沿って出ている
上は clip-path で左上を切ったもの、下は corner-shape: bevel で4つの角を切ったもの。どちらも枠線と影を付けている

clip-path は、描いたあとの見た目を形の外側で切り落とします。斜めの辺の上には枠線がなく、中の背景がそのまま見えました。要素の外側に出る影も切り落とされ、どの辺にも出ていません。

corner-shape では、斜めの辺の上にも枠線が引かれ、影も斜めの辺に沿って外側に出ました。MDN にも、背景、枠線、outline、box-shadow、overflow、backdrop-filter が角の形に従うと書かれています。

overflow: hidden を付けると、子要素も切った形で切り抜かれました。全面をピンクにした子要素を入れても、切り落とした角の部分は空白のままで、子要素は角からはみ出しませんでした。

クリックできる範囲も、切った形どおりになりました。切り落とした角の部分を document.elementFromPoint() で調べると、カードではなく、その下に重ねた要素が返りました。

丸みの度合いを superellipse() で細かく決める

キーワードのあいだの形は、superellipse() 関数で数値を指定して作れます。キーワードはそれぞれ、次の数値と同じ形です。検証環境で getComputedStyle() を読むと、キーワードを指定しても、この数値の形で返りました。

キーワード 計算値
square superellipse(infinity)
squircle superellipse(2)
round superellipse(1)
bevel superellipse(0)
scoop superellipse(-1)
notch superellipse(-infinity)

数値が大きいほど四角に近くふくらみ、0 で斜めの直線、マイナスになると内側にへこみます。最初の画像の superellipse(0.5) は、round と bevel のあいだの形です。

MDN にあるとおり、corner-shape は値と値のあいだを滑らかにアニメーションできます。round から bevel へ1秒の linear の transition を付けると、500ms の時点の計算値は superellipse(0.457105) でした。数値の真ん中の 0.5 ではありません。仕様では、数値をそのまま直線的に変えると、bevel から square への変化が、はじめは速く終わりは遅く見えるとしています。そのため、数値をいったん 0〜1 の値に変換してから途中の値を計算すると定めています。仕様の式で変換すると、round は 0.7071、bevel は 0.5 です。その真ん中を数値に戻すと 0.457105 になり、検証環境の値と一致しました。

transition: corner-shape 1s と一括指定の名前で書くと、4つの角のプロパティ(corner-top-left-shape など)がそれぞれ別に変化しました。

対応しているブラウザー

互換性データでは、corner-shape は実験的な機能とされています。

ブラウザー 対応
Chrome・Edge 139 から
Chrome(Android) 139 から
Firefox 対応なし(開発中の版のみ)
Safari 対応なし(Technology Preview のみ)
Safari(iOS) 対応なし

対応していないブラウザー向けに別の書き方を用意したいときは、@supports で分けます。

css
@supports not (corner-shape: bevel) {
  .cut {
    /* corner-shape が使えないときの指定 */
  }
}

検証環境の Chromium 153 では、CSS.supports('corner-shape', 'bevel') は true を返し、@supports not (corner-shape: bevel) の中の指定は使われませんでした。

​Posted by 86