おかゆ++

IT業界の片隅で生き残るブログ

はてなブログの背景にアニメーションをつける(自作テーマ不使用)

このブログの背景にアニメーションをつけてみました。コードはGitHubで公開しています。

github.com

はてなブログではhead要素の中に自由に要素を追加できるので、こういうちょっとした改造がすぐできていいですね。

自作テーマを作ることでも実現できると思いますが、そこまでは……という気持ちだったので、JavaScriptでゴリゴリやりました。

ざっくりした方法

  1. canvas要素を画面いっぱいのサイズで最背面に追加する
  2. canvas要素に適当なアニメーションを描画する(アニメーションはsetIntervalとかで愚直に書く)
  3. ウィンドウがリサイズしたときに、canvasも合わせてリサイズする

さくっと自分のはてなブログに適用したい方へ

はてなブログの 設定>詳細設定 を開きます。

f:id:okayu-moka:20170929164807p:plain
はてなブログ 設定>詳細設定

headに要素を追加 に、以下のソースを貼り付けます。

<script>
!function(n){function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var e={};t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{configurable:!1,enumerable:!0,get:i})},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=0)}([function(n,t){!function(){var n=15,t=null,e=null,i=[];window.addEventListener("load",function(n){o(),a(),r(),d()});var o=function(){t=document.createElement("canvas"),t.id="__background_animation_canvas__",t.style.position="fixed",t.style.top=0,t.style.left=0,t.style.zIndex=-1,t.style.margin="0",t.style.padding="0",t.width=window.innerWidth,t.height=window.innerHeight,e=t.getContext("2d"),document.body.appendChild(t)},a=function(){var e=window.innerWidth;n=e>1920?20:e>1600?15:e>1024?10:7;for(var o=0;o<n;o++)i.push({x:t.width/2,y:t.height/2,angle:2*Math.PI*Math.random(),size:30+70*Math.random(),speed:.02+(.05-.02)*Math.random()})},r=function(){var n=null;window.addEventListener("resize",function(){null===n&&window.clearTimeout(n),n=window.setTimeout(function(){t.width=window.innerWidth,t.height=window.innerHeight,n=null},200)})},l=function(){e.beginPath(),e.clearRect(0,0,t.width,t.height),e.closePath();for(var n=0;n<i.length;n++){var o=i[n];e.beginPath(),e.fillStyle="rgba(255, 170, 1, 0.1)",e.arc(o.x,o.y,o.size,0,2*Math.PI,!1),e.fill(),e.closePath()}},u=function(){var n=null;return function(){var e=t.width,o=t.height,a=Date.now();null===n&&(n=a);for(var r=0;r<i.length;r++){var l=i[r],u=l.speed*(a-n),d=u*Math.cos(l.angle),c=u*Math.sin(l.angle);l.x+=d,l.y+=c,(l.x<=0||e<=l.x)&&(l.angle=Math.atan2(c,-d),l.x=l.x<=0?0:e),(l.y<=0||o<=l.y)&&(l.angle=Math.atan2(-c,d),l.y=l.y<=0?0:o)}n=a}}(),d=function(){var n=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame,t=function(t){n?n(t):window.setTimeout(t,33)},e=function(){try{u(),l()}catch(n){console.log(n)}t(e)};t(e)}}()}]);
</script>

以上でアニメーションは適用されますが、全面の要素で隠れてしまう場合があります。その場合はCSSで背景を透明にします。このブログでは記事の部分(#content の部分)に背景色 #ffffff が設定されており、アニメーションが隠れてしまったので、記事部分の背景を透明にします。

cssはデザイン設定からも上書きできますが、コードが近いほうがわかりやすそうなので、同じく headに要素を追加 の部分に以下を追記します。

<style>
#content{ background-color: transparent !important; } /* 背景透過 */
</style>

このあたりは使用しているブログテーマによってまちまちなので、調整が必要です。

コードの解説

簡単にポイントのみ解説します。

jQueryを使うかどうか

ブログテーマによってはjQueryが使用されているものがあり、今使わせてもらっているこのテーマでも読み込まれています。

が、今回は使わずに素のJavaScriptだけにしました。jQueryを使わないと面倒なところが特になかったのと、他のブログテーマに乗り換えたときにも使えるようにしたかったのが主な理由です。

canvas要素を画面いっぱいに追加する

document.createElementcanvas要素の生成して、body要素の直下に追加します。

画面いっぱいに広げる際に注意が必要なのが、canvasのサイズはcssで設定せず、canvas.widthとcanvas.heightで設定する点です。canvas自体のサイズを調整せずにcsswidth:100% などとすると、canvasの解像度はそのままに、横に引き伸ばした表示になってしまいます。今回はウィンドウサイズ=canvasサイズとしたいので、canvas.widthとcanvas.heightを設定します。

var canvas = null;
var context = null;
var createCanvas = function() {
    canvas = document.createElement('canvas');
    canvas.id = '__background_animation_canvas__';
    canvas.style.position = 'fixed';
    canvas.style.top = 0;
    canvas.style.left = 0;
    canvas.style.zIndex = -1;
    canvas.style.margin = '0';
    canvas.style.padding = '0';

    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    context = canvas.getContext('2d');

    document.body.appendChild(canvas);
};

初期化とアニメーション開始のタイミング

案としては DOMContentLoaded イベント時と、windowの load イベント時があります。

はてなブログでは DOMContentLoaded 後にも色々スクリプトが走ったりしているぽいので、今回は load イベントで初期化・アニメーション開始としました。実際、 DOMContentLoaded だとアニメーション開始後のカクツキがひどかったので、load が無難だと思います。

window.addEventListener('load', function(event) {
    createCanvas();
    createCircles();
    initOnResize();
    startTimer();
});

アニメーションの描画

canvasにアニメーションを描画するために、タイマーを回します。タイマーとしては setInterval などでも良いですが、こういう画面更新の用途としては requestAnimationFrame を使うのが良いみたいです。

ただ requestAnimationFrame は対応していないブラウザなんかもあるみたいなので、対応していない場合は setTimeout で代用するようにしておきます。

var startTimer = function() {
    var requestAnimationFrame = 
            window.requestAnimationFrame || window.mozRequestAnimationFrame ||
            window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
    var requestFrame = function(loopFunc) {
        if (requestAnimationFrame) {
            requestAnimationFrame(loopFunc);
        } else {
            window.setTimeout(loopFunc, 33);
        }
    };
    var loopFunc = function() {
        try {
            move();
            draw();
        } catch (e) {
            console.log(e);
        }
        requestFrame(loopFunc);
    };
    requestFrame(loopFunc);
};

JavaScriptの圧縮(minify)

そのままのコードでだいたい130行くらいになってしまったので、圧縮して短くします。Webにオンラインで圧縮してくれるサービスがいくつもあるので、それを利用するのが一番手軽だと思います。

ただ今後のことも考えて、webpack3でminifyするようにしました。plugins にminifyプラグインを指定すると出力時に圧縮してくれます。

const webpack = require("webpack");

module.exports = {
    entry: {
        'build': './src/bubble-anim.js',
        'docs': './src/bubble-anim.js'
    },
    output: {
        filename: "./[name]/bubble-anim.min.js"
    },
    plugins: [
        new webpack.optimize.UglifyJsPlugin()
    ],
}

まとめ

ブログのカスタマイズは楽しいですね。<head> に自由に追加できるということは、実質何でもできると思うので、色々試していきたいです。