Blink で CSS の角の形状を実装する際の注意点

公開日: 2026 年 2 月 19 日

Chrome が 2025 年にリリースした CSS 機能の 1 つが corner-shape です。これにより、bevelscoop などのキーワードを使用して、border-radius を持つ角の形状を定義できます。-InfinityInfinity の値を受け取る superellipse 関数を使用することもできます。

この機能の概要とその仕組みについては、Amit Sheen 氏による Frontend Masters の詳細な記事をご覧ください。

2025 年初頭にこの機能を実装する際、さまざまな複雑さを持つ興味深い課題にいくつか遭遇しました。超楕円、Blink の境界線の描画、2D グラフィックでのベクトル数学の使用について多くのことを学びました。

このドキュメントでは、私が学んだことの一部を紹介します。他の人にとっても興味深い内容かもしれません。

凸型と凹型の形状の対称性

通常、superellipsek)の値は 0 から Infinity の範囲で、0 から 1 の値は凹面、残りは凸面(1 は bevel)ですが、CSS 仕様の superellipse の値は -Infinity から Infinity の範囲で、2k を表します。これにより、正の値は負の値の鏡像のように見えるため、対称性が生まれます。

ただし、デフォルトでは superellipse 数式はこのような動作をしません。

superellipse の式は xk + yk = 1 です。逆関数 x1/k + y1/k = 1 では、視覚的に対称な曲線は生成されません。

たとえば、k2 の場合:

スーパー楕円曲線の比較。丸いスーパー楕円(青)、正規の式で表されるスクープ スーパー楕円(赤)、視覚的に対称な曲線(黄)を示しています。
  • 青い曲線は丸い superellipsey=xn)を表します。
  • 赤い曲線は、正規の式(y=x1/n)の scoop superellipse を表しています。
  • 黄色の曲線は、青色の曲線(y=1-(1-x)n)と視覚的に対称な曲線を表します。

グラフに示すように、形状は同じではありません。

数学的な詳細には触れませんが、双対ノルムと曲率の認識に関連しています。

仕様と実装の面では、ここでは視覚的なものを表現しているため、凹型を計算する際には対称的な同等物を使用します。残りの計算は凸形状(k>=1、または正のスーパー楕円値)に対して行われます。

閉形式の数式

次の課題は、superellipse の曲線または境界を、単純な算術演算で構成される式である閉形式で表すことです。これは、パフォーマンスに不可欠です。これにより、システムは superellipse レンダリングをグラフィック エンジンに渡すことができます。

Skia などのグラフィック エンジンはベジエ曲線に精通しているため、superellipse の外周を近似する少数のベジエ曲線で superellipse を表現すると、superellipse 曲線のレンダリングのパフォーマンスが向上します。

幸いなことに、シンボリック回帰を使用すると、凸状の角の半分を単一の 3 次ベジエ曲線として表す数式を見つけることができます。

3 次ベジエ曲線には 4 つのポイントがあります。

  • 最初のポイントは(0, 1)です。
  • 最後のポイントは、実際のスーパー楕円の半分の角 0.51/k,0.51/k です。
  • 最初の制御点は、開始点と同じレベルで内側に伸びています(a, 1)。
  • 2 番目の制御点は、半分の角の対角線です((0.51/k - b,0.51/k + b))。

ここで使用されるハーフコーナー値は、後で他の計算に使用する非常に重要な座標です。

ここで、ab は、シンボリック回帰を使用して k から計算されます。

曲線にマッピングされたコントロール ポイントのイラスト。
デモについては、こちらの Codepen をご覧ください。

これらの 4 つの点を計算し、それらの間に 3 次ベジエ曲線を描画すると、指定された k を持つ閉じた凸半角コーナーが生成されます。次に、結果を回転させて残りの角を埋め、他の角に適用して反転させ、凹面相当をレンダリングします。

数学的な詳細には立ち入りませんが、ab を計算する式は次のとおりです。

p0 = 1.2430920942724248
p1 = 2.010479023614843
p2 = 0.32922901179443753
p3 = 0.2823023142212073
p4 = 1.3473704261055421
p5 = 2.9149468637949814
p6 = 0.9106507102917086

s = log2(k)
slope = p0 + (p6 - p0) * 0.5 * (1 + tanh(p5 * (s - p1)))
base = 1 / (1 + exp(slope * p1))
logistic = 1 / (1 + exp(slope * (p1 - s)))

a = (logistic - base) / (1 - base)
b =  p2 * exp(-p[3] * (s ^ p4))

枠線と影

システムのコーナーの境界線のパスを計算するだけでなく、内側(境界線またはインセット box-shadow)または外側(outline または通常の box-shadow)にオフセットした場合の見た目も計算します。従来のグラフィック ライブラリでは、これはストロークによって行われます。

ただし、CSS の境界線とシャドウには、ストロークとは異なるレンダリング特性があります。

  • 枠線が均一でない。
  • たとえば、上部の境界線を 10 ピクセル、右側の境界線を 5 ピクセルに設定し、角をそれらの間で補間できます。
  • また、両側ではなく内側に移動します。
  • 影とアウトラインはストロークのように正確にレンダリングされません。
  • 代わりに、角がシャープに見えるように調整します。

