WordPressブロックテーマで紅葉が舞う演出を実装します
*(注意)ウェブページの読み込み時間は遅くなってしまいます
はじめに
「ブロックテーマ」で利用可能な「フルサイト編集機能」は、ウェブサイトのヘッダーやフッター、サイドバーなど、従来のテーマでは制限されていた部分にも簡単に手を加えることができます
この機能により、管理画面のエディターを使用して、これらのエリアを直感的にカスタマイズできます
HTMLブロックは、ウェブページ上の任意の場所にコードを追加することができるので、今回は通常ほとんどのテンプレートで使用される「ヘッダーテンプレートパーツ」にコードを追加しました
ちなみに、この紅葉のビジュアルはSVGのパスを利用しています。このコード内のパスの部分を変更することで、季節やテーマに合わせた様々な形状、例えば桜の花びらなどに応用することが可能です
また、ユーザーがコンテンツに集中できるように、ページをスクロールすると紅葉の舞いが消え、ページの一番上まで戻ると再び表示されるように実装しました
実装の手順
- WordPressのダッシュボードにログイン
- 左側のサイドバーから「外観」⇨「エディター」を選択
- 「ヘッダーテンプレートパーツ」の一番下に「HTMLブロック」を追加します
コードをコピーしてHTMLブロックに貼り付けて下さい
コーピー用のコード
<div id="leaves"></div>
<div class="target-class"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.8.0/p5.min.js"></script>
<script defer>
const target = document.querySelector('.target-class');
const callback = function(entries, observer) {
entries.forEach(entry => {
if (!entry.isIntersecting) {
document.body.classList.add('hidden-class');
} else {
document.body.classList.remove('hidden-class');
}
});
};
const observer = new IntersectionObserver(callback);
observer.observe(target);
const svgPath=`d="
M 29.06 32.88
L 31.03 30.96
L 33.13 26.74
L 33.35 26.23
L 33.59 25.87
L 33.97 25.64
L 37.15 23.55
L 40.18 21.38
L 40.74 21.20
L 41.24 21.25
L 43.03 21.73
L 43.60 21.73
L 49.95 19.89
L 50.94 20.60
L 50.92 20.79
L 50.31 22.97
L 49.41 26.68
L 49.64 29.13
L 49.74 29.57
L 49.65 30.06
L 48.78 31.89
L 45.30 36.07
L 43.29 38.17
L 40.51 39.84
L 38.91 40.17
L 33.80 41.45
L 31.11 43.08
L 30.96 43.39
L 31.29 43.34
L 35.61 41.99
L 38.90 42.09
L 39.67 42.34
L 40.02 42.46
L 43.07 42.22
L 45.90 42.02
L 47.84 43.77
L 48.63 44.17
L 52.93 43.83
L 53.58 44.09
L 53.76 44.77
L 53.68 44.99
L 49.62 50.39
L 44.66 53.58
L 40.07 54.48
L 39.65 54.63
L 39.50 55.07
L 39.58 55.72
L 39.78 56.20
L 39.86 56.60
L 39.55 56.88
L 39.20 57.00
L 37.76 56.96
L 31.61 55.25
L 23.82 52.95
L 17.99 52.33
L 16.88 52.75
L 16.21 53.72
L 15.05 57.48
L 14.48 58.19
L 13.58 58.31
L 13.21 58.22
L 12.47 57.73
L 12.62 56.86
L 18.96 47.78
L 26.68 40.45
L 26.82 40.23
L 26.77 40.09
L 26.76 40.08
L 26.61 39.97
L 26.42 40.02
L 17.65 47.11
L 15.66 49.12
L 15.60 49.16
L 15.41 48.99
L 15.84 43.73
L 15.05 39.35
L 14.28 36.21
L 14.18 33.45
L 14.68 31.05
L 15.92 28.96
L 16.30 28.71
L 16.77 28.74
L 17.46 28.98
L 17.97 28.99
L 18.25 28.57
L 18.56 26.86
L 18.98 24.85
L 20.23 22.26
L 22.03 19.61
L 22.39 19.29
L 22.84 19.15
L 24.73 18.47
L 27.15 16.77
L 29.89 14.87
L 29.96 14.84
L 30.84 14.84
L 31.44 15.48
L 32.23 20.50
L 31.15 25.02
L 31.15 26.09
L 31.03 28.94
L 28.98 32.77
L 28.92 32.91
L 29.06 32.88
Z"`
const drawSVGPath = (p5, pathData) => {
const commands = pathData.match(/[a-df-zA-DF-Z][\d.,\s-]*/g);
p5.beginShape();
for (let command of commands) {
const [cmd, ...params] = command.split(/[ ,]/).filter(Boolean);
const args = params.map(Number);
if (cmd === "M") {
p5.vertex(...args);
}
else if (cmd === "C") {
p5.bezierVertex(args[0], args[1], args[2], args[3], args[4], args[5]);
}
else if (cmd === "Q") {
const [x1, y1, x2, y2] = args;
const cp1x = x1 + (1 / 3) * (x2 - x1);
const cp1y = y1 + (1 / 3) * (y2 - y1);
const cp2x = x1 + (2 / 3) * (x2 - x1);
const cp2y = y1 + (2 / 3) * (y2 - y1);
p5.bezierVertex(cp1x, cp1y, cp2x, cp2y, x2, y2);
}
else if (cmd === "L") {
p5.vertex(...args);
}
else if (cmd === "Z" || cmd === "z") {
p5.endShape(p5.CLOSE);
}
}
}
const leaves = (p) => {
let petals = [];
const NUM = p.windowWidth > 600 ? 80 : 30;
class Leaves {
constructor() {
this.hue = p.random(10, 50);
this.alpha = p.random(0.6, 0.9);
this.size = 50;
this.xRadius = p.random(10, 20);
this.base = p.random(p.width);
this.vPos = p.createVector(this.base, p.random(p.height));
this.vAngle = p.createVector(p.random(360), p.random(360));
this.vVelocity = p.createVector(1, 4);
this.scale = p.random(0.4, 0.8);
}
move() {
this.vAngle.add(this.vVelocity);
this.vPos.x = this.base + this.xRadius * p.cos(p.radians(this.vAngle.y));
this.vPos.y += this.vVelocity.y;
if (this.vPos.y > p.height + this.size) {
this.vPos.y = -this.size;
}
}
display() {
p.fill(this.hue, 100, 95, this.alpha);
p.push();
p.translate(this.vPos.x, this.vPos.y);
p.rotate(p.radians(this.vAngle.x));
p.scale(this.scale);
drawSVGPath(p, svgPath);
p.pop();
}
}
p.setup = () => {
p.createCanvas(p.windowWidth, p.windowHeight).parent('leaves')
p.frameRate(30);
p.colorMode(p.HSB);
p.noStroke();
for (let i = 0; i < NUM; i++) {
petals.push(new Leaves());
}
};
p.draw = () => {
p.clear();
petals.forEach((petal) => {
petal.display();
petal.move();
});
};
p.windowResized = () => {
p.resizeCanvas(p.windowWidth, p.windowHeight);
petals = [];
for (let i = 0; i < NUM; i++) {
petals.push(new Leaves());
}
};
};
if (!document.body.classList.contains('hidden-class')) {
new p5(leaves);
}
</script>
<style>
body.hidden-class #leaves {
display: none;
}
#leaves {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
z-index:1000;
pointer-events: none;
}
</style>
コードとカスタマイズについて
このコードは、p5.jsライブラリを利用して、動的なエフェクトを実現しています
ポイントになるようなコードについてコメントを追加しているので、カスタマイズの参考にして下さい
*注意:コードは省略しているのでこちらのコピペは利用できません
<!-- 紅葉が表示される領域 -->
<div id="leaves"></div>
<!-- スクロールに反応して紅葉を制御するための要素 -->
<div class="target-class"></div>
<!-- p5.jsライブラリの読み込み -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.8.0/p5.min.js"></script>
<script>
// .target-classがビューポート内にあるかどうかを監視するための設定
const target = document.querySelector('.target-class');
const callback = function(entries, observer) {
entries.forEach(entry => {
if (!entry.isIntersecting) {
// .target-classがビューポート外にある時にbodyタグにhidden-classを追加
document.body.classList.add('hidden-class');
} else {
// .target-classがビューポート内にある時にhidden-classを削除
document.body.classList.remove('hidden-class');
}
});
};
const observer = new IntersectionObserver(callback);
observer.observe(target);
// svgPathの定義(図形・紅葉の形) *パスの部分を変更はここで
const svgPath = `省略...`;
// SVGパスを描画する関数
const drawSVGPath = (p5, pathData) => {
// 省略...
}
// 図形(紅葉)の描画とアニメーションの設定 *別途
const leaves = (p) => {
// 省略...
};
// bodyタグにhidden-classクラスがない場合に紅葉アニメーションを起動
if (!document.body.classList.contains('hidden-class')) {
new p5(leaves);
}
</script>
<!-- 紅葉のスタイル設定 -->
<style>
/* hidden-classがbodyタグにある時は紅葉を非表示にする */
body.hidden-class #leaves {
display: none;
}
/* 紅葉の表示領域のスタイル設定 */
#leaves {
position: fixed;
top: 0;
left: 0;
height: 100vh; /* 画面の高さいっぱい */
width: 100vw; /* 画面の横幅いっぱい */
z-index: 1000;
pointer-events: none;
}
</style>
図形(紅葉)の描画とアニメーションの設定
カスタマイズの参考にconst leaves = (p) => {// 省略…};
const leaves = (p) => {
let petals = [];
// 紅葉の数(ウィンドウの幅600pxより大きい場合80個、小さい場合30個)
const NUM = p.windowWidth > 600 ? 80 : 30;
class Leaves {
constructor() {
// 紅葉の色の設定(色相0から360の範囲、透明度0から1の範囲)
this.hue = p.random(10, 50); // 色相の範囲(紅葉の色)
this.alpha = p.random(0.6, 0.9); // 透明度(明るさ)
// 紅葉の動きの設定
this.size = 50; //表示位置の調整用
this.xRadius = p.random(10, 20); // 水平方向の動きの範囲
this.base = p.random(p.width);
// 紅葉の位置と角度の初期化
this.vPos = p.createVector(this.base, p.random(p.height));
this.vAngle = p.createVector(p.random(360), p.random(360));
this.vVelocity = p.createVector(1, 4); // 移動速度(水平、垂直)
// 紅葉のスケール(サイズの変化)
this.scale = p.random(0.4, 0.8);
}
// 紅葉の移動処理
move() {// 省略...}
// 紅葉の描画処理
display() {// 省略...}
}
// p5.jsのセットアップ(初期化)
p.setup = () => { // 省略... };
// 描画処理
p.draw = () => {// 省略...};
// ウィンドウサイズ変更時の処理
p.windowResized = () => {// 省略...};
パスの部分を変更する場合についてconst svgPath = `省略...;`
SVGパスデータを取り込んで、p5.jsを使用してウェブページ上に描画します
使用している関数は M 、L、C、Q、Zなどのコマンドで構成されていますが、全てに対応しているわけではないので、できるだけシンプルなパスを使用して下さい
//桜の花びらの例
//サイズや色を変更すれば使えると思います
const svgPath = `d="
M 42.24 28.02
L 42.55 27.97
L 42.71 27.91
L 42.82 27.78
L 50.74 14.15
L 51.35 13.70
L 52.10 13.84
L 52.10 13.84
L 52.15 13.87
L 56.41 17.85
L 60.01 22.61
L 63.06 28.15
L 65.64 34.75
L 67.55 41.93
L 68.76 49.77
L 69.15 57.57
L 68.73 64.75
L 67.77 69.89
L 66.15 74.99
L 60.92 85.59
L 53.04 96.49
L 43.31 106.54
L 42.46 106.87
L 41.60 106.55
L 33.27 98.28
L 26.30 89.46
L 21.09 80.60
L 17.61 71.72
L 16.06 64.21
L 15.59 56.09
L 16.17 47.66
L 17.81 39.26
L 20.29 31.65
L 23.69 24.60
L 27.73 18.70
L 32.57 13.75
L 32.64 13.70
L 33.40 13.55
L 34.03 14.01
L 42.05 27.93
L 42.15 28.02
L 42.24 28.02
Z"`