CSSのclip-pathプロパティでいろいろ簡単に実装できる、便利な使い方と実装のポイント
Post on:2021年2月2日
CSSのclip-pathプロパティは、非常に便利です。
セクションの区切りを斜めにしたり、ボタンに波紋のエフェクトをつけたり、スクロールして要素がビューポートに入った時にアニメーションで表示されたり、最近のWebページやスマホアプリで見かけるエフェクトはclip-pathプロパティを使用すると、簡単に実装できます。
clip-pathプロパティの基礎知識と便利な使い方、実装のポイントなどを詳しく解説します。
Understanding Clip Path in CSS
by Ahmad Shadeed
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
はじめに
clip-pathプロパティを使用すると、内部のコンテンツは表示され、外部のコンテンツは非表示になるクリッピング領域を作成します。
簡単な例として、clip-pathで円を作成してみます。
1 2 3 4 |
.card { background-color: #77cce9; clip-path: circle(80px at 50% 50%); } |
clip-pathで円を作成
clip-pathを適用すると、表示されるエリアはブルーの円だけです。円の外側は表示されません。
下記のように円に切り抜きます。
clip-pathで円に切り抜く
clip-pathプロパティのサポートブラウザは、下記の通りです。
IEを除くすべてのブラウザにサポートされています。
※ダークグリーン(部分的なサポート)は、インラインSVGの形状とurl(#foo)構文のサポートはしますが、外部SVGの形状はサポートしません。
この記事では、SVGはurl(#foo)構文で解説しています。
clip-pathプロパティにおける座標
clip-pathについて解説する前に、座標の仕組みについて触れておきます。原点は左上隅で、x軸は右に、y軸は下に向いています。
原点は左上隅、x軸は右に、y軸は下に
これを念頭において、要素がどのようにクリップされるかを見てましょう。下記の例は、クリップされるエリアは100pxの円で、その中心は0,0(top, left)に位置しています。
ハイライトされた部分のみが表示されます
濃いブルーにハイライトされたエリアだけがユーザーに表示されることに注目してください。円の残りのエリアはクリップされます。
上記のCSSでは、右下の1/4円のみが表示されます。
問題は、座標をどう指定すれば完全な円を表示できるかということです。この場合は、x軸とy軸のポイントを変更する必要があります。
x軸とy軸のポイントを変更
円の中心を左から100px、上から100pxの位置に変更します。
座標がどのように機能するかを理解したので、clip-pathについてまずは使用可能な値から解説します。
clip-pathプロパティに使用できる値
clip-pathプロパティに使用できる値について、見てみましょう。
inset()値
inset()値はインセットの矩形を定義します。marginやpaddingと同じように4つの辺を定義できます。下記の例では、カードのすべての辺(上・右・下・左)から20pxのインセットがあります。
1 2 3 |
.card { clip-path: inset(20px); } |
inset()値の例、濃いブルーのエリアだけがユーザーに表示される
1つの辺からのインセットの値を調整することも可能です。
1 2 3 |
.card { clip-path: inset(20px 20px 50px 20px); } |
下の辺からの値だけを50pxにします。
marginやpaddingと同じように定義できる
角丸にしたい場合は、どうすればよいでしょうか?
答えは、簡単です。roundというキーワードで、簡単に角丸ができます。
1 2 3 |
.card { clip-path: inset(20px 20px 50px round 15px); } |
角丸の実装は、簡単
各辺の半径を個別に調整することもできます。
下記は、右上隅と左下隅の半径がゼロの例です。
1 2 3 |
.card { clip-path: inset(20px 20px 50px round 15px 0); } |
右上隅と左下隅の半径がゼロの例
circle()値
circle()値は円形のクリッピングを定義するため、半径とその位置が必要です。
1 2 3 |
.card { clip-path: circle(80px at 50% 50%); } |
円の半径は80pxで、x軸は50%、y軸は50%に配置されます。
ellipse()値
ellipse()値は幅と高さを定義して、楕円形のクリッピングを作成できます。
1 2 3 |
.card { clip-path: ellipse(100px 80px at center); } |
ellipse()値は楕円形にクリッピング
polygon()値
個人的にpolygon()値が最も興味深いです。x軸とy軸の値の複数の異なるセットを制御する機能があります。
1 2 3 |
.card { clip-path: polygon(x y, x y, x y, x y); } |
例えば、polygon()値で矩形にクリッピングしてみましょう。ポイントの各セットを軸上の座標にどのようにマッピングしているか確認してみてください。
1 2 3 |
.card { clip-path: polygon(5% 5%, 95% 5%, 95% 95%, 5% 95%); } |
polygon()値で、矩形にクリッピング
上記はシンプルな矩形ですが、polygon()値に複数のポイントを定義して複雑な形状を作成することもできます。
path()値
path()値を使用すると、SVGのパスで特定のエリアをクリップできます。現在のところ、ブラウザのサポートには一貫性がないため、異なるブラウザ間で機能させるには、インラインのSVGを使用して、clip-pathの値としてurl()を使用する必要があります。
1 2 3 4 5 |
<svg class="svg"> <clipPath id="triangle" clipPathUnits="objectBoundingBox"> <path d="M0.05,0.05 h1 v1"></path> </clipPath> </svg> |
CSSでは、url()値にパスを定義します。
1 2 3 |
.card { clip-path: url("#triangle"); } |
path()値はSVGのパスで特定のエリアをクリップできる
clip-pathの基礎知識と使用可能な値について解説しました。次は、clip-pathを使用した実装を解説します。
準備はいいですか?
clip-pathプロパティを使用した実装
斜めのエフェクト
Webページでこのエフェクトを見たことがあるかもしれません。この斜めのエフェクトはclip-pathにぴったりの使い方です。
clip-pathで斜めにする
斜めのエフェクトをどのように実装していると思いますか?
この実装には、polygon()を使用します。
1 2 3 |
.section { clip-path: polygon(0 0, 100% 0, 100% 80%, 0 100%); } |
polygon()に8つの値を調整するのが面倒かもしれません。しかし、ブラウザを使用して図形を簡単に作成することができます。
まずは、下記のように記述します。
1 2 3 |
.section { clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); } |
デベロッパーツールを起動して、その要素を検証します。すると、polygon()の左側に小さなポリゴンアイコンがあることに気がつくでしょう。
デベロッパーツールでその要素を検証する
そのアイコンをクリックすると、ブラウザ上で図形を編集できます。便利だと思いませんか?
実際の操作は、下記をご覧ください。
ブラウザ上で図形を編集できる
斜めの角度をレスポンシブ対応にしてみましょう。
ビューポートの幅に対して角度を決める場合は、calc()が便利です。
1 2 3 |
.section { clip-path: polygon(0 0, 100% 0, 100% calc(100% - 5vw), 0 100%); } |
このテクニックは、Kilian Valkhofのブログで学びました。
複数に斜めのエフェクトを適用する
斜めのエフェクトは複数の要素に必要なのか?と疑問に思いましたが、下記をご覧ください。
複数の要素を斜めにする
私が最初に考えたのは、単にbox-shadowやborderを追加することです。残念ながら、それらはクリッピングされてしまうので、期待どおりに表示されませんでした。
解決策は、複数の要素のそれぞれのクリッピングのポイントを変えることです。
1 2 3 |
<div class="hero"> <img src="bg.jpg" alt="" /> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
.hero { position: relative; min-height: 350px; } .hero img { position: absolute; left: 0; top: 0; width: 100%; height: 100%; clip-path: polygon(0 0, 100% 0, 100% 80%, 0 90%); } .hero:after { content: ""; position: absolute; left: 0; bottom: -20%; z-index: -1; width: 100%; height: 100%; background-color: #4545a0; clip-path: polygon(0 0, 100% 0, 100% 80%, 0 90%); } |
同じ大きさでクリップパスを持つ疑似要素を用意しています。2つの違いは、bottom: -20%;とz-index: -1;で配置していることです。20は、100 - 80から算出した値です。
スクロールに合わせて要素を表示
IntersectionObserver APIを使用することで、ユーザーがスクロールして要素がビューポートに入った時に要素を表示できます。
参考: Intersection Observerが簡単で便利!要素がビューポートに表示されているかを判定できる
このエフェクトに便利だと思ったclip-pathの値は、insetです。あなたはなぜ?と思うかもしれません。図で説明します。
inset()の値で矩形がどのように表示されるか
一番下のinset(50%)を適用することで、ブルーの矩形が完全に見えなくなることに注目してください。四辺からインセットを適用しているため、非表示になる値は50%です。つまり、矩形の端から中心に向かってインセットが適用されています。
次の図では、ユーザーがスクロールしている間に画像を表示するためにinsetを使用しています。
ユーザーのスクロール操作に合わせて画像を表示
JavaScriptで、ビューポート内にある各画像に.is-visibleを追加します。これでユーザーがスクロールして画像をビューポートに入った時に表示させることができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const images = document.querySelectorAll("img"); function check(entries) { entries.map((entry) => { if (entry.isIntersecting) { entry.target.classList.add("is-visible"); observer.unobserve(entry.target); } }); } const observer = new IntersectionObserver(check); images.forEach((image) => observer.observe(image)); |
1 2 3 4 5 6 7 8 |
img { clip-path: inset(50%); transition: 1.2s ease-in; } img.is-visible { clip-path: inset(0); } |
シンプルに実装できました。
数行のCSSとJavaScriptを使用するだけで、スクロールのエフェクトが完成です。
See the Pen
Reveal on Scroll by Ahmad Shadeed (@shadeed)
on CodePen.
しかも、遷移の方向を制御することもできます。実装には、四辺から1つの値を使用するだけです。例えば、上から下への遷移をしたい場合は、下の値を100%から0に遷移させる必要があります。下記は、それを説明したものです。
四辺それぞれから遷移させる時の値
実際の動作は、下記のデモページでご覧ください。
See the Pen
Animations - Clip Path - Inset by Ahmad Shadeed (@shadeed)
on CodePen.
ホバーとアニメーションのエフェクト
clip-pathを使ったホバーエフェクトとアニメーションエフェクトを作成する可能性は無限大です。下記の例で見てみましょう。
普通のよくあるボタン
これらのボタンにホバーとアニメーションのエフェクトを与えます。必要なのは、指定した位置からスケールするホバーエフェクトを追加することです。circle()を使用してみます。
より簡単に、よりメンテナンスしやすくするために、CSSの変数をします。そうすれば、全体を複製する必要はありません。必要なCSSの変数のみを変更するだけです。
参考: CSSの変数(カスタムプロパティ)の基礎知識、便利な使い方を詳しく解説
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
:root { --pos: left center; --size: 0; } .stats__item:before { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: #7777e9; clip-path: circle(var(--size) at var(--pos)); transition: 0.4s linear; } .stats__item:hover:before { --size: 300px; } |
これで、完成です。
clip-pathによるホバーとアニメーションのエフェクト
アニメーションの位置を変更するのも簡単です。
下記のデモではドロップダウンから位置を変更できます。
See the Pen
Animations - Clip Path by Ahmad Shadeed (@shadeed)
on CodePen.
アニメーションのエフェクトをさらに掘り下げたい場合は、clip-pathに100%依存した非常に便利なCSSアニメーションのライブラリTransition.cssをチェックしてみてください。
波紋のエフェクト
波紋のエフェクトは、Material Designで人気がでました。clip-pathを使用すると、このエフェクトも簡単に実装できます。
波紋のエフェクト
1 |
<button class="button"><span>Sign up now</span></button> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
.button { position: relative; } .button span { position: relative; z-index: 1; } .button:before { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: #fff; opacity: 0.1; clip-path: circle(0 at center); transition: 0.3s ease-out; } .button:hover:before { clip-path: circle(100px at center); } |
下記のデモではドロップダウンから位置を変更できます。
See the Pen
Button Ripple Effect by Ahmad Shadeed (@shadeed)
on CodePen.
終わりに
clip-pathで知っておくべきこと
-
- 非表示エリアは、ポインターのイベントを取得できない
- エリアがクリップされると、その外側にあるエリアはポインターのイベントを受け取りません。つまり、ユーザーはその上にカーソルを合わせることができません。
-
- 相対値を使用できる
- font-sizeを基準にしてclip-pathを作成できますか?
はい、できます。clip-pathの値にemやremを使用すれば完了です。
リソース
CSSのデバッグに関する電子書籍を書いていることをお知らせします。
興味がある場合は、debuggingcss.comにアクセスして、本に関する最新情報を購読してください。
コメントや提案があれば、@shadeed9までお願いします。
sponsors