Webブラウザの拡張機能は本質的に第三者のWebサイトにJavaScriptやCSSをインジェクションします。
WebサイトによってはContent-Security-Policy (CSP)によってJSやCSSのインジェクションを制限している場合があります。
外部のユーザーエージェントによるJSやCSSを制限するContent-Security-Policyが設定されているWebサイトは多くはないのですが、AppleのDeveloperドキュメント以下のコンテンツにはかなりImageやCSSについて厳しめのCSPが設定されています。
Content-Security-Policy: default-src 'self' *.apple.com; script-src 'self' *.apple.com 'unsafe-eval' 'sha256-7njJh...' 'sha256-fgSWl...'; img-src 'self' *.apple.com data:; style-src 'self' *.apple.com 'sha256-8sYhe...';
レスポンスヘッダを見ると上記のようなContent-Security-Policyヘッダが設定されています。
このときstyle-src 'self' *.apple.com
なのでapple.com
ドメイン以外のソースから提供されるCSSはブロックされます。
<link href="https://not-apple.com/styles/main.css" rel="stylesheet" /> <style> #inline-style { background: red; } </style> <style> @import url("https://not-apple.com/styles/print.css") print; </style>
インラインのstyle
属性もブロックされます。
<div style="display:none">Foo</div>
Webブラウザの拡張機能では、WebサイトのCSSに影響を与えないように拡張機能が挿入したHTMLにはインラインのstyle
属性を使うことはわりとありますが、そのように書いている場合はスタイルがブロックされて適用されません。
JavaScript で直接style
属性を設定したり、cssText
を設定したりしたスタイルも同様です。
document.querySelector("div").setAttribute("style", "display:none;"); document.querySelector("div").style.cssText = "display:none;";
以下のような、JavaScriptのstyle
プロパティを使って直接設定する場合はスタイルが適用されます。
document.querySelector("div").style.display = "none";
詳しくは下記の解説を見てください。
ただ、すべてのCSSをJavaScriptのstyle
プロパティを使って書いていくことは現実的ではないことが多いですし、DOM要素があらかじめ存在していなかったり擬似要素には適用できないなど、技術的に不可能な場合もあります。
対策としてはbrowser.runtime.getURL()
関数で取得したURLはそのWebサイト自身のソース扱いになるので、下記のようにCSSを参照するLinkタグを追加するとContent-Security-Policyでstyle-src 'self'
と設定されていてもそのCSSは問題なく読み込まれます。
衝突するようなスタイルがあるとWebサイトに影響を与えてしまうのでそこは注意する必要があります。
const link = document.createElement("link"); link.setAttribute("rel", "stylesheet"); link.setAttribute("href", browser.runtime.getURL("assets/style.css")); document.head.appendChild(link);
Webコンポーネント(Shadow DOM)に対して同様のことを行うには下記のようにします。
const link = document.createElement("link"); link.setAttribute("rel", "stylesheet"); link.setAttribute("href", browser.runtime.getURL("assets/style.css")); this.shadowRoot.appendChild(link);