Menu/Prof
スズキマコト
自由人
元々は楽器屋のギター兄ちゃん。
趣味でプログラミングしてるうちに
本職になってしまった人。

過去に喋っていた言語
c pascal Assembler
perl PHP Python Ruby など
javascriptなどは都度必要に応じて。
最近Mac買ったのでswift勉強してます。

体ぶっ壊して死にかけたので人生RESET中。

【swellカスタマイズ】javascript/cssだけで変な動きのあるページを作る

X
     この記事はプロモーションを含みます
contents

SWELL MotionMaster: Scroll Spy & CSS Animator

エラそうな名前のSWELL専用の野良プラグイン作ってみました。

この下の方にある記事内のソースとかCSSをコピペするのがめんどくさい人はプラグインで

まだjs圧縮とかしてないのでソースみたい人はどうぞ笑

私のBLOGの目次見てていただいた通り、スクロールに追従して見出しが反転して現在どこにいるかわかります。俗にいうスクロール・スパイって奴です。

SWELLの出力可能な目次に全て対応してます。

ついでにこの下の記事にあるCSSアニメーションも一緒に動くようにjavascript作りました。

このプラグインをインストールしていただければスクロールスパイと下で説明しているCSSアニメーションが動きます。 

使い方は記事を読んでください。

ちなみにCSSアニメーションの機能ははcocoon他のテーマでも多分動くはずなのでその目的で使っていただいてもOKです。

笑顔な助手

cocoonで動かしている様子。

インストールの仕方

一般的なプラグインのアップロード方式のインストールで可能です。

プラグインのページにプラグインのアップロードがありますので上でダウンロードしたzipファイルをそのままアップロードするだけです。

ファイルを選択でローカルにダウンロードしてあるswell-motionmaster.zipを選択して今すぐインストールして

プラグインを有効化すれば終わりです。

注意:

外観→カスタマイズ→投稿・固定ページ→目次 の中の設定で どの階層の見出しまで抽出するか を h5にしてください。

スクロールスパイの目次の反転表示の色を変えたい人

設定画面は無いので

プラグイン→プラグインファイルエディターを選択していただいて(警告でますが無視してOK)

右上にある編集するプラグインを選択から

SWELL MotionMaster: Scroll Spy & CSS Animator を選択してからassetsの中にある mlabo.cssの最初の行に反転用のCSSがあるのでそこを直接修正してください。

  • color:反転時の文字色(デフォルト黒文字)
  • background-color:反転時のバックグラウンドカラー(デフォルト薄いオレンジ)
  • font-weight: 文字の太さ(normal,boldなど)(デフォルト太字)

以下の記事は上記プラグインを使わずに自分で直接実装したい人用の記事になりますが

実際のエフェクト効果のサンプルにもなってますので適当に上下スクロールして効果を確認してみてください。

このBLOGは諸々実験する目的で稼働しているのでこのプラグインをインストールしてません笑

以下を参考に直接記述していただいてもこのプラグインをインストールしていただいても直接記述していただいてもどちらも同じ動作するのがわかります。

javascriptとcssだけで動きます jQueryは使いません。

以前にこのBLOGにご来訪いただいている場合ブラウザのキャッシュで

エフェクトがうまく発動しない可能性あります。

その場合はブラウザキャッシュを削除してみてください。

完全に面白半分なんですがjavascriptとcssだけで記述しているので jQueryは使ってません

前後左右&ふわっと出現効果で対象動くのですがあんまりやるとくどいっす。

この記事は実験のためやたらエフェクトかかってますw いらつきながらどうぞ笑

普通のスクロールでCSSが発火して逆スクロールして再度スクロールすると再発火可能。

スクロールを動かしたり戻したりしてみてください

やろうと思えばどの部分にもCSSで手軽に装飾できるのが楽しいSWELL

javascriptとcssだけで動きのあるページを作ります
swell 追加cssクラスを活用します
びっくりな助手

