カスタムパスに沿ってコンテンツを折り返す
長い間、ウェブデザイナーは長方形の制約の中でデザインすることを強いられてきました。ウェブ上のほとんどのコンテンツは、いまだに単純なボックスに閉じ込められています。これは、長方形以外のレイアウトに挑戦するクリエイティブな試みのほとんどが、不満に終わるためです。Chrome 37 から利用可能になった CSS シェイプの導入により、この状況は変わろうとしています。CSS Shapes を使用すると、ウェブ デザイナーは円、楕円、多角形などのカスタムパスに沿ってコンテンツを折り返すことができるため、長方形の制約から解放されます。
シェイプは手動で定義することも、画像から推測することもできます。
非常に簡単な例を見てみましょう。
透明な部分がある画像を最初にフロート表示したとき、コンテンツが回り込んで隙間を埋めることを期待していたのに、要素の周りに長方形の回り込み形状が残ってがっかりした、という経験はありませんか?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 Exclusions の導入により、フローティングされていない要素で shape-outside を使用できるようになります。
シェイプを手動で作成する
画像から形状を抽出するだけでなく、手動でコーディングすることもできます。circle()、ellipse()、inset()、polygon() のいくつかの関数値から選択して、シェイプを作成できます。各シェイプ関数は一連の座標を受け取り、座標系を確立する参照ボックスとペアになります。参照ボックスについては後ほど詳しく説明します。
circle() 関数
円の形状値の完全な表記は circle(r at cx cy) です。ここで、r は円の半径、cx と cy は X 軸と Y 軸上の円の中心の座標です。円の中心の座標は省略可能です。省略すると、要素の中心(対角線の交点)がデフォルトとして使用されます。
.element{
shape-outside: circle(50%);
width: 300px;
height: 300px;
float: left;
}
上記の例では、コンテンツは円形のパスの外側に回り込みます。単一の引数 50% は円の半径を指定します。この場合、要素の幅または高さの半分になります。要素のサイズを変更すると、円の半径に影響します。これは、CSS シェイプをレスポンシブにする方法の基本的な例です。
先に進む前に、CSS シェイプは要素の周囲のフロート領域の形状にのみ影響することを覚えておくことが重要です。要素に背景がある場合、その背景はシェイプによってクリップされません。この効果を実現するには、CSS マスキングのプロパティ(clip-path または mask-image)を使用する必要があります。clip-path プロパティは、CSS シェイプと同じ表記に従うため、値を再利用できるので非常に便利です。
このドキュメントのイラストでは、クリッピングを使用して形状を強調し、効果を理解しやすくしています。
円の形に戻ります。
円の半径にパーセンテージを使用する場合、値は実際には少し複雑な式(sqrt(width^2 + height^2) / sqrt(2))で計算されます。このことを理解しておくと、要素の寸法が等しくない場合に、結果として得られる円の形状をイメージするのに役立ちます。
シェイプ関数の座標には、px、em、rem、vw、vh など、すべての CSS 単位タイプを使用できます。ニーズに合わせて、柔軟性や剛性が十分なものを選択できます。
円の中心の座標に明示的な値を設定することで、円の位置を調整できます。
.element{
shape-outside: circle(50% at 0 0);
}
これにより、円の中心が座標系の原点に配置されます。座標系とは何ですか?ここで、参照ボックスを導入します。
CSS シェイプの参照ボックス
参照ボックスは、要素の周囲にある仮想ボックスで、シェイプの描画と配置に使用される座標系を確立します。座標系の原点は左上隅にあり、X 軸は右方向、Y 軸は下方向を指しています。
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 参照ボックスによって確立された座標系の表面積の増加を考慮して増加します。
shape-outside 宣言で使用できる参照ボックスは、一度に 1 つのみです。各参照ボックスは、異なる方法で、時には微妙な方法で形状に影響を与えます。CSS シェイプの参照ボックスについて詳しく説明している記事もあります。
ellipse() 関数
楕円は、押しつぶされた円のように見えます。これらは ellipse(rx ry at cx cy) として定義されます。ここで、rx と ry は X 軸と Y 軸の楕円の半径であり、cx と cy は楕円の中心の座標です。
.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() 関数
円や楕円では制限が多すぎる場合は、ポリゴン形状関数を使用すると、さまざまなオプションを利用できます。形式は 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;
}
オプションの fill-rule パラメータ(SVG からインポート)があります。これは、自己交差するパスや囲まれた形状の場合に、ポリゴンの「内側」をどのように考慮するかをブラウザに指示します。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 シェイプはウェブ コンテンツを単純なボックスから解放するという最初の前提を考えると、これは直感に反するように思えるかもしれません。その可能性は十分にあります。inset() のユースケースはまだ見つかっていません。これは、float と margin、または polygon() で実現できないものです。ただし、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 です。ここまでは、float の仕組みと同じです。この手法を適用すると、要素のジオメトリを再利用できます。border-radius プロパティを見てみましょう。
このプロパティを使用して、フロート要素の角を丸くすると、クリッピング効果が得られますが、フロート領域は長方形のままです。border-radius で作成された輪郭を囲むように shape-outside: border-box を追加します。
.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 参照ボックスを明示的に設定します。この場合、抜粋引用のコンテンツの量によって、外部コンテンツが回り込む形状が決まります。ここでは、HTML ツリー内の位置に関係なく、margin-top プロパティを使用して引用文を配置(オフセット)しています。
図形の余白
シェイプの周囲にコンテンツを回り込ませると、要素に近づきすぎることがあります。shape-margin プロパティを使用すると、シェイプの周囲にスペースを追加できます。
.element{
shape-outside: circle(40%);
shape-margin: 1em;
float: left;
}
効果は通常の margin プロパティを使用した場合と似ていますが、shape-margin は shape-outside 値の周囲のスペースにのみ影響します。座標系にスペースがある場合にのみ、シェイプの周囲にスペースが追加されます。そのため、上記の例では、円の半径が 50% ではなく 40% に設定されています。半径を 50% に設定すると、円が座標系のすべてのスペースを占有し、shape-margin の効果を適用する余地がなくなります。シェイプは最終的に要素の margin-box(要素とその周囲の margin)に制限されます。シェイプが大きくてオーバーフローする場合は、margin-box にクリップされ、最終的に長方形になります。
shape-margin は単一の正の値のみを受け入れることを理解しておくことが重要です。ロングハンド表記はありません。円の 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%);
}
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%);
}
図形内のコンテンツを折り返す
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 のストラット要素の位置は重要です。これらの要素は、コンテンツを挟むように左と右にフローティングされるためです。
.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%;
}
このスタイル設定により、2 つのフロート表示されたストラットが要素内のすべてのスペースを占有しますが、shape-outside プロパティによって残りのコンテンツ用のスペースが確保されます。
CSS Shapes がブラウザでサポートされていない場合、すべてのコンテンツが下に押し下げられ、見栄えが悪くなります。そのため、この機能はプログレッシブ エンハンスメントの方法で使用することが重要です。
前述のシェイプ アニメーションの例では、テキストが移動すると煩わしく感じられることがあります。すべてのユースケースでアニメーション シェイプが必要になるわけではありません。ただし、CSS シェイプと相互作用する他のプロパティをアニメーション化して、効果を追加することは可能です。
CSS シェイプの不思議の国のアリスのデモでは、スクロール位置を使用してコンテンツの上部マージンを変更しました。テキストが 2 つのフロート要素に挟まれている。下に移動するにつれて、2 つのフロート要素の shape-outside に従って再レイアウトする必要があります。これにより、テキストがウサギの穴に落ちていくような印象を与え、ストーリーテリングのエクスペリエンスが向上します。不当な行為のボーダーライン?可能であるとは言いきれません。でも、かっこいいですね。
テキスト レイアウトはブラウザによってネイティブに処理されるため、JavaScript ソリューションを使用するよりもパフォーマンスが向上します。しかし、スクロール時に margin-top を変更すると、多くの再レイアウト イベントとペイント イベントがトリガーされ、パフォーマンスが著しく低下する可能性があります。使用する際はご注意ください。ただし、CSS シェイプをアニメーション化せずに使用しても、パフォーマンスに目立った影響はありません。
プログレッシブ エンハンスメント
まず、ブラウザが CSS シェイプをサポートしていないと仮定し、機能を検出したときにその上に構築します。Modernizr は機能検出を行うのに適したソリューションであり、「Non-core detects」セクションに CSS シェイプのテストがあります。
一部のブラウザでは、外部ライブラリを必要とせずに、@supports ルールを介して CSS で機能検出を行うことができます。CSS Shapes にも対応している 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%);
}
}
Lea Verou が、CSS の @supports ルールの使用方法について詳しく説明しています。
CSS の除外からの曖昧性除去
現在 CSS Shapes として知られているものは、仕様の初期段階では CSS Exclusions and Shapes と呼ばれていました。命名の変更はニュアンスの違いのように思えるかもしれませんが、実際には非常に重要です。CSS Exclusions は、現在では別の仕様となっており、float プロパティを使用せずに、任意に配置された要素の周囲にコンテンツを回り込ませることができます。絶対配置された要素の周囲にコンテンツを折り返すことを想像してみてください。これは CSS Exclusions のユースケースです。CSS シェイプは、コンテンツを折り返すパスを定義するだけです。
このように、シェイプと除外は同じものではありませんが、互いに補完し合う関係にあります。CSS Shapes は現在ブラウザで利用できますが、CSS Exclusions はシェイプのインタラクションではまだ実装されていません。
CSS シェイプを操作するためのツール
従来の画像作成ツールでパスを作成することはできますが、この記事の執筆時点では、CSS シェイプの値に必要な構文をエクスポートできるツールはありません。たとえできたとしても、そのような作業方法はあまり実用的ではありません。
CSS シェイプはブラウザで使用されることを想定しており、ページ上の他の要素に反応します。シェイプの編集が周囲のコンテンツに与える影響を視覚化すると、非常に便利です。このワークフローに役立つツールがいくつかあります。
Brackets: Brackets 用の CSS Shapes Editor 拡張機能は、コードエディタのライブ プレビュー モードを使用して、シェイプ値を編集するためのインタラクティブなエディタをオーバーレイします。
Google Chrome: Google Chrome 用の CSS Shapes Editor 拡張機能を使用すると、ブラウザのデベロッパー ツールにシェイプの作成と編集を行うコントロールを追加できます。選択した要素の上にインタラクティブなエディタが配置されます。
Google Chrome のインスペクタには、シェイプをハイライト表示する機能が組み込まれています。shape-outside プロパティを持つ要素にカーソルを合わせると、その要素がハイライト表示され、形状が示されます。
画像からシェイプを抽出する: 画像を生成して、ブラウザで画像からシェイプを抽出する場合は、Rebecca Hauck 氏が執筆した Photoshop のチュートリアルが参考になります。
ポリフィル: Google Chrome は、CSS Shapes を搭載した最初の主要ブラウザです。Apple の iOS 8 と Safari 8 でも、この機能がまもなくサポートされる予定です。他のブラウザ ベンダーも今後検討する可能性があります。それまでは、CSS Shapes polyfill を使用して基本的なサポートを提供できます。
まとめ
コンテンツがシンプルなボックスに閉じ込められていることが多いウェブにおいて、CSS シェイプは表現力豊かなレイアウトを作成する方法を提供し、ウェブデザインと印刷デザインの忠実度のギャップを埋めます。もちろん、図形を不適切に使用すると、気が散る原因になります。しかし、センスと適切な判断に基づいて適用すれば、シェイプはコンテンツの表示を強化し、ユーザーの注意を独自の方法で引き付けることができます。
最後に、他の人による作品集をご紹介します。ほとんどが印刷物ですが、長方形以外のレイアウトの興味深い使い方が示されています。この記事が、CSS シェイプを試して新しいデザインのアイデアを試すきっかけになれば幸いです。
この記事をレビューし、貴重な分析情報を提供してくれた Pearl Chen、Alan Stearns、Zoltan Horvath に感謝します。