WWW Watch

改行削除するくらいなら gzip したらいいじゃない

CSS や JavaScript ファイルなどを gzip 圧縮して転送量の削減や Web サイト表示速度の向上を実現する方法を解説。既存 Web サイトのソースには一切手を加えない方法でまとめています。おまけでキャッシュ関連の記述もあり。

いや、1バイトの無駄もゆるせねぇんだよとか、難読化したいとかなら別にやればいいんですけど、CSS や JavaScript ファイルの改行やスペースを削除しただけでファイル容量圧縮、読み込み速ーい的なこという人がいるので今さらですが書いてみます。すでに色々なところで書かれてるのでかぶるのは承知の上で。

改行や無駄なスペースなどを削除すること自体が悪いと言ってるわけではありませんのでその辺は誤解ないようにお願いします。ただ、gzip 使って圧縮するのに比べたら、改行削除して削れるファイルサイズなんて微々たるものです。もちろん、両方やれば最大限ファイルサイズを削減できますので gzip 使うのとあわせて改行削除もやったらいいと思いますけども。Sass とか使ってるなら CSS の改行やスペース削除なんかは簡単だしね。

実際にどの程度ファイルサイズが変わるのか

まずは gzip 圧縮によってどの程度ファイルサイズに差が出るのか見てみましょう。

当 Blog の CSS ファイルを例に挙げてみますが、一部を除いて特に改行などは削除していない状態、1,700行弱のファイルが下記の通り、約 34KB です。

圧縮前の CSS ファイルサイズ

次にこいつの改行をすべて削除してみます。こんな感じに。

改行を削除した状態の CSS

この状態でファイルサイズを見てみると…

改行を削除した状態の CSS ファイルサイズ

約 30KB になりました。ファイルサイズにして 10% 強、圧縮できたことになります。当然、元のファイルサイズが大きければ (というより行数やインデントが多ければ) 圧縮率は高くなると思いますけども。

次に、改行などは削除していない状態の元ファイルを gzip 圧縮してみます。するとファイルサイズは…

gzip 圧縮した状態の CSS ファイルサイズ

約 7.1KB まで小さくなりました。元のファイルサイズと比べると 20% 強のサイズですので、ファイルサイズを 8割程度削減できたことになります。ちなみに、改行も削除した状態で gzip 圧縮すれば、あともう少しファイルサイズを小さくできます。でも、gzip 圧縮せずに改行だけ削除したところで大したファイルサイズの削減にはなっていないことがわかると思います。

実際に読み込み時間にどの程度差が出るのかも見てみます。Firebug で表示してみますが、圧縮前の状態だと、下記の通り受信に 93ms かかっています。約 0.1 秒ですね。

圧縮前の CSS の読み込み速度

次に gzip 圧縮した状態のファイルを読み込んでみます。結果は 15ms (0.015秒) になりました。先ほどと比べて 1/6 程度の短い時間で受信が完了しているのはわかると思います。

gzip 圧縮した CSS の読み込み速度

当然、読み込み速度は回線やサーバの状況などによってその都度変化しますが、gzip 圧縮することでかなりの転送量削減や速度向上につながることがわかります。

どういう仕組み?

gzip を使用した転送量削減の仕組みについて細かい説明は割愛しますが、簡単に言えば JavaScript や CSS、HTML、XML… 何でもいいんですけど、これらファイルを圧縮した状態でブラウザに渡して、あとはブラウザ側で展開して通常通り処理してもらうっていうもの。

つまりブラウザさえ gzip に対応していれば使えるということですが、大昔のブラウザや、細かく調べていませんので正確にはわかりませんが、旧式の所謂ガラケーに搭載されたブラウザなど (?) 一部を除けば、gzip はほぼすべてのブラウザで問題なく扱えます。

また、後述しますが、gzip を扱えないブラウザでアクセスされたとしても圧縮前のファイルを渡せばいいだけですので全く問題はありません。

gzip を使用することで、サーバはブラウザに対して圧縮ファイルを送信するので、当然、元のファイルをそのまま送信するよりデータ転送量は減らすことができます。この辺はメールの添付ファイルを圧縮して送ったりするするのと同じです。そのため、前述したように転送量と受信にかかる時間を削減できるわけです。

ちなみに、gzip 圧縮されたファイルの拡張子は 「.gz」 になります。

圧縮ファイルをどのように用意するか

gzip によるファイル圧縮は、サーバで mod_deflate (mod_gzip) が使える場合は設定さえしてやればあとはサーバ側でファイルへのアクセス時に自動的に圧縮して送信してくれるので簡単です。例えば .htaccess でやるなら下記のように。

<ifModule mod_deflate.c>
SetOutputFilter DEFLATE
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|ico)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI _\.utxt$ no-gzip
</ifModule>

画像ファイルは圧縮しても意味ないので除外したりしていますが、設定さえしてしまえばあとはサーバ側で圧縮してくれるので簡単。

