CSS シェイプ スタートガイド

カスタムパスでコンテンツをラップする

長い間、ウェブ デザイナーは長方形の制約内で作成を余儀なくされてきました。ウェブ上にあるほとんどのコンテンツは、いまだに単純な枠にとらわれています。長方形以外のレイアウトを使用したクリエイティブな制作は、結果的に不満が募るからです。これは、Chrome 37 以降で利用できる CSS シェイプの導入によって変わりつつあります。 ウェブ デザイナーは、CSS シェイプを使用して、円、楕円、多角形などのカスタムパスの周りにコンテンツを囲むことができます。これにより、長方形の制約から解放されます。

シェイプは手動で定義することも、画像から推定することもできます。

非常にシンプルな例を見てみましょう。

私と同じくらい素敵だったかもしれません。まず、透明な部分で画像をフローティングしたときは、コンテンツがラップして隙間を埋めることを想定していましたが、要素の周囲に長方形のラップ形状が残っていることにがっかりしました。この問題を解決するために、CSS シェイプを使用できます。

画像からのシェイプの抽出
<img class="element" src="image.png" />
<p>Lorem ipsum…</p>

<style>
.element{
  shape-outside: url(image.png);
  shape-image-threshold: 0.5;
  float: left;
}
</style>

CSS の shape-outside: url(image.png) 宣言により、ブラウザに対して画像からシェイプを抽出するよう指示します。

shape-image-threshold プロパティでは、シェイプの作成に使用するピクセルの最小不透明度レベルを定義します。値は 0.0(完全に透明)~1.0(完全に不透明)の範囲内にする必要があります。つまり、shape-image-threshold: 0.5 は不透明度 50% 以上のピクセルのみがシェイプの作成に使用されることを意味します。

ここで重要なのは、float プロパティです。shape-outside プロパティはコンテンツをラップする領域のシェイプを定義しますが、浮動小数点数なしでは、シェイプの効果は表示されません。

要素の float 値の反対側に浮動小数点領域があります。たとえば、コーヒーカップの画像を含む要素が左にフロートされている場合、フローティング領域はカップの右側に作成されます。両側に隙間がある画像でも、コンテンツは float プロパティで指定された反対側(left または right)のシェイプの周りにラップされるだけで、両方をラップすることはできません。

将来的には、導入時の CSS 除外でフロートされていない要素で shape-outside を使用できるようになる予定です。

シェイプを手動で作成する

画像から図形を抽出するだけでなく、手動でコーディングすることもできます。シェイプの作成には、circle()ellipse()inset()polygon() の関数値を選択できます。各シェイプ関数は座標のセットを受け取り、座標系を設定する参照ボックスとペアになります。参照ボックスの詳細については、この後すぐに説明します。

Circle() 関数

「Circle()」というシェイプの値のイラスト

円の形状の値の完全な表記は circle(r at cx cy) です。ここで、r は円の半径、cxcy は円の中心の X 軸と Y 軸上の座標です。円の中心の座標は省略可能です。省略すると、要素の中心(対角線の交差)がデフォルトで使用されます。

.element{
  shape-outside: circle(50%);
  width: 300px;
  height: 300px;
  float: left;
}

上記の例では、コンテンツは円形パスの外側を囲んでいます。単一の引数 50% で、円の半径を指定します。この特定のケースでは、要素の幅と高さの半分になります。要素の寸法を変更すると、円シェイプの半径が変わります。これは、CSS シェイプがどのようにレスポンシブになるかを示す基本的な例です。

先に進む前に、CSS のシェイプは要素の周囲のフロート領域のシェイプにのみ影響することを覚えておいてください。要素に背景がある場合は、シェイプによってクリップされません。この効果を実現するには、CSS マスキングのプロパティ(clip-path または mask-image)を使用する必要があります。clip-path プロパティは CSS シェイプと同じ表記法に従っているため、値を再利用できるため、非常に便利です。

「circle()」シェイプとクリップパスのイラスト

このドキュメント全体を通して、イラストではクリップを使用して図形をハイライトし、効果を把握できるようにしています。

円の図形に戻ります。

円の半径にパーセンテージを使用する場合、値はやや複雑な数式(sqrt(width^2 + height^2) / sqrt(2))で計算されます。これを理解すると、要素の寸法が等しくない場合に生成される円の形状を推測するのに役立ちます。

CSS のすべての単位タイプは、px、em、rem、vw、vh などの形状関数の座標で使用できます。ニーズに応じて、十分な柔軟性または柔軟性を備えたタイプを選択できます。