通常の境界線とシャドウのレンダリング パスは、丸い corner-shape 値やそれよりも凸状の corner-shape 値(squircle など)ではうまく機能し、scoop よりも凹状の形状では 90 度回転できますが、このデフォルトは -1 から 1 の間の corner-shape 値では機能しません。境界線やシャドウをエッジに平行にオフセットすると、幅が不均一に見える角が生成されるためです。

たとえば、bevel の角を取り、境界線を両側に数ピクセルずつオフセットすると、角の中央が両側よりも広く見える「お腹」効果が生まれます。

これを考慮して、ストロークのように機能する効果を作成します。つまり、開始位置の角の曲線の法線を見つけ、border または shadow-spread の幅と同じ長さにします。

幸いなことに、これはサブ楕円(bevel と丸の間)でのみ必要です。squircle などのハイパー楕円は想定どおりに機能します。

サブ楕円曲線法線を求めるには、サブ楕円とそれに対応する二次曲線が互いに近いので、二次曲線法線を求めるだけで十分です。

前に計算した同じハーフコーナーを使用すると、同じ中間点を持つ二次曲線を見つけ、その二次制御点を導き出すことができます。そこから法線を計算するのは簡単です。

通常は border-width または shadow-spread と同じ長さで続き、結果の曲線をエッジ(境界の内側のエッジ、シャドウの外側のエッジ)でクリップして、連続したパスを作成します。

境界線のある角のイラスト。境界線の形状を定義するために法線がどのように拡張されるかを示しています。
CodePen でこの例をご覧ください。

superellipse の接線を計算するより数学的に正確な方法もありますが、この方法は効率的で、境界線やシャドウのレンダリングに十分な結果が得られます。

カラー結合

ブラウザで発生する興味深いペイント処理は、CSS で指定されていません。均一でない色やスタイルで枠線をレンダリングします。たとえば、要素の上部境界線が緑色の実線で、右側の境界線が黄色の点線の場合などです。この場合、マイターは、ボーダーエッジの関連する角とパディングエッジの関連する角の間を通る切開線です。隣接するエッジの間に境界線を作成します。指定されていませんが、ブラウザ間でレンダリングはやや一貫しています。

Blink(および他のブラウザ)での実装方法は次のとおりです。描画されようとしているエッジは、マイターで交差するポリゴンのように粗くクリップされ、関連するエッジは含まれるが、他のエッジは含まれないように計算されます。これにより、ブリーディング(他のエッジの 1 つが誤ったスタイルと色で描画されること)を回避できます。

この多角形は、丸みを帯びた角が重なることがないため、比較的簡単に計算できました。ただし、これはハイポエリプスの場合は異なり、特に凹型スーパーエリプス(superellipse 値が負の場合)では異なります。これらの形状は、単純な交差ポリゴンが重複や「ブリーディング」を起こしやすい非常に興味深い形状を作成できます。

次の CSS を考えてみましょう。

.weird {
  width: 200px;
  height: 200px;
  corner-shape: scoop round;
  border-radius: 80% 20% / 50% 50%;
  border-width: 10px;
  border-color: orange purple black blue;
  border-style: solid dotted;
}
均一でない境界を持つ CSS 要素の例。オレンジ、紫の点線、黒、青の点線のエッジが表示されています。

各エッジ(オレンジ、紫の点線、黒、青の点線)を個別にクリップしてから、パスを描画します。

他の 3 つの角と重ならないようにするには、慎重にクリッピングする必要があります。

たとえば、オレンジ色の(上部の)エッジについて考えてみましょう。

そのエッジ全体を含み、紫、黄、黒のエッジにはみ出さない正確なポリゴンを見つけるのは困難です。他の図形は、より複雑です。

このプロセスには 3 つのクリップが含まれます。

最初のクリップには、角全体(留め継ぎなし)を含むエッジ全体が含まれています。次に例を示します。

2 つの角(1 つはスクープ、1 つは丸)を表す切り取られた角の形状。

これは、2 つの角(1 つは scoop、1 つは丸い角)で構成され、その間に最小限のエッジがあり、端で接続されています。

この形状から開始すると、反対側のエッジとの重複が解消され、2 つのマイターのみが懸念事項となります。

これは、この角から、境界線の端とパディングの端の角の間を通り、端と交差する直前で止まるポリゴンを切り取ることで実現されます。

クリップする領域のデモ。

システムは、境界エッジからパディング エッジまでの線が、関連する開始点からの曲線の接線と交差する点を見つけます(曲線が凹面の場合)。

その点がレンダリング領域内にある場合、プロセスはそこで停止し、その接線に沿って境界ボックスに再び出会うまで続行され、四角形が完成します。

それ以外の場合は、単純な三角形をクリップできます。

概要

ウェブ プラットフォームは、ウェブ デザイナーやウェブ デベロッパーに優れた表現力を提供します。単一の数値を受け取る CSS プロパティは、正確かつ一貫してレンダリングするために、内部で複雑な処理を行っていることがあります。

corner-shape 機能は驚くほど複雑でした。このドキュメントは、Blink、他のブラウザ、仕様でこの機能に取り組む将来のデベロッパーを支援することを目的としています。