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

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

長い間、ウェブ デザイナーは長方形の制限内で作成することを余儀なくされてきました。ウェブ上のコンテンツのほとんどは、長方形以外のレイアウトに挑戦してもうまくいかないため、シンプルなボックスに収まっています。しかし、CSS シェイプの導入により、この状況は変わります。CSS シェイプは Chrome 37 以降で利用できます。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>

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

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

ここで重要なのは float プロパティです。shape-outside プロパティは、コンテンツが折り返される領域の形状を定義しますが、float がないと、その形状の効果は表示されません。

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

今後、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() シェイプと clip-path のイラスト

このドキュメントのイラストでは、クリッピングを使用して形状をハイライトし、効果を理解できるようにしています。

円形に戻します。

円の半径にパーセンテージを使用する場合、値は実際には、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 の 4 つのオプションがあります。名前が境界を示しています。前回説明した「margin-box」は、要素の境界の外側のエッジによって制限されます。「border-box」は要素の境界の外側のエッジによって制限されます。「padding-box」は要素の padding によって制限されます。「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;
}

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

circle() シェイプ関数の半径にも、同じ farthest-side キーワードと closest-side キーワードを使用できます。

floor() 関数

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

円や楕円では制限が多い場合は、ポリゴン形状関数を使用するとさまざまなオプションが利用できます。形式は 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 によって作成された等高線を囲みます。

border-box リファレンス ボックスを使用して要素の border-radius からシェイプを抽出する
.element{
  border-radius: 50%;
  shape-outside: border-box;
  float: left;
}

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

content-box リファレンス ボックスを使用してオフセット プルクォートを作成する

オフセット プルクォートの効果は、float プロパティと margin プロパティのみを使用して実現できます。ただし、その場合には、HTML ツリー内の表示したい位置に quote 要素を配置する必要があります。

柔軟性をさらに高めながら、同じオフセット プルクォート効果を実現する方法は以下のとおりです。

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

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

図形の余白

コンテンツをシェイプにラップすると、要素に密着しすぎてしまうことがあります。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 つだけ受け入れることを理解することが重要です。長い記号はありません。円の shape-margin-top とは何ですか?

図形のアニメーション化

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 シェイプを使用してコンテンツを折り返す『不思議の国のアリス』デモのスクリーンショット

CSS シェイプ仕様の最初のドラフトには、シェイプ内にコンテンツを折り返すことができる shape-inside プロパティが含まれていました。一時期は Chrome と WebKit にも実装されていました。ただし、任意の位置に配置されたコンテンツをカスタムパス内にラップするには、考えられるすべてのシナリオを網羅し、バグを回避するために、はるかに多くの労力と調査が必要になります。そのため、shape-inside プロパティは CSS シェイプ レベル 2 に延期され、その実装は取り下げられました。

ただし、多少の工夫と妥協をすれば、カスタム シェイプ内にコンテンツをラップする効果を実現できます。ハックは、shape-outside を使用して 2 つのフローティング要素を使用し、コンテナの反対側に配置することです。ただし、セマンティックな意味を持たない空の要素を 1~2 つ使用する必要があります。これらの要素は、内部に形状があるように見せるための支柱として機能します。

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

  Lorem ipsum...
</div>

ストラット要素 .left-shape.right-shape をコンテナの上部に配置することは重要です。これらのストラット要素は、コンテンツを囲むために左右にフローティングされるためです。

.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 の shape-inside の回避策のデモのイラスト

このスタイル設定では、2 つのフローティング ストラットが要素内のすべてのスペースを占有しますが、shape-outside プロパティによって残りのコンテンツのためのスペースが確保されます。

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

前述の形状アニメーションの例では、テキストが移動するのが煩わしい場合があります。すべてのユースケースで、アニメーション化されたシェイプが必要なわけではありません。ただし、CSS シェイプとやり取りする他のプロパティをアニメーション化して、必要に応じて効果を追加できます。

CSS シェイプを使った不思議の国のアリスのデモでは、スクロール位置を使用してコンテンツの上余白を変更しています。テキストは 2 つのフロート要素間でスクイーズされます。下に移動すると、2 つのフローティング要素の shape-outside に応じて再レイアウトする必要があります。これにより、テキストが「うさぎの穴に落ちていく」ような印象を与え、ストーリーテリングのエクスペリエンスが向上します。ボーダーラインの不必要性必要な場合もある。でも、かっこいいですね。

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

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

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

一部のブラウザでは、外部ライブラリを必要とせずに、@supports ルールを介して CSS で機能検出を行うことができます。CSS シェイプもサポートしている Google Chrome は、@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 シェイプと呼ばれているものは、仕様の初期段階では CSS 除外とシェイプと呼ばれていました。名前の変更は些細なことのように思えますが、実際には非常に重要です。独立した仕様となった CSS の除外を使用すると、浮動小数点プロパティがなくても、任意に配置された要素の周囲にコンテンツをラップできます。絶対配置された要素の周囲にコンテンツをラップするとします。これは CSS 除外のユースケースです。CSS シェイプは、コンテンツが折り返されるパスを定義するだけです。

したがって、形状と除外は同じではありませんが、互いに補完し合うことができます。CSS シェイプは現在ブラウザで使用できますが、CSS 除外はシェイプの操作ではまだ実装されていません。

CSS シェイプを使用するためのツール

従来の画像作成ツールでパスを作成できますが、現時点ではどのツールも CSS シェイプ値に必要な構文をエクスポートしません。仮に可能だったとしても、そのような働き方は現実的ではありません。

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

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

Google Chrome: Google Chrome の CSS シェイプ エディタ拡張機能は、ブラウザのデベロッパー ツールを拡張し、シェイプを作成、編集するためのコントロールを提供します。選択した要素の上にインタラクティブ エディタが表示されます。

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

画像から図形を生成: 画像を生成してブラウザで図形を抽出する場合は、Rebecca Hauck によるPhotoshop のチュートリアルをご覧ください。

ポリフィル: Google Chrome は、CSS シェイプを搭載した最初のメジャー ブラウザです。この機能は、Apple の iOS 8 と Safari 8 で近日中にサポートされる予定です。他のブラウザ ベンダーは、今後この機能を検討する可能性があります。それまでは、基本的なサポートを提供する CSS シェイプ ポリフィルがあります。

まとめ

コンテンツのほとんどがシンプルなボックスに収められているウェブにおいて、CSS シェイプは表現力豊かなレイアウトを作成するための方法を提供し、ウェブと印刷デザインの忠実度ギャップを埋めます。当然ながら、図形は悪用されて気を散らす原因になる可能性があります。ただし、適度に、そして慎重に使用すれば、コンテンツの表現を強化し、ユーザーの注意を独自の方法で引き付けることができます。

最後に、他のクリエイターによる作品集をご紹介します。ほとんどが印刷物ですが、長方形以外のレイアウトの興味深い使い方をご覧いただけます。CSS シェイプを試して、新しいデザインのアイデアを試すきっかけになれば幸いです。

この記事をレビューして貴重な分析情報を提供してくださった Pearl Chen、Alan Stearns、Zoltan Horvath の皆様に感謝いたします。