このページは面白がって色々やってますが

管理人

実際のページはこういうのやりすぎるとくどい。

笑顔な助手

一応上下左右に

笑顔な助手

動きます

エフェクトが効く部分はゆっくりとスクロールするとエフェクトが見えませんので

その場合はスクロールバックすると再度エフェクトの確認ができます。

ほぼ全てのブロックと単独行に自在に適用可能

javascriptとcssだけで動きのあるページを作ります
swell 追加cssクラスを活用します
javascriptとcssだけで動きのあるページを作ります
swell 追加cssクラスを活用します
javascriptとcssだけで動きのあるページを作ります
swell 追加cssクラスを活用します

ここは段落ブロックです。文章をここに入力してください。

  • リスト
  • リスト
  • リスト

なんでもできるぜ

preタグでコード表示の部分

@font-face {
font-family: 'icomoon';
src:url('/wp-content/themes/swell/assets/fonts/icomoon.ttf?7ojy2d') format('embedded-truetype'),
url('/wp-content/themes/swell/assets/fonts/icomoon.ttf') format('truetype'),
url('/wp-content/themes/swell/assets/fonts/icomoon.woff') format('woff'),
url('/wp-content/themes/swell/assets/fonts/icomoon.svg') format('svg');
font-weight: normal;
font-style: normal;
font-display: swap;
}

画像ギャラリーの一枚一枚にも個別で

つくりは簡単です。

動きをつけたいブロックでもしくはPブロック単位で「高度な設定」> 追加CSSクラスを使用してます。

こんな感じ

javascriptとcssだけで動きのあるページを作ります
swell 追加cssクラスを活用します

必ず初期化クラスの slideview とセットで宣言してください。

スクロールできます
slideview初期化 class定義 (必ず宣言)
UU-MOVE,tsU上から下に
DD-MOVE,tsD下から上に
LL-MOVE,tsL左から右に
RR-MOVE,tsR右から左に
FF-MOVE360度クルリと回転する
MFADE,ofadeスライドせずにふわっと出現する
borderボーダーアニメーション。指定場所の中心から左右に伸びるラインを引く
borderl同上。指定場所の左端から伸びるラインを引く
INBKborder*のライン幅を文字列と同等にするならこれを一緒に宣言(display: inline-block;)
FLAT-MOVE中心から下に向かって回転
FLAT-TOP-MOVE中心から上に向かって回転

tsU,tsD,tsL,tsR,ofadeについて

これは何かと言いますと具体的にはスクロールに追従せずに即効果を出したいシーンで使います。

私のTOPページをみていただくとわかります。

このページ先頭付近にあるTAB付きのメニュー(New computer blog life)の各TABをクリックしたら意味がわかると思います。 ここではtsD,tsL,tsR,ofadeを各TABの追加cssクラスに宣言しています。

これが border の動き方

これが borderl の動き方。

slideview と **-MOVEまたは border* の各classを組み合わせて宣言します。

宣言する順番はどちらが先でも構いません。必ずセットで宣言を。

**-MOVE と border は 併用可能。

こんなことも可能(INBK FF-MOVE border slideview)

**-MOVEは複数記述しても1番最後のみ有効

使用するCSS

外観>テーマファイルエディターでも カスタマイズ>追加CSSでも好きな方にコピペしてください。

/*スクロールスパイで利用*/
a.p-toc__link.active, a.p-toc__link:hover {
color:white;
background-color:black;
font-weight:bold;
}

/* MOVE FADE */
.slideview {
  opacity: 0;
}

.slideview.on {
  opacity: 1;
}

.LL-MOVE.on {
  animation: slideInL forwards 2s;
}
.RR-MOVE.on {
  animation: slideInR forwards 2s;
}

.UU-MOVE.on {
  animation: slideInU forwards 2s;
}

.DD-MOVE.on {
  animation: slideInD forwards 2s;
}

