canvasにsans-serifとserifで「あ」を描画して差異があるかどうかを見るという方法です。
function hasJapSerif () {
const size = 16
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = size
canvas.height = size
ctx.fillStyle = '#000'
ctx.textAlign = 'start'
ctx.textBaseline = 'top'
ctx.font = size + 'px sans-serif'
ctx.fillText('あ', 0, 0);
const pixels1 = ctx.getImageData(0, 0, size, size).data
ctx.clearRect(0, 0, size, size)
ctx.font = size + 'px serif'
ctx.fillText('あ', 0, 0);
const pixels2 = ctx.getImageData(0, 0, size, size).data
for (let i = 0, ii = size*size*4; i < ii; i++) {
if (pixels1[i] !== pixels2[i]) {
return true
}
}
return false
}
これを利用して、Androidなど日本語明朝体がバンドルされてないデバイスのみ、日本語明朝体のウェブフォントを読み込むということができます。
if (!hasJapSerif()) {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = 'https://fonts.googleapis.com/css?family=Noto+Serif+JP'
document.head.appendChild(link)
}
去年のAdvent Calendarでシンプルにfont-familyを指定したい記事を書きました。
その記事で全ての主要なデバイスで日本語明朝体を表示する方法の一つに、UserAgentを見てAndroidの場合はGoogleFontsのNotoSerifを読み込むという雑なサンプルコードを紹介しました。
その記事を書いた2018年末、そしてこの2019年末も、主要デバイスで日本語明朝体をバンドルしてないのはAndoridだけですが、この判定方法はもちろんスマートではないですし、今後、Androidで日本語明朝体がバンドルされて font-family: serif の指定だけで日本語明朝体が表示されるようになる可能性もあるので、ちゃんとしたものを投稿しました。
わざわざ日本語明朝体がバンドルされてない場合のみウェブフォントを読み込み適用させる方法をとりたいのは、読み込むリソースの容量をできるだけ小さくしたいだけでなく、ウェブサイトのフォントはどのデバイスでもできるだけ同じにするのではなく、そのデバイスにバンドルされてる標準なフォントをできるだけ使う、という考え方をしてるのもあります。