ブックマークレットは、URL の代わりに javascript: で始まる JavaScript を登録したブックマークです。ブックマークを選ぶと、表示中のページの上でその JavaScript が実行されます。拡張機能を入れなくても、ページの見た目を少し変えたり、ページの情報を取り出したりできるので、ちょっとした道具として便利です。ここでは、表示中のページに Google Fonts のフォントを読み込み、本文のフォントを変えるブックマークレットを例に、書き方の決まりを説明します。
まずはふつうの JavaScript として書く
いきなり 1 行で書くと読みにくいので、まずはふつうの JavaScript として書き、開発者ツールのコンソールで動きを確かめます。
(() => {
const id = "bm-google-font";
// 2 回目以降は、CSS を読み込み直さない
if (!document.getElementById(id)) {
const link = document.createElement("link");
link.id = id;
link.rel = "stylesheet";
link.href = "https://fonts.googleapis.com/css2?family=Noto+Serif+JP:wght@400;700&display=swap";
document.head.append(link);
}
// 本文に当たる要素だけ、フォントを変える
document.querySelectorAll("p, li, dt, dd, blockquote, h1, h2, h3, h4, h5, h6").forEach((el) => {
el.style.setProperty("font-family", '"Noto Serif JP", serif', "important");
});
})();
処理の流れは次のとおりです。
- Google Fonts の CSS を読み込む
link要素を作り、head要素に追加する。CSS の中にフォントのファイルの場所が書かれていて、必要な文字のフォントが読み込まれる - 段落や見出しなどの要素に、
font-familyを指定する
font-family は、要素の style に important 付きで指定しています。ページの CSS に !important 付きの指定があっても、上書きできるようにするためです。
フォントを変える要素を、ページのすべての要素 (*) にしなかったのには理由があります。アイコンをフォントで表示しているページでは、アイコン用の要素のフォントまで変わると、アイコンが崩れて別の文字が表示されてしまいます。コードの表示に使う等幅のフォントが変わるのも困ります。変える要素は、本文に当たるものに絞っておくのが無難です。
ブックマークレットにするときの決まり
ふつうの JavaScript をブックマークレットにするには、次の点を守ります。
全体を即時実行の関数で囲む。 上の例のように (() => { ... })(); で囲みます。中で宣言した変数が、ページのスクリプトの変数とぶつからなくなります。また、javascript: の URL は、最後の式の値が文字列だと、ページの中身がその文字列に置き換わってしまいます。関数で囲んで値を返さないようにすると、この問題も防げます。
先頭に javascript: を付け、URL として符号化する。 ブックマークの URL には、空白や %、# などをそのまま書けないことがあります。encodeURIComponent() で符号化しておくと確実です。コンソールで次のように実行すると、登録用の文字列ができます。
// code に、上のブックマークレットの本体を文字列として入れる
const code = `(() => { /* 本体 */ })();`;
console.log("javascript:" + encodeURIComponent(code));
1 行にまとめるなら、// の注釈を使わない。 改行を残したまま encodeURIComponent() で符号化すれば、改行も %0A として残るので問題ありません。しかし、改行を取り除いて 1 行にまとめると、最初の // から後ろがすべて注釈とみなされ、残りの処理が動かなくなります。1 行にする場合、注釈は /* */ で書くか、取り除いておきます。
できた文字列は、ブラウザーのブックマークの管理画面で新しいブックマークを作り、URL の欄に貼り付けて登録します。ブラウザーによっては、アドレスバーに javascript: で始まる文字列を貼り付けると、先頭の javascript: が取り除かれます。だまされて危険なスクリプトを実行させられるのを防ぐための仕組みなので、登録はブックマークの管理画面から行います。
動かないページがある
ブックマークレットは、どのページでも動くとは限りません。
ページが Content Security Policy (CSP) を設定していることがあります。CSP は、そのページで読み込んでよい CSS やフォント、実行してよいスクリプトの出どころを、サーバーから指定する仕組みです。style-src や font-src で読み込み先が制限されていると、Google Fonts の CSS やフォントのファイルが読み込まれず、フォントは変わりません。ブラウザーやページの設定によっては、ブックマークレットそのものが実行されないこともあります。
うまく動かないときは、開発者ツールのコンソールを開いて、読み込みが拒否されたというエラーが出ていないかを確かめます。CSP で拒否されている場合、ブックマークレットの側で回避する方法は基本的にありません。
安全に使うために
ブックマークレットは、表示中のページの中で、そのページのスクリプトと同じ権限で動きます。ページの内容を読んだり、フォームに入力した値を取り出したりすることもできてしまいます。出どころのわからないブックマークレットは登録しないでください。自分で書いたものでも、外部から読み込むのは、Google Fonts のように信頼できる提供元だけにしておきます。javascript: の URL がページの中でスクリプトとして実行される危険については、「URL の値をそのまま location.href に入れると XSS になる」でも説明しています。
まとめ
- ブックマークレットは、
javascript:で始まる JavaScript を登録したブックマーク - 全体を即時実行の関数で囲み、値を返さないようにする。URL は
encodeURIComponent()で符号化する - フォントを変える要素は、本文に当たるものに絞る (アイコンのフォントなどを壊さない)
- CSP で読み込み先が制限されたページでは、動かないことがある