.MFADE.on {
  animation: fade forwards 4s;
}

.ofade {
  animation: fade forwards 1s;
}



.FLAT-MOVE {
transform-origin: center bottom;
transform: rotateX(-90deg);
}

.FLAT-MOVE.on {
transition: all 1s ease-in-out;
transform: rotateX(0deg);
}

.FLAT-TOP-MOVE {
 transform-origin: center top;
 transform: rotateX(-90deg);
}

.FLAT-TOP-MOVE.on {
  transition: all 3s ease-in-out;
  transform: rotateX(0deg);
}

.FF-MOVE.on {
  transition: all 1s ease-in-out;
  transform: rotate(360deg);
}


@keyframes fade {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

.tsL {
  animation: slideInL forwards 0.5s;
}

@keyframes slideInL {
  0% {
    opacity: 0;
    transform: translateX(-140px);
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}

.tsR {
  animation: slideInR forwards 0.5s;
}

.tsRR {
  animation: slideInR forwards 2s;
}

@keyframes slideInR {
  0% {
    opacity: 0;
    transform: translateX(140px);
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}

.tsU {
  animation: slideInU forwards 0.5s;
}

@keyframes slideInU {
  0% {
    opacity: 0;
    transform: translateY(-140px);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.tsD {
  animation: slideInD forwards 0.5s;
}

@keyframes slideInD {
  0% {
    opacity: 0;
    transform: translateY(140px);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.INBK {
  display: inline-block;
}

.border {
  position: relative;
}

.borderl {
  position: relative;
}

.borderl.on {
  /* 追加のスタイルプロパティ */
}

.borderl.on:before {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  border-bottom: solid 2px #0f6aaa;
  animation: border_anim 2s linear forwards;
}

.border.on:before {
  opacity: 1;
  content: '';
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 0;
  border-bottom: solid 2px #0f6aaa;
  transform: translateX(-50%);
  animation: border_anim 2s linear forwards;
}

@keyframes border_anim {
  0% {
    width: 0%;
  }
  100% {
    width: 100%;
  }
}

CSSアニメーション仕様書

一般的な説明

このCSSコードは、ウェブページ上のさまざまな要素に対する多様なアニメーションと遷移を提供することを目的として設計されています。これらのアニメーションには、異なる方向からのスライドイン(左、右、上、下)、フェードイン、回転、およびボーダーアニメーションが含まれます。

アニメーションの詳細

スライドインアニメーション

  • 左からのスライドイン(.LL-MOVE.on, .tsL
  • 右からのスライドイン(.RR-MOVE.on, .tsR, .tsRR
  • 上からのスライドイン(.UU-MOVE.on, .tsU
  • 下からのスライドイン(.DD-MOVE.on, .tsD

フェードインアニメーション

  • フェードイン(.MFADE.on, .ofade, @keyframes fade

回転アニメーション

  • 360度回転(.FF-MOVE.on

ボーダーアニメーション

  • ボーダーアニメーション(.border.on:before, .borderl.on:before, @keyframes border_anim

その他のアニメーション

  • 中心から下に向かって回転(.FLAT-MOVE, .FLAT-MOVE.on
  • 中心から上に向かって回転(.FLAT-TOP-MOVE, .FLAT-TOP-MOVE.on

以上がこのCSSコードの主な機能となります。

使用するjavascript

カスタマイズ>高度な設定>bodyタグ終了直前に出力するコード にそのまま貼り付けてください。

javascriptとcssだけで動きのあるページを作ります
swell 追加cssクラスを活用します

SWELLのjavascript記述はページごとに読み込ませる方法と

カスタマイズ>高度な設定で全体的に読み込ませる

方法と2種類あります。

個別にjsファイルを作っておいてそれを読み込ませたい方はこちら↓

カスタマイズ>高度な設定で全体的に読み込ませる場合は

以下のソースをそのままコピペでOKですが

ページ毎に読み込ませる(ページ下部のJS記入する部分)場合の注意

ページごとの記載はデフォルトは 先頭と最下部のscriptタグが自動で付加されますので

それを削ったものをコピペしてください。

めんどくさい方はそのままコピペしても良いのですが

その際は必ずその下部にあるチェックマークをお忘れなく

このCSSとjavascriptのBLOGへの実装方法の考え方

笑顔な助手

cssの場合は

スクロールできます
外観>テーマファイルエディター恒久的に使うならこっちに記載
またはカスタマイズ>追加CSS恒久的に使うならこっち記載その2
個別ページの下部のCSS記載欄一時的にテストもしくはそのページだけしか使わないならこっち
笑顔な助手

javascriptの場合は

スクロールできます
カスタマイズ>高度な設定恒久的に使うならこっち記載
個別ページの下部のJS記載欄一時的にテストもしくはそのページだけしか使わないならこっち

いずれにコピペしても正常に動作することを確認してます。

現在プラグイン化されたものと同じソースです。座標抽出を共通化してスクロールスパイとエフェクトを同時に制御するようにいたしました。

<script>
//scrool spy and .slideview use
document.addEventListener('DOMContentLoaded', function() {
    const sview = document.querySelectorAll('.slideview, .swl-format-1, .swl-format-2');
    const sections = Array.from(document.querySelectorAll('h2, h3, h4, h5'));
    let adj = window.innerHeight * 0.1;
    let rafId = null;
    let lastScrollTop = 0;

    function getTopPositions(elements) {
        return Array.from(elements, el => el.getBoundingClientRect().top + window.pageYOffset);
    }

    let svTop = getTopPositions(sview);
    let sectionsTop = getTopPositions(sections);

    function updateAdjAndSvAndSectionsTop() {
        adj = window.innerHeight * 0.1;
        svTop = getTopPositions(sview);
        sectionsTop = getTopPositions(sections);
    }

    window.addEventListener('resize', updateAdjAndSvAndSectionsTop);

    function toggleActiveClass(links, isActive) {
        links.forEach(link => {
            if (isActive) {
                link.classList.add('active');
            } else {
                link.classList.remove('active');
            }
        });
    }

    function handleScroll() {
        if (rafId) {
            return;
        }

        rafId = requestAnimationFrame(() => {
            const scrollPos = document.documentElement.scrollTop || document.body.scrollTop;

            if (Math.abs(scrollPos - lastScrollTop) < 1) {
                rafId = null;
                return;
            }

            lastScrollTop = scrollPos;

            sections.forEach((section, i) => {
                const navLinks = document.querySelectorAll(`a[href="#${section.id}"].p-toc__link`);
                const isActive = scrollPos + window.innerHeight - adj >= sectionsTop[i] && (i === sections.length - 1 || scrollPos + window.innerHeight - adj < sectionsTop[i + 1]);
                toggleActiveClass(navLinks, isActive);
            });

            sview.forEach((el, i) => {
                if (scrollPos + window.innerHeight - adj > svTop[i]) {
                    el.classList.add('on');
                } else {
                    el.classList.remove('on');
                }
            });

            rafId = null;
        });
    }

    window.addEventListener('scroll', handleScroll);

    updateAdjAndSvAndSectionsTop();

    const observer = new MutationObserver((mutationsList) => {
        for (let mutation of mutationsList) {
            if (mutation.type === 'childList') {
                handleScroll();
            }
        }
    });

    const tocElements = document.querySelectorAll('.toc');
    tocElements.forEach(toc => observer.observe(toc, { childList: true, subtree: true }));
});
</script>

仕様書

概要

このコードは、ウェブページにスクロールスパイとスライドビューの機能を追加します。ユーザーがページをスクロールすると、特定のセクションや要素が表示される際に対応するナビゲーションリンクがアクティブになり、スライドビュー要素が表示されるようにします。

主な機能

  1. ウィンドウサイズの変更: ウィンドウサイズが変更されると、要素の位置情報を更新します。
  2. セクションのアクティブ切り替え: ページをスクロールする際に特定のセクションが表示されるようになると、関連するナビゲーションリンクにアクティブクラスを追加・削除します。
  3. スライドビュー要素の表示: 特定の位置までスクロールすると、スライドビュー要素に on クラスを追加して表示します。
  4. MutationObserverの使用: ページ内の特定の要素(.toc)の変化を監視し、変更があるたびにスクロール処理を実行します。

主な変数と関数

  • 変数
    • sview: スライドビュー要素を格納するコレクションです。
    • sections: 対象の見出し要素(h2, h3, h4, h5)の配列です。
    • adj: 要素の表示位置を調整するための値です。
    • rafId: requestAnimationFrameのIDです。
  • 関数
    • getTopPositions: 要素の上端の位置を取得します。
    • updateAdjAndSvAndSectionsTop: ウィンドウサイズの変更時に変数を更新します。
    • toggleActiveClass: ナビゲーションリンクのアクティブ状態を切り替えます。
    • handleScroll: スクロールイベントハンドラーで、スクロール位置に基づいて上記の機能を実行します。

使い方

このコードを対象とするHTMLページに追加するだけで、上記の機能が実現できます。必要なクラス名とIDを適切に設定してください。

動作の意味としては目的の領域に画面が達したらadj分オフセットした位置にからエフェクト発動

指定のclassにonまたはactive を追加してそのエフェクト仕込んだclassを発動させる的な動作してます。

教科書に載っているようなclassに名称追加して新しいclassを参照できるようにしようってやつです。

領域から外れると(バックスクロールなど)on/activeを削除するのでまた元classで初期化されて

再度領域に達すると同じように繰り返しエフェクトが可能。

意味わからなくてもコピペして使えると思います。

このjavascriptとcssの定義を応用すればスクロールアクションに対する任意のCSS発火が

色々とできると思います。

SWELLのブロックエディターに応用する方法

SWELLのエディター設定にカスタム書式ってあるの知ってますか?

1番上ででダウンロードした野良プラグインをインストールした状態で

以下の設定をしておくとSWELLブロックエディター上で

文字の一部部分に下線のアニメーションを追加でます。←こんな感じに

この画面からもう少し下までスクロールするとこんな画面で設定できます。

内容は以下のように。

.swl-format-1{
display: inline-block;
font-weight:bold;
}

.swl-format-2{
 display: inline-block;
 position: relative;
font-weight:bold;
}

.swl-format-2.on:before {
  opacity: 1;
  content: '';
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 0;
  border-bottom: solid 2px #0f6aaa;
  transform: translateX(-50%);
  animation: underline_anim 2s forwards;
}

@keyframes underline_anim {
  0% {
    width: 0;
  }
  100% {
    width: 100%;
  }
}

使い方はブロックエディタのツールバーのSWELLアイコンの中に追加されたコマンドがあるので

アニメーションを適用させたい部分をマウスの左クリックで範囲指定して「下動ライン」を選択するだけです。

シェアしてくれると喜びます
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

makotoのアバター makoto Blogger&YouTuber

サーバー管理者として17年ほど仕事でサーバー触ってました。
www,mail,dns,sql各鯖をすべてFreeBSDで運用してましたが現世ではかなりレアなタイプになるみたいですね笑

viやシェルスクリプトとかperlとかgccとかFreeBSDとか実はbashよりtcshが好きとか時々寝ぼけるのは
その名残でしょう。

今まで縁の下の力持ち的な他人のためにプログラムを書き他人のためにサーバー構築し他人のためにWEBサイトを創る的な世界から
自分の好きなことに集中できる環境は実に気持ち良いですね。
現役は引退済みなので難しいことはやりませんしやれません。

現在 ほぼ自由人。

contents