円の位置を調整するには、円の中心の座標に明示的な値を設定します。

.element{
  shape-outside: circle(50% at 0 0);
}

これにより、円の中心が座標系の原点に配置されます。座標系とは何ですか。そこで登場するのが参照ボックスです。

CSS シェイプのリファレンス ボックス

参照ボックスは要素を囲む仮想的なボックスで、シェイプの描画と配置に使用する座標系を確立します。座標系の原点は左上隅にあり、X 軸は右側、Y 軸は下を指しています。

CSS シェイプの座標系

shape-outside は、コンテンツをラップするフローティング領域の形状を変更することに注意してください。浮動小数点領域は、margin プロパティで定義されたボックスの外端まで拡張されます。これは margin-box と呼ばれ、特に明記されていない場合に、シェイプのデフォルトの参照ボックスになります。

次の 2 つの CSS 宣言の結果は同じです。

.element{
  shape-outside: circle(50% at 0 0);
  /* identical to: */
  shape-outside: circle(50% at 0 0) margin-box;
}

この要素には、まだマージンを設定していません。この時点では、座標系の原点と円の中心は要素のコンテンツ領域の左上隅にあると仮定しても安全です。マージンを設定すると、このように変わります。

.element{
  shape-outside: circle(50% at 0 0) margin-box;
  margin: 100px;
}

これで、座標系の原点が、要素のコンテンツ領域の外側(上 100 ピクセル、左 100 ピクセル)にあるようになりました。円の中心も同様です。また、円の半径の計算値も、margin-box 参照ボックスによって確立される座標系の面積の増大に伴い、大きくなります。

マージン ボックス座標系(マージン有 / マージンなし)
参照ボックスには、「margin-box」、「border-box」、「padding-box」、「content-box」など、複数のオプションから選択できます。これらのオプションには、境界を暗示する名前が付けられています。「margin-box」についてはすでに説明しました。「border-box」は要素の境界の外縁によって制約され、「padding-box」は要素のパディングによって制約されます。「content-box」は、要素内のコンテンツによって使用される実際のサーフェス領域と同じです。
すべての参照ボックスのイラスト

shape-outside 宣言で一度に使用できる参照ボックスは 1 つのみです。それぞれの基準ボックスは、異なる形で、場合によっては微妙な形でシェイプに影響します。CSS シェイプのリファレンス ボックスについてより深く掘り下げた記事があります。

ellipse() 関数

ellipse() のシェイプの値のイラスト

楕円はつまみがついた円のように表示されます。ellipse(rx ry at cx cy) として定義されます。rxry は X 軸と Y 軸上の楕円の半径、cxcy は楕円の中心の座標です。

.element{
  shape-outside: ellipse(150px 300px at 50% 50%);
  width: 300px;
  height: 600px;
}

割合の値は、座標系のディメンションから計算されます。面白い計算は必要ありません。楕円の中心の座標を省略すると、座標系の中心から座標が推定されます。

X 軸と Y 軸の半径はキーワードで定義することもできます。farthest-side は楕円の中心とそれから最も遠い参照ボックスの辺までの距離と等しい半径になります。closest-side はその逆で、中心と辺の間の最短距離を使用します。

.element{
  shape-outside: ellipse(closest-side farthest-side at 50% 50%);
  /* identical to: */
  shape-outside: ellipse(150px 300px at 50% 50%);
  width: 300px;
  height: 600px;
}

これは、要素の寸法(または参照ボックス)が予測できない方法で変更される可能性があるものの、楕円の形状を適応させたい場合に便利です。

同じ farthest-side キーワードと closest-side キーワードを circle() シェイプ関数で半径に指定することもできます。

Polygon() 関数

drawable() シェイプの値のイラスト

円や楕円では制限が厳しすぎる場合は、ポリゴン シェイプ関数を使用して選択肢が広がります。形式は polygon(x1 y1, x2 y2, ...) で、ポリゴンの各頂点(点)に x y 座標のペアを指定します。ポリゴンを指定するペアの最小数は 3(三角形)です。

.element{
  shape-outside: polygon(0 0, 0 300px, 300px 600px);
  width: 300px;
  height: 600px;
}

頂点は座標系に配置されます。レスポンシブ ポリゴンでは、一部またはすべての座標にパーセンテージ値を使用できます。

.element{
  /* polygon responsive to font-size*/
  shape-outside: polygon(0 0, 0 100%, 100% 100%);
  width: 20em;
  height: 40em;
}