ところが、個人のサイトオーナーが使うようなレンタルサーバだと mod_deflate が使えないケースが多い (都度圧縮されるため、その処理がサーバに負荷をかけるので仕方ないんですけども) ので、今回は手作業で用意する方法も紹介してみます。

なお、PHP などのプログラムで動的に生成されているページや SSI で何らかの処理をしているページなどに関してはアクセスの度にサーバ側で動的に gzip 圧縮して送信するっていう形、つまり出力結果に対して gzip 圧縮するという順番にしてあげないといけません。この場合も上記の mod_deflate が使えれば特に問題ありませんが、サーバ環境によってはお手上げかも。PHP ファイルの圧縮であれば、zlib が使える環境ならそれで代替できます。

ちなみに、当サイトは さくらインターネットさんのレンタルサーバを使っていますが、PHP で zlib は使えるものの、mod_deflate (mod_gzip) は今のところ使えません……

PHP で zlib を有効にするなら、php.ini に

zlib.output_compression = On

を設定するだけです。サイト全体を PHP で出力してる (WordPress 使ってるとか、MovableType で ダイナミックパブリッシングしてるとか) なら有効かもしれません。

余談ですが、WordPress で よく使われるプラグイン、WP Super Cache にはコンテンツを gzip 圧縮するオプションが用意されていたりします。

余談ついでに、例えば CSS ファイルを PHP で書き出すとかすれば、この仕組みで CSS ファイルなどの圧縮もできますが、すでに稼働しているサイトの場合、既存のソースコードを変更したりしないといけないのは面倒なのであまりやらないですよね…

gzip 圧縮してみる

で、話を戻して手作業で gzip ファイルを作る方法ですが、誰でもわかりやすくて簡単なのはファイル圧縮ソフトを使うことでしょう。例えば、Windows 環境では Lhaplus を私は使わせて頂いてますが、.gz 形式の圧縮ファイルが簡単に作れます。

インストールしたら、設定画面から下記のようにコンテキストメニューに圧縮メニューが追加されるようにし、そこに .gz を選択できるようにしておきます。これで圧縮したいファイルを右クリック → 圧縮 > .gz で簡単に圧縮ファイルが作れます。

Lhaplus の設定

なお、64bit 版の Windows でも Lhaplus は動作しますが、コンテキストメニューに 「圧縮」、「解凍」 のメニューが追加されないという問題があります。それを解決するために、下記の拡張を公開してくれている方がいらっしゃいますので、そちらを利用させてもらうといいと思います。管理者権限でインストールしましょう。

一方、Mac 環境なら Terminal から gzip コマンド打てばいいだけですので、特にソフトウェアをインストールしたりしなくても .gz ファイルを作ることができます。

実際に gzip したファイルを使ってみる

CSS ファイルを例に話を進めますが、上記の手順で gzip 圧縮した CSS ファイルを用意したら、サーバにアップします。この際、圧縮前のファイルと同じディレクトリに、一緒に入れておきましょう。

gzip 圧縮した CSS ファイルを設置

普通に圧縮すれば、style.css の圧縮ファイルは style.css.gz になっていると思います。このようにファイル名は元のファイル名 + .gz になっていることを確認してください。これが違うと後述する設定が正常に動作しません。

なお、すでに稼働しているサイトなら、CSS ファイルを読み込む側の HTML ファイルには変更を加える必要はありません。これから作るサイトなら、HTML ファイル内で読み込み指定するのは、あくまで圧縮前の CSS ファイルです。つまり、普通にサイトを作って、最後に CSS を gzip 圧縮して元の CSS ファイルと同じ場所に入れとけば準備完了ってことです。

<!-- ↓正しい例。HTMLは変更の必要なしです。 -->
<link rel="stylesheet" href="style.css" />
 
<!-- ↓間違い。こういうことする必要はないです。 -->
<link rel="stylesheet" href="style.css.gz" />

mod_rewrite で .gz ファイルを送信するように設定

ということで、サーバ側で mod_rewrite が使えないと終わりなんですが、今どきのレンタルサーバで mod_rewrite 使えないのも珍しいと思いますので進めます。.htaccess ファイルを編集して、gzip に対応したブラウザには .gz ファイルを、そうでない場合には元の .css ファイルを渡すようにしてあげましょう。

下記のように記述します。

#RewriteEngine を有効に
RewriteEngine On
 
#これの記述は任意。対象ディレクトリを指定したい場合は書けばいい。書かなければ .htaccess が置かれたディレクトリ以下に有効
RewriteBase /
 
#Accept-Encoding ヘッダをみて、gzip があれば (つまり gzip に対応した相手なら) 処理を続行。なければ終わり。
RewriteCond %{HTTP:Accept-Encoding} gzip
 
#送信リクエストされたファイル名に対して、.gz がついたファイルがあるか調べて、あれば次の行へ。なければここで終了。
RewriteCond %{REQUEST_FILENAME}¥.gz -s
 
