阿部寛のサイトみたいなflameライクなデザインを簡単なJavaScriptとCSSで実装

我がサイトを阿部寛氏の公式ホームページみたいなflameライクな作りにしたい。ぬるぬるサクサク、キビキビシュッシュと動くあの感じ。

第一候補としては現代風にSPAを自前で作って見た目をあの感じにするということなのですが、すでにやっておられる方がいました。しかし実際に長く使うのはちょっとまた別の話という印象を受けます。

なので、これをもっと素朴に長く続けられるような形で作れないかなと考えています。

flamesetをそのまま使う方法も考えましたが、HTML5では非推奨な上に自分でもちょっと使いにくいと感じているものをわざわざ採用するのも本末転倒な気がするので、却下。

最終的にごくごく簡素な静的サイトにちょっとだけJavaScriptの力を借りて実現させることにしました。サイトジェネレ―ターはHugoを使っていますが、理由はただ単に速いからというだけです。Hugoじゃないとできないことはやっていません(むしろHugoでしかできないことなんてあるのでしょうか?)。

絶対に欲しい機能

  1. 左カラム右カラムを分けるバー。あれでサイズをうにょうにょと変える。
  2. 変えたサイズは保存され、次のページへ遷移しても維持される。
  3. レスポンシブに対応

そう、たったこれだけ。あとは特になにもしなくても爆速になるでしょう。

静的サイトにして、常識的な範囲でまともなサーバーを借りれば、あとは余計なJavaScriptや無駄に巨大な画像を大量に読み込まないようにしておくだけで庶民サイトにおけるスピード問題は十中八九解決すると信じています。

しかし、このたった3つの実現がなかなか茨の道でした。

1. 左カラムと右カラムを分けるバー。サイズをうにょうにょ変える。

縦方向(Y方向)は無視します。使いません。横だけ。

最低限のHTML

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>flameset的なサイトのレイアウト</title>
</head>
<body>
    <!--左カラム-->
    <div id="wrapper">
        <!--右カラム-->
        <div id="side">
            <!--サイズを変えるためのバー-->
            <div id="splitbar"></div>
        </div>
    </div>
</body>
</html>

最低限のCSS

#wrapper {
    width: 70%;
    height: 100vh;
    overflow: auto;
}
#side {
    position: fixed;
    top: 0;
    right: 0;
    width: 30%;
    height: 100vh;
    overflow: auto;
}
#splitbar {
    position: absolute;
    top: 0;
    left: 0;
    width: 10px;
    height: 100%;
    user-select: none;
}

簡単にレスポンシブに対応するために、右カラム(side)はwrapperの中にいてもらいます。

splitbarをクリックしたらフラグが立ってマウスを動かすとwrapperとsideのサイズが変わるようにJavaScriptを書きます。

splitbarはあくまでもsideの中の一部としておくと計算が楽になると思います。

最低限のJavaScript

