見出し画像

背景画像をフェード切り替えする

貸し本棚で背景画像の設定ができるようになりました。

がっつり背景画像をタイリングするものではなく、控えめにcoverするスタイルですが、ポータルだけでなく、本棚、小説、エピソードそれぞれに決まった枚数まで背景画像を設定することができます。小説やエピソードの背景を設定して、文字打ちすることで、ビジュアルノベルのような雰囲気を楽しむこともできます。

この記事は以下のことに役立つかもしれません。

  • すでに表示されている画像を別の画像にフェードアウト→フェードインして切り替える方法

  • 画像を必要に応じてプリロードする方法

  • スマホの背景画像を固定する方法

背景画像のフェード切り替え

背景画像を複数枚設定すると、一定時間で切り替えます。このとき、現在表示している画像がフェードアウトして、新たに表示される画像がフェードインするのが理想的です。
これを実現するためには、単一の背景とtransitionだけでは(多分)できません。

2枚の背景を切り替える

単一の背景でフェードインフェードアウトができないのであれば、2枚用意して、1枚をフェードアウト、もう1枚をフェードインしてあげれば実現できます。

<template>
    <div id="main-container">
        <div id="primary-background" class="background"></div>
        <div id="secondary-background" class="background"></div>
        <main>
            <router-view v-slot="{ Component }">
                <transition mode="out-in">
                    <component :is="Component" />
                </transition>
            </router-view>
        </main>
    </div>
</template>

上記のようなページ構成にし(端折ってあります)、#primary-backgroundと#secondary-backgroundの2枚の背景を用意します。
この背景のスタイルは以下のとおりです。

.background {
    content: "";
    pointer-events: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center;
    opacity: 0;
    background-image: none;
    transition: opacity 5s ease-in-out;
}

スマホではbackground-attachment: fixedが効かないので、position: fixedで対応します。
背景を素早く切り替えると、その動きが気になってしまい、読書や執筆の意識を妨げてしまいます。切り替えには5秒ほどかけて「知らない間に切り替わっていた」ぐらいの感覚にしておきます。

背景の切り替えは、背景が設定される場所、本棚↔小説↔本文での行き来があったとき、さらに本文の遷移において発生します。この切り替え判定処理は複雑なので割愛します。
この背景を切り替える必要が発生したとき、以下の切り替え処理を実行します。

showBackground() {
    if (this.backgrounds && this.backgrounds.length > 0) {
        if (this.backgrounds.length <= this.bgIndex) {
            this.bgIndex = 0;
        }
        const url = this.backgrounds[this.bgIndex++].url;
        const img = new Image();
        img.onload = () => {
            const currPane = this.pane;
            this.pane = (this.pane === "primary") ? "secondary": "primary";
            $("#" + this.pane + "-background").css({
                "background-image": "url(" +img.src+ ")",
                "opacity": 0.15
            });
            $("#" + currPane + "-background").css({
                "opacity": 0
            });
        };
        img.src = url;
    } else if (this.bgIndex > 0) {
        $("#" + this.pane + "-background").css({
            "opacity": 0,
        });
        this.bgIndex = 0;
    }
}

this.backgroundsに背景リストが入っています。この中身は表示している場所によって変わるので、インデックスを剰余で計算することはできません。厳密さが失われますが、インデックスが超過したら0に戻すという冗長な処理を行います。

画像をプリロードする

Imageオブジェクトを作成し、onloadイベントに切り替え処理を記述します。
直接背景URLを書き換えてしまうと、画像の読み込みが完了する前に切り替えがスタートし、映像にちらつきが発生します。そのため、Imageオブジェクトが読み込みを完了した時点で切り替えを開始します。
最後にImageオブジェクトに画像のURLを設定すれば、切り替えがスタートします。
切り替え処理では、フェードインする画像のURLを設定し(事前読み込み済み)、opacityを0.15に設定しています。一方、フェードアウトする画像はURLをそのままにしてopacityだけを0に設定します。URLを消してしまうとtransitionとは無関係に画像が突然消滅し、きれいなフェードアウトになりません。
画像リストが無く(this.backgrounds.length === 0)かつ背景を表示中(this.bgIndex > 0)のときは、表示中の背景をフェードアウトさせるだけです。

まとめ

実際に使っていただけるとわかりますが、5秒のフェードではいつ背景が切り替わったかほぼ認識できないため、執筆や読書の妨げになることはないと思います。
また、この切り替え処理であれば、切り替え中に更に切り替えが発生しても問題が生じることはありません。

たかが背景ですが、一枚設定するだけでも気分転換になり、執筆や読書が楽しくなります。本文の途中に挿絵を挟むよりも淡い背景に溶け込むほうが効果的にみえるかもしれません。


この記事が気に入ったらサポートをしてみませんか?