#リクエストされたファイル名 + .gz のファイルを返す。
RewriteRule .+ %{REQUEST_URI}.gz

これで、

  • gzip に対応したブラウザに対して
  • gzip されたファイルがあればそれを送信する
  • 対応していなければ圧縮していないファイルを送信する

という風にうまいことやってくれます。

あと、gzip 圧縮されたファイルが、元ファイルと同じように処理されるように MIME タイプも設定しといてあげましょう。CSS や JavaScript など、圧縮ファイルを用意する状況に応じて書いておけば大丈夫。

#httpd.conf 内の mod_mime で設定がされていないなら書いとく。これで .gz のファイルが gzip として扱われる。
AddEncoding x-gzip .gz
 
#~.css.gz というファイルに CSS の MIME タイプを指定
<files *.css.gz>
  AddType text/css .gz
</files>
 
#~.js.gz というファイルに JavaScript の MIME タイプを指定
<files *.js.gz>
  AddType text/javascript; .gz
</files>

※本来 JavaScript の MIME タイプは application/javascript ですが、IE7 以前が対応していないので text/javascript が無難。

ということで、設定が正しければ、gzip 圧縮版があるファイルは、そちらが送信されます。Firebug などで確認してみましょう。

おまけ。キャッシュの保持期間も設定しておくといいかも

gzip による圧縮で送信されるファイルのサイズを小さくすることも有効ですが、送信されるファイルの数自体を減らすというのも大事です。ブラウザのキャッシュ機能をうまく利用するのもひとつの手です。これは mod_expires が使えるサーバであれば、.htaccess で設定できます。例えば下記のような感じ。

<ifModule mod_expires.c>
ExpiresActive On
<Files ~ "¥.(gif|jpg|png|ico)$">
  ExpiresDefault "access 1 weeks"
</Files>
ExpiresByType text/css "access 3 days"
ExpiresByType text/javascript "access 3 days"
ExpiresByType application/javascript "access 3 days"
</ifModule>

頻繁に更新されるものは期間を短く、又は設定自体をしないようにすればいいですが、画像など、1度アップされたら変更される可能性の低いものは少し長めのキャッシュを設定してもいいですね。

access <num> <type> (access plus <num> <type> でもいいですが plus は省略できます) で、該当ファイルのアクセスから指定の期間 (<num> <type>) が経過するまでキャッシュしとけという意味になります。

<num> の部分には整数値、<type> には下記のいずれかが指定できます。

  • years
  • months
  • weeks
  • days
  • hours
  • minutes
  • seconds

ただし、キャッシュされていることを忘れていると、修正時に更新が反映されなくてハマるなんてマヌケなことになりかねませんので注意しましょう。キャッシュ設定自体は長めに設定しておいて、ファイルの更新に関しては、

<link rel="stylesheet" href="style.css?20120101" />

のようにクエリ文字列を付与してキャッシュをクリアするなどしてあげればいいかもしれません。自分の環境だけとりあえずキャッシュをクリアしたいだけなら Ctrl + F5 でスーパーリロードすればいいだけですけども。

さらにおまけ。Cache Manifest っていう手段もあるよ

Application Cache に対応したブラウザに対しては、Cache Manifest を渡してキャッシュしてもらうっていう手もあります。詳しいことは下記のページに書いてあります。

仕様はこっち

最も簡単な Cache Manifest の例は下記のような感じになります。

CACHE MANIFEST
 
/js/jquery.js
/img/logo.png

で、これを記述したファイルを

example.appcache

みたいに、.appcache 拡張子を付けてサーバに設置し、HTML 上で下記のように読み込んであげれば、指定したファイルがキャッシュされますと。

<html manifest="example.appcache">

Cache Manifest には、jQuery のライブラリとか、基本的に更新されることがないようなファイルを指定するといいかもしれません。

ただし、注意しないといけないのは cache manifest を指定したページ自体もキャッシュされてしまう仕様なので、アクセスごとにページが動的に生成されてるようなサイトだとずーっと古いページが表示されてしまうことになります。一応、キャッシュをクリアする方法もありますが、メンドクサイので使うときは注意が必要です。

ちなみに Cache Manifest ファイルの MIME タイプを設定しておかないと正しく動作しませんので、使用する場合は .htaccess に

AddType text/cache-manifest .appcache

するなど、下準備も必要です。

うまく使えばオフライン状態でも Web アプリケーションなどを使えるようにするなんてことができます。リファレンス的なものを Web ページとして作って、それを丸ごとキャッシュしてもらえばオフラインでも参照できるとか、そういう用途も考えられるんじゃないでしょうか。ちなみにキャッシュデータのサイズは最大で 5MB までです。


なんか書いてたら長くなってしまいましたが、Web サイトの表示速度は速いに超したことはありませんので、環境が許すなら色々試してみたらいいと思います。

Recent Entry

全ての記事一覧を見る

Hot Entry

逆引きおすすめエントリー