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 キーワードを使用できます。

polygon() 関数

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 プロパティについて見てみましょう。

これをフロート要素の角に適用すると、切り抜き効果は得られますが、フロート領域は長方形のままになります。border-radius によって作成された輪郭をラップするように shape-outside: border-box を追加します。

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

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

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

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

同じオフセット プルクォート効果をより柔軟に実現する方法は次のとおりです。

.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 除外は、個別の仕様になりました。これにより、float プロパティを使用せずに、任意に配置された要素の周囲にコンテンツをラップできるようになりました。絶対配置された要素の周囲にコンテンツをラップするとします。これは 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 の皆様に感謝いたします。