document.addEventListener("DOMContentLoaded", function() {
    const wrapper = document.getElementById("wrapper");
    const side = document.getElementById("side");
    const splitbar = document.getElementById("splitbar");
    const bodyWidth = document.body.clientWidth;
    let flg = false;

    // バーをクリックしたらフラグをオン
    splitbar.onclick = function() {
        flg = true;
    }

    // マウスを動かしたら左右のカラムサイズを変える
    window.onmousemove = function(e) {
        if (flg) {
            wrapper.style.width = e.pageX + "px";
            side.style.width = (bodyWidth - e.pageX) + "px";
        }
    }
}

ここまででとりあえず「うにょうにょ」までは出来ました。しかし、このままではページ遷移したときにレイアウトがリセットされてしまいますので、sessionStorageを使って状態を保存します。

2. 変えたサイズは保存され、次のページへ遷移しても維持される。

widthの値をsessionStorageに保存するJavaScript

document.addEventListener("DOMContentLoaded", function() {
    const wrapper = document.getElementById("wrapper");
    const side = document.getElementById("side");
    const splitbar = document.getElementById("splitbar");
    const bodyWidth = document.body.clientWidth;
    let flg = false;

    // バーをクリックしたらフラグをオン
    splitbar.onclick = function() {
        flg = true;
    }

    // マウスを動かしたら左右のカラムサイズを変える
    window.onmousemove = function(e) {
        if (flg) {
            wrapper.style.width = e.pageX + "px";
            side.style.width = (bodyWidth - e.pageX) + "px";
            
            // ※ここから下が追加分

            // マウスを離したらフラグをfalseにしてstorageに登録
            window.onmouseup = function(e) {
                flg = false;
                sessionStorage.setItem('key', wrapper.style.width + ':' + side.style.width)
            }
        }
    }
}

wrapperとsideのサイズをまとめてセッションストレージに保存します。別々にやると呼び出すときの条件分岐がめんどくさそうなので1つにまとめることにしました。

そして、次のページに移動した時、何よりも先にこのセッションストレージに保存されたデータを読み込まなければいけません。

ということで、保存したデータをhead内に新たにstyleタグを作ってねじ込みます。

sessionStorageの値を読み込んでheadにstyleタグを差し込むJavaScript

const k = sessionStorage.getItem('key');
if (k) {
    const style = document.createElement('style');
    const data = k.split(':');
    const wrapperWidth = data[0] + "px";
    const sideWidth = data[1] + "px";
    style.textContent = "<style>" + wrapperWidth + sideWidth + "</style>";
    document.head.appendChild(style);
}

色々な書き方があると思いますが、とりあえずこれで。私にとっては誤解が少なく、かつめんどくさくないやり方です。

うにょうにょサイズを変更したときと同じように wrapper.style.width = ~px としても良いのかもしれません。しかしその場合、google adsenseなどと併用した際、ページが読み込まれたあとにガクッとサイズが変わることがありました。

なので事前にstyleタグを作ってサイズを確定させてしまいます。しかもこれはページの描写の前にやっておかなければならないのでhead閉じタグ直前に配置して読み込ませます。

JavaScript 全部

// 何よりも先に実行されてほしい部分
const k = sessionStorage.getItem('key');
if (k) {
    const style = document.createElement('style');
    const data = k.split(':');
    const wrapperWidth = data[0] + "px";
    const sideWidth = data[1] + "px";
    style.textContent = "<style>" + wrapperWidth + sideWidth + "</style>";
    document.head.appendChild(style);
}
// ページ読み込み後に実行される部分
document.addEventListener("DOMContentLoaded", function() {
    const wrapper = document.getElementById("wrapper");
    const side = document.getElementById("side");
    const splitbar = document.getElementById("splitbar");
    const bodyWidth = document.body.clientWidth;
    let flg = false;

    // バーをクリックしたらフラグをオン
    splitbar.onclick = function() {
        flg = true;
    }

    // マウスを動かしたら左右のカラムサイズを変える
    window.onmousemove = function(e) {
        if (flg) {
            wrapper.style.width = e.pageX + "px";
            side.style.width = (bodyWidth - e.pageX) + "px";
            
            // マウスを離したらフラグをfalseにしてstorageに登録
            window.onmouseup = function(e) {
                flg = false;
                sessionStorage.setItem('key', wrapper.style.width + ':' + side.style.width)
            }
        }
    }
}

レスポンシブに対応

レスポンシブの対応って簡単なようで難しく、難しいようで簡単だと思います。やろうと思えばできるけど、スマートにやらないと後でものすごく苦労する感じ?

できるからといってやっているといつまでも終わらない。うまい落とし所を見つけるのは予想の10倍難しい、そんな印象です。

最低限のCSS

#splitbar {
    display: none;
}
@media only screen and (min-width: 1025px) {
    #wrapper {
        height: 100vh;
        width: 70%;
        overflow: auto;
    }
    #side {
        position: fixed;
        top: 0;
        right: 0;
        width: 30%;
        height: 100vh;
        overflow: auto;
    }
    #splitbar {
        display: block;
        position: absolute;
        top: 0;
        left: 0;
        width: 10px;
        height: 100%;
        user-select: none;
    }
}

こんな感じにしておけば、PCではよくあるフツーの2カラムのサイトがスマホでワンカラムになる状態を実現できます。

まとめ

  1. 左カラム右カラムを分けるバー。あれでサイズをうにょうにょと変える。
  2. 変えたサイズは保存され、次のページへ遷移しても維持される。
  3. レスポンシブに対応

細かい設定を加える必要はあると思いますが、おおまかなところはこれで完成です。

SPAに手を出してみたい気持ち

世間はもっぱらSPAのようですが、SPAにはシングルページアプリケーションというくらいですから、アプリケーションとしての居場所があるような気がします。

今wordpressのようなサイトで出来ていることを「庶民のサイト」で全部のせを実現するのはまだ早いのかもしれません。少なくとも私にとってはかなり敷居が高いと感じました。

情報を探してみると、だいたいが「立ち上げてみた」「1ページ作ってみた」「スターターが便利だよ」というのものばかりであり、長く運用されているものは見当たらず。

プロやセミプロのような人間が匙を投げる代物を、ズブの素人が長い間メンテナンスし続けられるのだろうか…。

Vue.jsやGatsbyjsを勧めているサイトがSPAになっていないのはなぜなんでしょう?どうして「SPAを作ってみた」の記事がはてなブログから投稿されているのでしょう?

Gatsbyjsを使ってみたけれど

Gatsbyjsを一度使ってみました。

いい感じにSPAかつSSR、静的HTMLでmetaタグぎっしりSEO完璧、そしてPWAのサイトがサクッとできました。広告も入れられるし、Graphqlもなんとなくわかりました。

でも、開発中の動作がめちゃくちゃが遅い。遅すぎる…。node.jsの馬鹿みたいに遅いビルドには耐えられない。何をしているのかわからないScriptが大量にインストールされる恐ろしい光景…。

そして、未熟な私にとってはブラックボックス感がすごくて気持ち悪かったです。修行して出直します。

かたやHugo。速い。何度でも気軽にビルドしてチェックができます。最悪HTMLべた書きでもいい。

唯一気になるのは、Hugoのあれこれを学んだところでそれはGolangの勉強にはなっていなそうなところ。それでもやはりこの圧倒的な速さは正義だと思います。ズボラな人間にとって起動が速い、buildが速いというのは大変ありがたいもんです。

記事一覧へ戻る
メニュー