概要
Webフォントを当てると途端にサイトが良く見えるようになりますが、一方でフォントファイルに入っている文字数が多いため、必然的にファイルサイズが大きくなってしまいます。
そこでフォントのサブセット化と呼ばれる、使用する文字だけをフォントから抽出して独自のフォントとして用意する方法があります。
5〜10MBほどあるフォントが大体数十KB程度になるので初期ロード時間が劇的に改善されます。
サブセットフォント生成ツール
このfontminというツールを使用します。
インストール
gulp用のパッケージがあるのでそれを使います。
$ npm install -g gulp $ npm install --save-dev gulp gulp-fontmin
基本的な使い方
例として日本語以外の全ASCII文字列を対象にしてみましょう。
gulp.src
に元々のフォントファイルを、gulp.dest
に生成先ディレクトリを指定します。
gulp.task('font', () => { return gulp.src('./fonts/src/*.ttf') .pipe(fontmin({ text: '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~' })) .pipe(gulp.dest('./fonts/dest')); });
実行
$ gulp font
Mgen+ (ムゲンプラス) | 自家製フォント工房のmgenplus-1c-thin.ttf
に対して実行すると、以下のようなファイルが生成されます。
mgenplus-1c-thin.css mgenplus-1c-thin.eot mgenplus-1c-thin.svg mgenplus-1c-thin.ttf mgenplus-1c-thin.woff
自動で生成されたmgenplus-1c-thin.css
に
@font-face { font-family: "Mgen+ 1c thin"; src: url("mgenplus-1c-thin.eot"); /* IE9 */ src: url("mgenplus-1c-thin.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */ url("mgenplus-1c-thin.woff") format("woff"), /* chrome, firefox */ url("mgenplus-1c-thin.ttf") format("truetype"), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ url("mgenplus-1c-thin.svg#Mgen+ 1c thin") format("svg"); /* iOS 4.1- */ font-style: normal; font-weight: normal; }
とfont-face
が定義されているので、これを読み込んで使用すればOKです。
ソース中の全日本語を対象にしたい場合
コマンドラインで日本語の抽出をすることができます。
$ find ./src/app/ | xargs grep -dskip -o -h -e "[亜-熙ぁ-んァ-ヶ]" | sort | uniq > ./subset.txt
これをgulp task化します。
gulp.task('japanese', (cb) => { exec('find ./src/app/ | xargs grep -dskip -o -h -e "[亜-熙ぁ-んァ-ヶ]" | sort | uniq > ./subset.txt', (err) => { cb(err); }); });
あとは先程のコードと結合すればOKです。
gulp.task('font', () => { return gulp.src('./fonts/src/*.ttf') .pipe(fontmin({ text: getSubsetText(), })) .pipe(gulp.dest('./fonts/dest')); }); function getSubsetText() { const ascii = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'; const data = fs.readFileSync('./subset.txt', { encoding: 'utf-8' }); const all = ascii + data.toString().split('\n').join(''); console.log(all); return all; }