クリップパスを動かす(HTML/CSS/JS)
前書き
クリップパス(clip-path)をアニメーションさせる方法を掲載しています。
目次
- 準備
- 三点
- 四点
- 円
- 組合せ
- 参考
準備
下記サイトを参考にしてパスを設定しています。
CSS clip-path maker
GSAP(GreenSock社が開発しているJavaScriptライブラリ)を使用しています。
こちらのページからダウンロード出来ます。
GSAP Installation
当ページでは、2つのファイルを読み込んでいます。
import { gsap } from './gsap_3.10.4/esm/gsap-core.js';
import { CSSPlugin } from './gsap_3.10.4/esm/CSSPlugin.js';
三点
要素を重ねて配置して、それぞれ、clip-pathを変化させています。
九つの点を準備して、そこから三つの点を選んでいます。
いろは
いろは
にほへと
にほへと
にほへと
にほへと
ちりぬるを
ちりぬるを
ちりぬるを
ちりぬるを
<div class="wrap">
<div class="item item01 js-311">いろは</div>
<div class="item item02 js-312">いろは</div>
</div>
<div class="wrap">
<div class="item item01 js-321">にほへと</div>
<div class="item item02 js-322">にほへと</div>
<div class="item item03 js-323">にほへと</div>
<div class="item item04 js-324">にほへと</div>
</div>
<div class="wrap">
<div class="item item01 js-331">ちりぬるを</div>
<div class="item item02 js-332">ちりぬるを</div>
<div class="item item03 js-333">ちりぬるを</div>
<div class="item item04 js-334">ちりぬるを</div>
</div>
.wrap{
position: relative; height: 5.5em;
}
.item{
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
display: flex; justify-content: center; align-items: center;
writing-mode: vertical-rl; text-orientation: upright;
}
.item01{ color: #595757; background: #c9c9ca; }
.item02{ color: #e5e6e6; background: #417abe; }
.item03{ color: #e5e6e6; background: #346c9c; }
.item04{ color: #e5e6e6; background: #35526d; }
// 座標
const div = [0, 50, 100];
const num = div.length;
const point = [];
let key = 1;
for (let i = 0; i < num; i++) {
for (let j = 0; j < num; j++) {
point[key] = div[j] + "% " + div[i] + "%"; //1: "0% 0%" ... 9: "100% 100%"
key++
}
}
//座標を代入
const cp3 = (a, b, c) => {
return "polygon(" + point[a] + "," + point[b] + "," + point[c] + ")";
}
//座標を動かす1------------------
const tl31 = gsap.timeline({
defaults: {ease: "power0", duration: 1}
});
const init31 = () => {
gsap.set(".js-312", {clipPath: cp3(1, 4, 7)}); //左端
}
const motion31 = () => {
tl31.to(".js-312", {clipPath: cp3(1, 5, 7)})
.to(".js-312", {clipPath: cp3(2, 7, 6)})
.to(".js-312", {clipPath: cp3(9, 8, 2)})
.to(".js-312", {clipPath: cp3(7, 9, 2)})
}
init31();
motion31();
//座標を動かす2------------------
const tl32 = gsap.timeline({
defaults: {ease: "power0", duration: 1}
});
const init32 = () => {
gsap.set(".js-322", {clipPath: cp3(9, 9, 9)}); //右下角
gsap.set(".js-323", {clipPath: cp3(1, 1, 1)}); //左上角
gsap.set(".js-324", {clipPath: cp3(7, 7, 7)}); //左下角
}
const motion32 = () => {
tl32.to(".js-322", {clipPath: cp3(1, 7, 9)})
.to(".js-323", {clipPath: cp3(1, 9, 3)})
.to(".js-324", {clipPath: cp3(3, 7, 9)});
}
init32();
motion32();
//座標を動かす3------------------
const tl33 = gsap.timeline({
defaults: {ease: "power0", duration: 1}
});
const init33 = () => {
gsap.set(".js-334", {clipPath: cp3(1, 1, 7)}); //左端
gsap.set(".js-333", {clipPath: cp3(7, 3, 3)});
gsap.set(".js-332", {clipPath: cp3(7, 6, 6)});
}
const motion33 = () => {
tl33.to(".js-334", {clipPath: cp3(1, 3, 7)})
.to(".js-333", {clipPath: cp3(7, 3, 6)})
.to(".js-332", {clipPath: cp3(7, 6, 9)});
}
init33();
motion33();
四点
要素を重ねて配置して、それぞれ、clip-pathを変化させています。
九つの点を準備して、そこから四つの点を選んでいます。
わかよ
わかよ
たれそ
たれそ
たれそ
たれそ
つねならむ
つねならむ
つねならむ
<div class="wrap">
<div class="item item01 js-411">わかよ</div>
<div class="item item02 js-412">わかよ</div>
</div>
<div class="wrap">
<div class="item item01 js-421">たれそ</div>
<div class="item item02 js-422">たれそ</div>
<div class="item item03 js-423">たれそ</div>
<div class="item item04 js-424">たれそ</div>
</div>
<div class="wrap">
<div class="item item01 js-431">つねならむ</div>
<div class="item item02 js-432">つねならむ</div>
<div class="item item03 js-433">つねならむ</div>
</div>
//三点と同じ
// 座標
const div = [0, 50, 100];
const num = div.length;
const point = [];
let key = 1;
for (let i = 0; i < num; i++) {
for (let j = 0; j < num; j++) {
point[key] = div[j] + "% " + div[i] + "%"; //1: "0% 0%" ... 9: "100% 100%"
key++;
}
}
//座標を代入
const cp4 = (a, b, c, d) => {
return "polygon(" + point[a] + "," + point[b] + "," + point[c] + "," + point[d] + ")";
}
//座標を動かす1------------------
const tl41 = gsap.timeline({
defaults: {ease: "power0", duration: 1}
});
const init41 = () => {
gsap.set(".js-412", {clipPath: cp4(1, 1, 4, 4)}); //左端上半分
}
const motion41 = () => {
tl41.to(".js-412", {clipPath: cp4(1 ,2, 5, 4)}) //左上半分
.to(".js-412", {clipPath: cp4(2, 7, 8, 3)}) //平行四辺形
.to(".js-412", {clipPath: cp4(2, 6, 8, 4)}) //菱形
.to(".js-412", {clipPath: cp4(9, 1, 3, 7)}) //ねじれ
}
init41();
motion41();
//座標を動かす2------------------
const tl42 = gsap.timeline({
defaults: {ease: "power0", duration: 1}
});
const init42 = () => {
gsap.set(".js-422", {clipPath: cp4(7, 7, 8, 8)});
gsap.set(".js-423", {clipPath: cp4(8, 8, 9, 9)});
gsap.set(".js-424", {clipPath: cp4(4, 4, 7, 7)});
}
const motion42 = () => {
tl42.to(".js-422", {clipPath: cp4(7, 2, 3, 8)})
.to(".js-423", {clipPath: cp4(1, 8, 9, 2)})
.to(".js-424", {clipPath: cp4(4, 3, 6, 7)})
}
init42();
motion42();
//座標を動かす3------------------
const tl43 = gsap.timeline({
defaults: {ease: "power0", duration: 1}
});
const init43 = () => {
gsap.set(".js-432", {clipPath: cp4(1, 1, 4, 4)});
gsap.set(".js-433", {clipPath: cp4(6, 6, 9, 9)});
}
const motion43 = () => {
tl43.to(".js-432", {clipPath: cp4(1, 3, 6, 4)})
.to(".js-433", {clipPath: cp4(6, 4, 7, 9)})
.to(".js-432", {clipPath: cp4(1, 3, 3, 7), duration: 0.5})
.to(".js-433", {clipPath: cp4(3, 7, 7, 9), duration: 0.5},"<")
.set(".js-432", {clipPath: cp4(1, 3, 7, 7)})
.set(".js-433", {clipPath: cp4(3, 3, 7, 9)})
.to(".js-432", {clipPath: cp4(1, 2, 8, 7), duration: 0.5})
.to(".js-433", {clipPath: cp4(3, 2, 8, 9), duration: 0.5},"<")
}
init43();
motion43();
円
要素を重ねて配置して、それぞれ、clip-pathを変化させています。
九つの点を準備して、1つの点を選んで、半径を指定しています。
うゐの
うゐの
おくやま
おくやま
おくやま
おくやま
けふこえて
けふこえて
けふこえて
けふこえて
<div class="wrap">
<div class="item item01 js-511">うゐの</div>
<div class="item item02 js-512">うゐの</div>
</div>
<div class="wrap">
<div class="item item01 js-521">おくやま</div>
<div class="item item02 js-522">おくやま</div>
<div class="item item03 js-523">おくやま</div>
<div class="item item04 js-524">おくやま</div>
</div>
<div class="wrap">
<div class="item item01 js-531">けふこえて</div>
<div class="item item02 js-532">けふこえて</div>
<div class="item item03 js-533">けふこえて</div>
<div class="item item04 js-534">けふこえて</div>
</div>
//三点と同じ
// 座標
const div = [0, 50, 100];
const num = div.length;
const point = [];
let key = 1;
for (let i = 0; i < num; i++) {
for (let j = 0; j < num; j++) {
point[key] = div[j] + "% " + div[i] + "%"; //1: "0% 0%" ... 9: "100% 100%"
key++
}
}
//座標を代入
const cp2 = (a, b) => {
return "circle(" + a + " at " + point[b] + ")";
}
//座標を動かす1------------------
const tl21 = gsap.timeline({
defaults: {ease: "power0", duration: 1}
});
const init21 = () => {
gsap.set(".js-212", {clipPath: cp2("0%", 5)});
}
const motion21 = () => {
tl21.to(".js-212", {clipPath: cp2("50%", 5)})
.to(".js-212", {clipPath: cp2("50%", 4)})
}
init21();
motion21();
//座標を動かす2------------------
const tl22 = gsap.timeline({
defaults: {ease: "power0", duration: 1}
});
const init22 = () => {
gsap.set(".js-222", {clipPath: cp2("0%", 7)});
gsap.set(".js-223", {clipPath: cp2("0%", 9)});
gsap.set(".js-224", {clipPath: cp2("0%", 5)});
}
const motion22 = () => {
tl22.to(".js-222", {clipPath: cp2("100%", 7)})
.to(".js-223", {clipPath: cp2("100%", 9)})
.to(".js-224", {clipPath: cp2("50%", 5)})
}
init22();
motion22();
//座標を動かす3------------------
const tl23 = gsap.timeline({
defaults: {ease: "power0", duration: 1}
});
const init23 = () => {
gsap.set(".js-234", {clipPath: cp2("0%", 1)}); //左端
gsap.set(".js-233", {clipPath: cp2("0%", 1)}); //左端
gsap.set(".js-232", {clipPath: cp2("0%", 1)}); //左端
}
const motion23 = () => {
tl23.to(".js-234", {clipPath: cp2("40%", 1)})
.set(".js-233", {clipPath: cp2("40%", 1)})
.to(".js-233", {clipPath: cp2("40%", 5)})
.set(".js-232", {clipPath: cp2("40%", 5)})
.to(".js-232", {clipPath: cp2("40%", 9)})
}
init23();
motion23();
組合せ
要素を重ねて配置して、それぞれ、clip-pathを変化させています。
<div class="wrap50">
<div class="item50 js-511"></div>
</div>
.wrap50{
position: relative; padding: 100% 0 0;
}
.item50{
position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: #c9c9ca;
}
// 絶対値
const pathObtained = [
[32,170, 29,176, 35,172, 32,170],
//中略
[567,335, 573,249, 578,163, 577,161, 493,264, 567,335],
];
//相対化
const width = 614;
const height = 613;
const pathRelative = (arr, w, h) => {
for (let i = 0; i < arr.length; i++) {
arr[i] = arr[i].map((value, index) => {
if( value % 2 == 0){
return Math.round( value / w * 100 * 100 ) / 100;
}else{
return Math.round( value / h * 100 * 100 ) / 100;
}
});
}
return arr;
}
const pathStandard = pathRelative(pathObtained, width, height);
//座標を乱す
const getRandom = () => {
return Math.floor( Math.random() * ( 8 - 3 ) + 3 ) * [-1,1][Math.floor(Math.random() * 2)];
}
const pathRandom = (arr) => {
for (let i = 0; i < arr.length; i++) {
arr[i] = arr[i].map((value) => {
if( value % 2 == 0){
return value + getRandom();
}else{
return value + getRandom();
}
});
}
return arr;
}
//座標の代入
const cpx = (arr) => {
let val = "polygon(";
for (let i = 0; i < arr.length; i++) {
if( i % 2 == 0 && i != 0){
val += "," + arr[i] + "%";
}else{
val += arr[i] + "%";
}
}
val += ")";
return val;
}
//要素を複製
const num = pathStandard.length - 1;
const wrap = document.querySelector(".js-51");
const target = document.querySelector(".js-511");
for (let i = 0; i < num; i++){
const targetClone = target.cloneNode(true);
wrap.appendChild( targetClone );
}
//座標を動かす
const init51 = () => {
gsap.set(".js-511", {
clipPath: (index) => { return cpx(pathStandard[index]); },
opacity : "random(0.4, 1, 0.01)",
});
}
let count = 1;
const bgColorArr = ["#c9c9ca","#417abe","#35526d","#a675a5","#f18d1d"];
const motion51 = () => {
let pathNext = [].concat(pathStandard); //pathStandardを複製
if(count % 3 == 0){
//基準の座標
}else{
pathNext = pathRandom(pathNext); //座標を乱す
}
gsap.to(".js-511", {
clipPath: (index) => {
return cpx(pathNext[index]);
},
opacity : "random(0.4, 1, 0.01)",
backgroundColor: bgColorArr[count % 5],
duration: 1,
});
count ++;
}
init51();
motion51();
参考
早く知りたかった!フロアマップの座標を一括取得できる意外な方法
関連記事
GSAP ScrollTriggerを使う(HTML/JS)
この記事は役に立ちましたか?
送信中