SVG からインポートされる fill-rule パラメータがオプションでもあります。このパラメータは、パスが自己交差する、または閉じられたシェイプがある場合に、ポリゴンの「内側」を考慮する方法をブラウザに指示します。Joni Trythall 氏は、SVG での fill-rule プロパティの仕組みについて詳しく説明しています。定義されていない場合、fill-rule はデフォルトで nonzero になります。

.element{
  shape-outside: polygon(0 0, 0 100%, 100% 100%);
  /* identical to: */
  shape-outside: polygon(nonzero, 0 0, 0 100%, 100% 100%);
}

inset() 関数

inset() シェイプ関数を使用すると、コンテンツを囲む長方形を作成できます。CSS シェイプによってウェブ コンテンツがシンプルなボックスから解放されるという最初の前提を考えると、直感に反しているように聞こえるかもしれません。そうかもしれませんね。浮動小数点数とマージン、または polygon() ではまだ実現できない inset() のユースケースはまだありません。ただし、inset() の方が長方形の場合は、polygon() よりも式の方が読みやすいです。

インセットのシェイプ関数の完全な表記は inset(top right bottom left border-radius) です。最初の 4 つの位置引数は、要素の端から内側へのオフセットです。最後の引数は、長方形の枠線の半径です。これはオプションなので省略できます。これは、CSS ですでに使用されている border-radius 省略表記に従います。

.element{
  shape-outside: inset(100px 100px 100px 100px);
  /* yields a rectangular shape which is 100px inset on all sides */
  float: left;
}

参照ボックスからのシェイプの作成

shape-outside プロパティにシェイプ関数を指定しない場合、ブラウザで要素の参照ボックスからシェイプを導出できます。デフォルトの参照ボックスは margin-box です。今のところ特に珍しいものはなく、すでにフロートが機能しています。しかし、この方法を適用すると、要素のジオメトリを再利用できます。border-radius プロパティを見てみましょう。

これを使用してフローティング要素の角を丸くすると、クリップ効果が得られますが、フローティング領域は長方形のままになります。shape-outside: border-box を追加して、border-radius によって作成された輪郭をラップします。

ボーダー ボックス参照ボックスを使用して要素の境界半径からシェイプを抽出する
.element{
  border-radius: 50%;
  shape-outside: border-box;
  float: left;
}

もちろん、すべての参照ボックスをこの方法で使用できます。派生シェイプの別の用途として、オフセット プル クォートがあります。

コンテンツ ボックスの参照ボックスを使用してオフセット引用の引用を作成する

float 型プロパティと margin プロパティのみを使用すると、オフセット プル クォート効果を実現できます。ただし、そのためには、HTML ツリー内のレンダリングする位置に引用符要素を配置する必要があります。

同じオフセットの引用効果に柔軟性を持たせる方法は次のとおりです。

.pull-quote{
  shape-outside: content-box;
  margin-top: 200px;
  float: left;
}

ここでは、シェイプの座標系の content-box 参照ボックスを明示的に設定しています。この場合、プル引用のコンテンツの量によって、外側のコンテンツを囲む形状が定義されます。margin-top プロパティは、HTML ツリー内での位置に関係なく、プルクォートを配置(オフセット)するために使用されます。

図形の余白

コンテンツを 1 つのシェイプでラップすると、要素に接近しすぎることがあることがわかります。shape-margin プロパティを使用すると、シェイプの周囲にスペースを追加できます。

.element{
  shape-outside: circle(40%);
  shape-margin: 1em;
  float: left;
}

効果は通常の margin プロパティを使用した場合と似ていますが、shape-marginshape-outside 値の周囲のスペースにのみ影響します。座標系にスペースがある場合にのみ、シェイプの周囲にスペースが追加されます。そのため、上記の例では、円の半径が 50% ではなく 40% に設定されています。半径を 50% に設定すると、円が座標系のすべてのスペースを占有することになり、shape-margin を適用する余地がなくなります。シェイプは最終的に、要素の margin-box(要素とその周囲の margin)に制約されることに注意してください。シェイプがより大きく、オーバーフローしている場合は margin-box にクリップされ、長方形になります。

shape-margin が受け取る正の値は 1 つのみであることを理解することが重要です。長い表記はありません。円のシェイプ マージン トップとは何ですか?

図形をアニメーション化する

