クリップパスでの要素の切り抜き
基本的に画像は四角ですが、時には丸や、星など様々な形に切り抜きたいことがあります。
そんな時便利なものが、clip-pathです。
clip-pathを使用すると例えば以下のようなものを作る事ができます。
See the Pen Untitled by tora (@-tora-) on CodePen.
クリップパスのメンタルモデル
クリッピングパスは切り抜きたい図形を(x,y)の座標で制作し、その図形からはみ出たエリアをカットし、内側を表示します。
切り抜く形の図形の境界線をクリッピングパスと言い、座標を直接指定したり、SVGを使用する事が可能です。
例えば以下のような図形で切り抜きたい場合のパスの制作方法について解説します。
クリッピングパスの考え方は元の四角い画像をキャンバスとし、そのキャンバスに座標を指定してパスをつなげていきます。
左上が原点となり、x軸0、y軸0となります。
以下のように、例えば、キャンバスの右上はx軸100%、y軸0%です。
キャンバスの中心は(50%, 50%)で、右下は(100%, 100%)となります。
この座長を横長の8角形になるようにプロットし、その点を直線で結ぶ事でパスが出来上がります。
以下の図ご覧ください。
このプロットした座標のデータをまとめると以下のような集まりになります。
30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%
このデータをclip-pathのpolygon関数に始まりのポイントはどこでもよいのですが、必ず時計回りに座標を並べていきます。
座標はx,yで一組のセットですので、半角スペースを空け、2つの値を1組とし、その組をカンマ区切りで記載します。
すると以下のようなcssとなり、これで完成です。
clip-path: polygon(30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%);
あとはこれをimgタグに適応するだけで制作した形に画像を切り抜いてくれます。
この例ではpolygon関数関数を使用しましたが、使用可能な関数は以下があります。
- inset()
- circle()
- ellipse()
- polygon()
- path()
- url()
inset()
内側に小さくなった四角形に切り取ります。
書き方
clip-path: inset(オフセット値 round 角丸の値); // 例 clip-path: inset(10px 20px 30px 40px round 10px);
roundの左がどのくらい内側に境界線をオフセットするかを表し、 roundの右がborder-radiusと同じ、角丸の半径を表しています。
境界線のオフセットは他のcssの値の指定方法を同じように、topから時計回りにright,bottom,leftと指定していきます。
もちろん省略し、まとめて『10px』や『10px 20px』という指定も可能です。
circle()
circleは円形に切り抜きます。
書き方
clip-path: circle(半径 at 位置); // 例 clip-path: circle(50px at center);
atの右が円の半径を表し、atの右が中心の位置を表します。
円の半径は%でも表す事も可能ですが、計算がややこしいのであまり使用しません。
中心の値は他にも以下のように指定することが可能です。
clip-path: circle(50px at 50% 50%); // x軸y軸で50%とする事でcenterと同じになります。 clip-path: circle(50px at 100px 100px); // x軸y軸でpxで指定して中心に寄せる事もできます。 clip-path: circle(50px); // 省略するとデフォルトでcenterとなるります。
ellipse()
ellipseは楕円形に切り抜くことが可能です。
書き方
clip-path: ellipse(x軸方向の半径 y軸方向の半径 at 位置); // 例 clip-path: ellipse(100px 50px at center);
atの左側にx軸y軸の半径を表し、atの右側に位置を表します。
円の中心の表し方はcircleの時と同じ方法が使えます。
polygon()
polygonは多角形に切り抜く事が可能です。
書き方
clip-path: polygon(xとyの組みあせ座標の配列); // 例 clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
初めの例にも記載しましたが、x軸y軸のデータを並べ、その点を結ぶ事でパスを形成します。
始まりのポイントはどこでもよいのですが、必ず時計回りに座標を並べていきます。
座標はx,yで一組のセットですので、半角スペースを空け、2つの値を1組とし、その組をカンマ区切りで記載します。
path()
pathを使用する事でSVGのパスを使用して切り抜く事が可能です。
以下はSVGアイコンのパスデータです。
こちらのd=””の部分のコードをpath()にセットする事でそのSVGの形に切り抜く事ができます。
以下は上のパスを実際に使用した例です。
See the Pen Untitled by tora (@-tora-) on CodePen.
画像をくり抜く場合、こちらのSVGを使用したくり抜きが多いかと思います。
ですが、SVGパスをpath関数にセットして制作する事は少し面倒です。
d=””を探したり、パスの成型したり、工数がかかる上、以下のようにパスが複数に分かれている場合はなおさらです。
例えば以下のようなSVG画像があった場合、月マークで1つのpath。星マークで1つのpathと分かれています。
このようにパスが複数に分かれている場合はclip-pathの指定方法が面倒になります。
複数のパスを使用する方法
SVGデータで別々になっているため複数のパスをセットして切り抜きを行いたい場合がありますが、その場合、画像を複数用意する必要があります。
clip-pathは画像1枚につき、1つしか指定する事ができません、ですので、画像をパスの数だけ用意し、それぞれの画像にclip-pathをセットします。
例として上ででてきたの月と星のSVGの形にくり抜いてみます。
今回は月と星の2つのパスが必要なので、同じ画像を2つ用意します。
そして、その画像完全に同じ位置に重ねます。
<div class="wrap"> <img class="img1" src="画像までのパス"/> <img class="img2" src="画像までのパス"/> </div> <style> .wrap { width: 300px; position: relative; } .img1 { } .img2 { position: absolute; top: 0; left: 0; } </style>
次にそれぞれの画像に月と星のパスをclip-pathにセットします。
順番はどちらでも大丈夫です。
.img1 { clip-path: path("M403.469,395.031c-129.203,0-233.938-104.75-233.938-233.953c0-62.438,24.5-119.125,64.375-161.078C109.313,17.953,13.563,125.094,13.563,254.656C13.563,396.781,128.781,512,270.906,512c98.688,0,184.359-55.578,227.531-137.125C469.406,387.781,437.297,395.031,403.469,395.031z"); } .img2 { position: absolute; top: 0; left: 0; clip-path: path("M349.641,179.328c1.047,1.016,1.516,2.484,1.266,3.922l-8.563,49.938c-0.281,1.672,0.406,3.344,1.766,4.344c1.359,0.984,3.156,1.109,4.656,0.328l44.859-23.578c1.281-0.688,2.813-0.688,4.109,0l44.859,23.578c1.484,0.781,3.297,0.656,4.656-0.328c1.359-1,2.031-2.672,1.75-4.344l-8.563-49.938c-0.25-1.438,0.219-2.906,1.266-3.922L478,143.969c1.203-1.172,1.641-2.938,1.125-4.531c-0.531-1.594-1.906-2.781-3.578-3.016l-50.141-7.297c-1.438-0.203-2.688-1.109-3.344-2.406l-22.422-45.453c-0.734-1.516-2.281-2.453-3.969-2.453c-1.672,0-3.219,0.938-3.953,2.453l-22.438,45.453c-0.641,1.297-1.891,2.203-3.328,2.406l-50.141,7.297c-1.672,0.234-3.063,1.422-3.578,3.016s-0.078,3.359,1.125,4.531L349.641,179.328z"); }
実際に制作したものが以下になります。
See the Pen Untitled by tora (@-tora-) on CodePen.
url()
path関数を使用してSVGの形でくり抜く事はできますが、上の例で見たように複数のパスがある場合は設定が面倒になってきます。
そんな時にurl関数を使用する事で簡単に解決する事が可能です。
url関数はSVGスプライトのように、SVGデータをインラインデータとして記載し、そのIDをurl関数に記載する事で使用する事ができます。
まずはSVGデータを用意し、そのデータをSVGスプライトとして扱えるように変換します。
変換方法は以下の記事を参照ください。
SVGスプライトを制作すると以下のようなコードを取得できるかと思います。
<svg> <defs> <symbol id="icon-sample" width="600" height="600" viewBox="0 0 600 600"> <path d="M118.204 115.732c-37.852 0-68.537-30.688-68.537-68.541 0-18.292 7.178-34.9 18.86-47.191-36.502 5.26-64.554 36.649-64.554 74.606 0 41.638 33.755 75.394 75.393 75.394 28.912 0 54.011-16.283 66.659-40.173-8.505 3.781-17.912 5.905-27.823 5.905z"></path> <path d="M102.434 52.538c0.307 0.298 0.444 0.728 0.371 1.149l-2.509 14.63c-0.082 0.49 0.119 0.98 0.517 1.273 0.398 0.288 0.925 0.325 1.364 0.096l13.142-6.908c0.375-0.202 0.824-0.202 1.204 0l13.142 6.908c0.435 0.229 0.966 0.192 1.364-0.096 0.398-0.293 0.595-0.783 0.513-1.273l-2.509-14.63c-0.073-0.421 0.064-0.851 0.371-1.149l10.634-10.359c0.352-0.343 0.481-0.861 0.33-1.327-0.156-0.467-0.558-0.815-1.048-0.884l-14.69-2.138c-0.421-0.059-0.787-0.325-0.98-0.705l-6.569-13.316c-0.215-0.444-0.668-0.719-1.163-0.719-0.49 0-0.943 0.275-1.158 0.719l-6.574 13.316c-0.188 0.38-0.554 0.645-0.975 0.705l-14.69 2.138c-0.49 0.069-0.897 0.417-1.048 0.884s-0.023 0.984 0.33 1.327l10.63 10.359z"></path> </symbol> </defs> </svg>
こちらのsymbol部分をclipPathに変更します。
<svg> <defs> <clipPath id="icon-sample" width="600" height="600" viewBox="0 0 600 600"> <path d="M118.204 115.732c-37.852 0-68.537-30.688-68.537-68.541 0-18.292 7.178-34.9 18.86-47.191-36.502 5.26-64.554 36.649-64.554 74.606 0 41.638 33.755 75.394 75.393 75.394 28.912 0 54.011-16.283 66.659-40.173-8.505 3.781-17.912 5.905-27.823 5.905z"></path> <path d="M102.434 52.538c0.307 0.298 0.444 0.728 0.371 1.149l-2.509 14.63c-0.082 0.49 0.119 0.98 0.517 1.273 0.398 0.288 0.925 0.325 1.364 0.096l13.142-6.908c0.375-0.202 0.824-0.202 1.204 0l13.142 6.908c0.435 0.229 0.966 0.192 1.364-0.096 0.398-0.293 0.595-0.783 0.513-1.273l-2.509-14.63c-0.073-0.421 0.064-0.851 0.371-1.149l10.634-10.359c0.352-0.343 0.481-0.861 0.33-1.327-0.156-0.467-0.558-0.815-1.048-0.884l-14.69-2.138c-0.421-0.059-0.787-0.325-0.98-0.705l-6.569-13.316c-0.215-0.444-0.668-0.719-1.163-0.719-0.49 0-0.943 0.275-1.158 0.719l-6.574 13.316c-0.188 0.38-0.554 0.645-0.975 0.705l-14.69 2.138c-0.49 0.069-0.897 0.417-1.048 0.884s-0.023 0.984 0.33 1.327l10.63 10.359z"></path> </clipPath> </defs> </svg>
次にimgを用意し、そのimgに対してurl関数を使用してパスを当てます。
当て方は元々symbolだった位置にあったid(いまはclipPathのid)を指定する事で可能です。
<svg> <defs> <clipPath id="icon-sample" width="600" height="600" viewBox="0 0 600 600"> <path d="M118.204 115.732c-37.852 0-68.537-30.688-68.537-68.541 0-18.292 7.178-34.9 18.86-47.191-36.502 5.26-64.554 36.649-64.554 74.606 0 41.638 33.755 75.394 75.393 75.394 28.912 0 54.011-16.283 66.659-40.173-8.505 3.781-17.912 5.905-27.823 5.905z"></path> <path d="M102.434 52.538c0.307 0.298 0.444 0.728 0.371 1.149l-2.509 14.63c-0.082 0.49 0.119 0.98 0.517 1.273 0.398 0.288 0.925 0.325 1.364 0.096l13.142-6.908c0.375-0.202 0.824-0.202 1.204 0l13.142 6.908c0.435 0.229 0.966 0.192 1.364-0.096 0.398-0.293 0.595-0.783 0.513-1.273l-2.509-14.63c-0.073-0.421 0.064-0.851 0.371-1.149l10.634-10.359c0.352-0.343 0.481-0.861 0.33-1.327-0.156-0.467-0.558-0.815-1.048-0.884l-14.69-2.138c-0.421-0.059-0.787-0.325-0.98-0.705l-6.569-13.316c-0.215-0.444-0.668-0.719-1.163-0.719-0.49 0-0.943 0.275-1.158 0.719l-6.574 13.316c-0.188 0.38-0.554 0.645-0.975 0.705l-14.69 2.138c-0.49 0.069-0.897 0.417-1.048 0.884s-0.023 0.984 0.33 1.327l10.63 10.359z"></path> </clipPath> </defs> </svg> <div class="wrap"> <img class="img" src="https://sushirice.pro/wp-content/uploads/2022/07/キャンドル-scaled.jpg"/> </div> <style> .img { clip-path: url(#icon-sample); } </style>
実際に実装したものが以下になります。
See the Pen Untitled by tora (@-tora-) on CodePen.
アニメーション
transitionもしくは@keyframesを使って簡単なアニメーションを作る事ができます。
以下はホバーする事でパスが変形するデモです。
See the Pen Untitled by tora (@-tora-) on CodePen.
transitionを使用しして滑らかなアニメーションを適応させています。
clip-pathでも他でtransitionを使用するのと同じように使う事ができますが、注意が必要な点があります。
それは、パスの座標の数を変更する事ができない点です。
パスを指定する際に以下のようにパスの座標を並べましたが、変化前と変化後で座長の数が異なっています。
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); // 変化前は4点だったものが、変化後が以下のように3点になっている clip-path: polygon(50% 0%, 100% 50%, 50% 100%);
このような変形の場合、transitionプロパティは効果を機能せず、瞬時に見た目が切替わってしまいます。
以下はそのデモです。
See the Pen Untitled by tora (@-tora-) on CodePen.
@keyframesを使用する場合も、一般的に使用する時と変わらない形で使用する事が可能です。
See the Pen Untitled by tora (@-tora-) on CodePen.
クリップした要素への影の付け方
clip-pathで切り抜いた要素へ影をつける場合は注意が必要になります。
以下のデモを見てください。
See the Pen Untitled by tora (@-tora-) on CodePen.
このデモでは切り抜いたimgにたいしてdrop-shadowをつけています。
ですが、影はついていません。
これは順番に依存するためにです。
初めに影が付けられ、その後で切り抜きが行われるので、影も切り取られてしまっている状態になります。
ですので、切り抜きを行った要素自体ではなく、親要素に影をつける必要があります。
See the Pen Untitled by tora (@-tora-) on CodePen.
ここでbox-shadowではなくdrop-shadowを使用している点にも注意です。
box-shadowの場合、ボックスモデルの外側に対して影をつけるので四角い影がついてしまいます。
パスジェネレーター
もし、切り抜きたい形のSVGが見つからない。複雑でパスの座標を自分で考える事が難しい場合はジェネレーターを使用する事で直観的にオリジナルのパスを制作する事が可能です。
スクロール
よくページのトップへ戻るボタンや、目次などをクリックすると自動でスクロールされ、目的の場所へ移動するUIがあります。
その際にスクロールが滑らかに行われますが、あれはデフォルトの動きではありません。
通常はこの↓ように一瞬で移動します。
この一瞬で移動するという動きはユーザーにとって状態の変換がわかりにくいので、ページを移動したのか、ページのスクロール位置が変更されたのかが判別しにくく、少し使いずらい印象を受けます。
ですので、スクロールを滑らかにしている事が多いですが、以下のように記載する事でcssからスクロールを滑らかにする事が可能です。
html { scroll-behaviour: smooth; }
ページの一番root(一番初め)となるhtml要素に対してscroll-behaviour: smooth;を適応します。
実際の例が以下です。
スクロールのオフセット
以下はよくあるデザインかと思います。
メニューがスクロール固定されており左に本文、右に目次があるタイプで、目次をクリックすると本文の各見出しが画面トップになるようにスクロールされます。
スムーズなスクロールはscroll-behaviour: smooth;で実現していますが、1つ問題があります。
それは固定されたメニューのせいで見出しが隠れてしまうためです。
デフォルトの状態では目次クリックでスクロールした際に対象の要素がページのトップ(y軸の0pxの位置)に移動するようになっています。
この問題を解決するためにはページのトップからマージンを持たせる必要がありますが、これはscroll-margin-topで解決可能です。
今回の例ではヘッダーメニューの高さが50pxでしたのでトップのマージンを60pxにします。
html { scroll-behaviour: smooth; } h2 { scroll-margin-top: 60px; }
scroll-behaviour: smooth;は一番トップレベルのhtmlに設定していますが、scroll-margin-topはマージンを持たせたい要素に記載します。
今回はh2の見出ししかないですのでh2に対してのみscroll-margin-topをセットしましたが、h3,h4,h5と対象の要素が増えればそれぞれにセットする必要があります。
以下は使用したデモです。
スクロールスナップ
scroll-behaviourはスクロールをスムーズにするものでした。
では以下のような、近い方の要素を表示するようなスクロールを実装する場合はどうしたらよいでしょうか。
See the Pen Untitled by tora (@-tora-) on CodePen.
このようなスクロールにはscroll-snap(スクロールスナップ)が有効です。
scroll-snapはscroll-snap-typeとscroll-snap-alignを組み合わせて使用します。
<div class="wrap"> <div class="inner"> <div class="box item-1">item1</div> <div class="box item-2">item2</div> <div class="box item-3">item3</div> <div class="box item-4">item4</div> <div class="box item-5">item5</div> </div> </div> <style> .wrap { scroll-snap-type: x mandatory; } .box { scroll-snap-align: center; } </style>
※必要なcss以外は省いています。実際に上の例を制作するためには他のスタイルも必用です。
scroll-snap-type
scroll-snap-typeはスクロールの方向と種類を決めます。記載する場所はoverflow: auto;でスクロール設定をした要素です。
scroll-snap-type: 方向 タイプ;
方向は以下から選ぶ事ができます。
- x -> x軸方向になりますので水平方向です。
- y -> y軸方向になりますので垂直方向です。
- block -> blockなので垂直です。(yと同じです)
- inline -> inlineなので水平方向です。(xと同じです)
- both -> xとy両方です。
タイプは以下から選ぶ事ができます。
- mandatory -> スクロールを解除した時にスナップ点により近い要素を必ず表示します。
- proximity -> スナップ点に近い時には近い要素が表示されますが、近くない時はその場にとどまります。
スクロールタイプは文章では伝わりずらいので以下のデモを触って実際に確かめてみてください。
See the Pen Untitled by tora (@-tora-) on CodePen.
今回はx軸方向でmandatoryのスクロールタイプを使用したいので以下のようになります。
.wrap { scroll-snap-type: x mandatory; }
scroll-snap-align
scroll-snap-alignはスナップの軸を設定します。
以下の値を設定する事が可能です。
- start -> スクロールスナップ領域の先頭に軸が置かれます
- end -> スクロールスナップ領域の最後に軸が置かれます
- center -> スクロールスナップ領域の中央に軸が置かれます
startをセットするとスクロールスナップ領域の先頭に軸が置かれます。
以下のデモをご覧ください。
See the Pen Untitled by tora (@-tora-) on CodePen.
endをセットするとスクロールスナップ領域の最後に軸が置かれます。
以下のデモをご覧ください。
See the Pen Untitled by tora (@-tora-) on CodePen.
centerをセットするとスクロールスナップ領域の中央に軸が置かれます。
以下のデモをご覧ください。
See the Pen Untitled by tora (@-tora-) on CodePen.
スクロールバーのデザイン変更
上デモでスクロールを有効にするとスクロールバーがでたのがわかると思いますがこのススクロールバーの見た目はOS毎に異なります。
以下はwindowsとMacでの見た目の違いです。
このようにwebサイトを閲覧するユーザーのパソコンのOSによって見た目が変わってきてしまいます。
そのせいで以下のようにせっかくのデザインがカッコ悪くなってしまう事もあるでなるべく同じ見た目、カッコいいい見た目でそろえておきたいですよね。
スクロールバーの見た目をカスタマイズする
スクロールバーをカスタマイズするためにはまずスクロールバーの名称から知っておく必要があります。
スクロールバーは以下のように2つのパーツが組み合わさっています。
thumb(サム)は表示中のコンテンツの位置を表します。
trackは全体の高さを表します。
この2つそれぞれのスタイルを変更していきます。
色を変化させる
まずは色を変化させてみましょう。
今回は以下のようなデザインを再現してみます。
html構造は以下です。
<ul class="list"> <li class="list-item">メニュー1</li> <li class="list-item">メニュー1</li> <li class="list-item">メニュー1</li> ... 略 ... <ul>
list要素にoverflow-y: auto;をセットし、スクロール可能にしています。
スクロールバーはoverflow-y: auto;をつけたlist要素に対して表示されますので、list要素にスクロールバーのスタイルを定義していきます。
.list::-webkit-scrollbar { // こちらでtrackの色を変更する事が可能です。 background-color: rgba(255, 255, 255, 0.2); } .list::-webkit-scrollbar-thumb { // こちらでthumbの色を変更する事が可能です。 background-color: #fff; }
サイズを変更する
色を変更する事はできましたが、まだ不格好です。
ここからサイズや形を変化させていきましょう。
要領としては色を変化させた時と同じで、スタイルを適応させたい箇所に目的のスタイルを記載していくだけです。
今回はスクロールバー全体の幅を細くし、thumbの角を丸くします。
.list::-webkit-scrollbar { // こちらでtrackの色を変更する事が可能です。 background-color: rgba(255, 255, 255, 0.2); width: 5px; } .list::-webkit-scrollbar-thumb { // こちらでthumbの色を変更する事が可能です。 background-color: #fff; border-radius: 10px; }
以下は実際に出来上がったでもになります。