我正在开发一个 Chrome 扩展,我希望用户能够添加自己的 CSS 样式来更改扩展页面(而不是网页)的外观。我已经研究过 using document.stylesheets
,但似乎它希望拆分规则,并且不会让您注入完整的样式表。有没有一种解决方案可以让我使用字符串在页面上创建新的样式表?
我目前没有使用 jQuery 或类似的,所以纯 Javascript 解决方案会更可取。
我正在开发一个 Chrome 扩展,我希望用户能够添加自己的 CSS 样式来更改扩展页面(而不是网页)的外观。我已经研究过 using document.stylesheets
,但似乎它希望拆分规则,并且不会让您注入完整的样式表。有没有一种解决方案可以让我使用字符串在页面上创建新的样式表?
我目前没有使用 jQuery 或类似的,所以纯 Javascript 解决方案会更可取。
有几种方法可以做到这一点,但最简单的方法是创建一个<style>
元素,设置它的textContent属性,然后附加到页面的<head>
.
/**
* Utility function to add CSS in multiple passes.
* @param {string} styleString
*/
function addStyle(styleString) {
const style = document.createElement('style');
style.textContent = styleString;
document.head.append(style);
}
addStyle(`
body {
color: red;
}
`);
addStyle(`
body {
background: silver;
}
`);
如果你愿意,你可以稍微改变它,以便在addStyle()
调用时替换 CSS 而不是附加它。
/**
* Utility function to add replaceable CSS.
* @param {string} styleString
*/
const addStyle = (() => {
const style = document.createElement('style');
document.head.append(style);
return (styleString) => style.textContent = styleString;
})();
addStyle(`
body {
color: red;
}
`);
addStyle(`
body {
background: silver;
}
`);
IE 编辑:请注意,IE9 及以下版本最多只允许 32 个样式表,因此在使用第一个片段时要小心。这个数字在 IE10 中增加到 4095。
2020 年编辑:这个问题已经很老了,但我仍然偶尔会收到有关它的通知,因此我将代码更新为更现代,并替换.innerHTML
为.textContent
. 这个特定实例是安全的,但innerHTML
尽可能避免是一个好习惯,因为它可能是 XSS 攻击向量。
感谢这个家伙,我能够找到正确的答案。这是如何完成的:
function addCss(rule) {
let css = document.createElement('style');
css.type = 'text/css';
if (css.styleSheet) css.styleSheet.cssText = rule; // Support for IE
else css.appendChild(document.createTextNode(rule)); // Support for the rest
document.getElementsByTagName("head")[0].appendChild(css);
}
// CSS rules
let rule = '.red {background-color: red}';
rule += '.blue {background-color: blue}';
// Load the rules and execute after the DOM loads
window.onload = function() {addCss(rule)};
你听说过承诺吗?它们适用于所有现代浏览器,并且使用起来相对简单。看看这个将 css 注入 html 头部的简单方法:
function loadStyle(src) {
return new Promise(function (resolve, reject) {
let link = document.createElement('link');
link.href = src;
link.rel = 'stylesheet';
link.onload = () => resolve(link);
link.onerror = () => reject(new Error(`Style load error for ${src}`));
document.head.append(link);
});
}
您可以按如下方式实现它:
window.onload = function () {
loadStyle("https://fonts.googleapis.com/css2?family=Raleway&display=swap")
.then(() => loadStyle("css/style.css"))
.then(() => loadStyle("css/icomoon.css"))
.then(() => {
alert('All styles are loaded!');
}).catch(err => alert(err));
}
真的很酷,对吧?这是一种使用 Promises 决定样式优先级的方法。
或者,如果您想同时导入所有样式,您可以执行以下操作:
function loadStyles(srcs) {
let promises = [];
srcs.forEach(src => promises.push(loadStyle(src)));
return Promise.all(promises);
}
像这样使用它:
loadStyles([
'css/style.css',
'css/icomoon.css'
]);
您可以实现自己的方法,例如按优先级导入脚本、同时导入脚本或同时导入样式和脚本。如果我获得更多选票,我将发布我的实现。
如果您想了解有关 Promises 的更多信息,请在此处阅读更多信息
我最近也有同样的需求,并编写了一个与 Liam 相同的函数,除了还允许多行 CSS。
injectCSS(function(){/*
.ui-button {
border: 3px solid #0f0;
font-weight: bold;
color: #f00;
}
.ui-panel {
border: 1px solid #0f0;
background-color: #eee;
margin: 1em;
}
*/});
// or the following for one line
injectCSS('.case2 { border: 3px solid #00f; } ');
这个函数的来源。你可以从Github repo下载。或者在这里查看更多示例用法。
我的偏好是将它与 RequireJS一起使用,但在没有 AMD 加载程序的情况下,它也可以作为全局函数工作。
我认为注入任何 HTML 字符串的最简单方法是通过:insertAdjacentHTML
// append style block in <head>
const someStyle = `
<style>
#someElement { color: green; }
</style>
`;
document.head.insertAdjacentHTML('beforeend', someStyle);