CSS シェイプは、遷移やアニメーションなど、他の多くの CSS 機能と併用できます。ただし、読書中にテキストのレイアウトが変わると、ユーザーはとても不快に感じられることを強調しておく必要があります。形状をアニメーション化する場合は、エクスペリエンスに十分注意してください。

ブラウザで補間可能な値で定義されている限り、circle()ellipse() のシェイプの半径と中心をアニメーション化できます。circle(30%)からcircle(50%)へのルートは可能です。ただし、circle(closest-side) から circle(farthest-side) の間でアニメーション化すると、ブラウザがクラッシュします。

.element{
  shape-outside: circle(30%);
  transition: shape-outside 1s;
  float: left;
}

.element:hover{
  shape-outside: circle(50%);
}
アニメーション化された円の GIF

polygon() シェイプをアニメーション化すると、さらに興味深い効果が得られます。ただし、この 2 つのアニメーション状態の間でポリゴンの頂点の数が同じでなければならないという点が重要です。頂点を追加または削除すると、ブラウザによる補間ができなくなります。

1 つのコツは、必要な最大数の頂点を追加して、シェイプの知覚エッジが少なくなるようにアニメーション状態に配置することです。

.element{
  /* four vertices (looks like rectangle) */
  shape-outside: polygon(0 0, 100% 0, 100% 100%, 0 100%);
  transition: shape-outside 1s;
}

.element:hover{
  /* four vertices, but second and third overlap (looks like triangle) */
  shape-outside: polygon(0 0, 100% 50%, 100% 50%, 0 100%);
}
アニメーション化された三角形の GIF

シェイプ内でコンテンツを折り返す

CSS シェイプを使用してコンテンツをラップする Alice in Wonderland デモのスクリーンショット

CSS Shapes 仕様の最初のドラフトには、シェイプ内にコンテンツをラップできる shape-inside プロパティが含まれていました。しばらくの間、Chrome や Webkit にも実装がありました。しかし、任意に配置されたコンテンツをカスタムパスでラップするには、考えられるすべてのシナリオをカバーしてバグを回避するために、より多くの労力と調査が必要になります。そのため、shape-inside プロパティは CSS Shapes Level 2 まで延期され、その実装は取り消されています。

ただし、多少の労力と少しの妥協点があれば、コンテンツをカスタム シェイプでラップする効果が得られます。このコツは、shape-outside で 2 つのフローティング要素を使用し、コンテナの両側に配置することです。デメリットは、意味を持たない空の要素を 1 つまたは 2 つ使用する必要があるものの、内部に形状を錯覚させるために支柱として機能することです。

<div>
  <div class='left-shape'></div>
  <div class='right-shape'></div>

  Lorem ipsum...
</div>

.left-shape.right-shape の strut 要素はコンテナの上部で位置が重要です。これらの要素は、コンテンツの両側に左右にフローティングされるからです。

.left-shape{
  shape-outside: polygon(0 0, ...);
  float: left;
  width: 50%;
  height: 100%;
}

.right-shape{
  shape-outside: polygon(50% 0, ...);
  float: right;
  width: 50%;
  height: 100%;
}
Alice のデモにおけるシェイプインサイドの回避策のイラスト

このスタイル設定では、2 つのフローティング ストラットが要素内のすべてのスペースを占有しますが、shape-outside プロパティは残りのコンテンツ用のスペースを切り分けます。

CSS シェイプがブラウザでサポートされていない場合、すべてのコンテンツが押し下げられて、見苦しい効果が生じます。そのため、この機能を段階的に拡張して使用することが重要です。

これまでのシェイプ アニメーションの例では、テキストのシフトが気になる場合があることがわかります。すべてのユースケースでシェイプのアニメーション化が保証されるわけではありません。ただし、CSS シェイプと連携する他のプロパティをアニメーション化することで、必要に応じて効果を追加できます。

CSS シェイプの不思議の国のアリスのデモでは、スクロール位置を使用してコンテンツの上余白を変更しています。テキストは 2 つのフローティング要素の間に挟まれます。下に移動する場合は、2 つのフローティング要素の shape-outside に従って再レイアウトする必要があります。これにより、テキストがラビットホールに入ったかのような印象を与え、ストーリーテリングのエクスペリエンスを高めます。ボーダーラインは不当ですか?可能であるとは言いきれません。見た目もかっこいい。

