このブログの背景にアニメーションをつけてみました。コードはGitHubで公開しています。
はてなブログではhead要素の中に自由に要素を追加できるので、こういうちょっとした改造がすぐできていいですね。
自作テーマを作ることでも実現できると思いますが、そこまでは……という気持ちだったので、JavaScriptでゴリゴリやりました。
ざっくりした方法
- canvas要素を画面いっぱいのサイズで最背面に追加する
- canvas要素に適当なアニメーションを描画する(アニメーションはsetIntervalとかで愚直に書く)
- ウィンドウがリサイズしたときに、canvasも合わせてリサイズする
さくっと自分のはてなブログに適用したい方へ
はてなブログの 設定>詳細設定 を開きます。
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.createElement
でcanvas要素の生成して、body要素の直下に追加します。
画面いっぱいに広げる際に注意が必要なのが、canvasのサイズはcssで設定せず、canvas.widthとcanvas.heightで設定する点です。canvas自体のサイズを調整せずにcssで width: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>
に自由に追加できるということは、実質何でもできると思うので、色々試していきたいです。