テキスト レイアウトはブラウザでネイティブに行われるため、JavaScript ソリューションを使用するよりもパフォーマンスが高くなります。ただし、スクロールでマージン上部のマージンを変更すると、再レイアウト イベントとペイント イベントが多数発生し、パフォーマンスが著しく低下する可能性があります。使用する際はご注意ください。ただし、CSS シェイプをアニメーション化せずに使用すると、目に見えるパフォーマンス上の影響は生じません。

プログレッシブ エンハンスメント

最初はブラウザが CSS シェイプをサポートしていないと仮定し、機能を検出したときにそれを基に構築します。Modernizr が特徴検出に適したソリューションであり、「コア以外の検出」セクションに CSS シェイプのテストがあります。

一部のブラウザでは、外部ライブラリを必要とせずに、@supports ルールによって CSS の機能検出を行うことができます。Google Chrome は CSS シェイプもサポートしており、@supports ルールをサポートしています。これを使用して、以下を段階的に強化していきます。

.element{
  /* styles for all browsers */
}

@supports (shape-outside: circle(50%)){
  /* styles only for browsers which support CSS Shapes */
  .element{
    shape-outside: circle(50%);
  }
}

CSS の @supports ルールの使用方法について詳しくは、Lea Verou をご覧ください。

CSS の除外との曖昧さ回避

現在 CSS Shape として知られていることは、仕様が策定された当初は CSS Exclusions と CSS Shapes と呼ばれていました。名前の変更は微妙な違いに思えるかもしれませんが、実際には非常に重要です。別の仕様になった CSS 除外を使用すると、浮動小数点数のプロパティを必要とせずに、任意の位置に配置された要素の周囲にコンテンツをラップできます。絶対的な位置に配置された要素の周囲にコンテンツを囲むことを想像してみてください。これが CSS の除外の使用例です。CSS シェイプは、コンテンツをラップするパスを定義するだけです。

つまり、シェイプと除外設定は同じものではありませんが、相互に補完し合います。CSS シェイプは現時点でブラウザで利用できますが、CSS の除外はシェイプの操作ではまだ実装されていません。

CSS シェイプを扱うツール

従来の画像作成ツールでパスを作成できますが、このドキュメントの執筆時点では、CSS シェイプ値に必要な構文をエクスポートすることはできません。仮にそうだとしても、そのように働くことは現実的とは言えません。

CSS シェイプは、ページ上の他の要素に反応するブラウザで使用することを目的としています。シェイプを編集すると、そのシェイプを囲むコンテンツに対する影響を可視化すると非常に便利です。このワークフローに役立つツールがいくつかあります。

角かっこ: Brackets 用の CSS Shapes Editor 拡張機能は、コードエディタのライブ プレビュー モードを使用して、シェイプの値を編集するためのインタラクティブなエディタをオーバーレイします。

Google Chrome: Google Chrome の CSS シェイプ エディタ拡張機能を使用すると、ブラウザのデベロッパー ツールにシェイプの作成や編集のためのコントロールが追加されます。選択した要素の上にインタラクティブなエディタを配置します。

Google Chrome のインスペクタには、図形のハイライト表示のサポートが組み込まれています。shape-outside プロパティを含む要素にカーソルを合わせると、ライトが点灯してシェイプを示します。

画像からのシェイプ: 画像を生成する際にブラウザでシェイプを抽出したい場合、Rebecca Hauck 氏は Photoshop のチュートリアルを適切に作成しています。

Polyfill: Google Chrome は CSS Shapes を導入した最初の主要ブラウザです。この機能は、Apple の iOS 8 と Safari 8 でもサポートされる予定です。他のブラウザ ベンダーでも今後検討される可能性があります。それまでは、基本的なサポートを提供するための CSS シェイプ ポリフィルが提供されています。

おわりに

コンテンツがほとんどが単純な箱に閉じ込められているウェブでは、CSS シェイプを使用して表現力豊かなレイアウトを作成し、ウェブ デザインと印刷デザインの間のフィデリティ ギャップを埋めることができます。もちろん、図形は悪用されて注意が散漫になることもあります。しかし、好みや適切な判断を取り入れて形にすることで、コンテンツの見栄えが良くなり、ユーザーの注意を 1 人ひとりに合った方法で集中させることができます。

他の人による作品集もあわせてご覧ください。ほとんどが印刷物です。長方形でないレイアウトの興味深い使い方を実演しています。この情報が、CSS シェイプを試し、新しいデザインのアイデアを試すきっかけになれば幸いです。

この記事のレビューと貴重な知見の提供に協力してくれた Pearl Chen、Alan Stearns、Zoltan Horvath に感謝します。