使用 Javascript 将 CSS 样式表作为字符串注入

问题描述 投票:0回答:7

我正在开发一个 Chrome 扩展程序,我希望用户能够添加自己的 CSS 样式来更改扩展程序页面(而不是网页)的外观。我研究过使用

document.stylesheets
,但它似乎希望将规则分开,并且不允许您注入完整的样式表。有没有一种解决方案可以让我使用字符串在页面上创建新的样式表?

我目前没有使用 jQuery 或类似的,所以纯 Javascript 解决方案会更好。

javascript css dom google-chrome-extension
7个回答
137
投票

有多种方法可以完成此操作,但最简单的方法是创建一个

<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 攻击向量。


21
投票

感谢这个人,我能够找到正确的答案。这是如何完成的:

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)};

小提琴


9
投票

你听说过 Promise 吗?它们适用于所有现代浏览器,并且使用起来相对简单。看看这个将 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));
}

真的很酷,对吧?这是一种使用 Promise 来决定样式优先级的方法。

或者,如果你想同时导入所有样式,你可以这样做:

function loadStyles(srcs) {
    let promises = [];
    srcs.forEach(src => promises.push(loadStyle(src)));
    return Promise.all(promises);
}

像这样使用它:

loadStyles([
    'css/style.css',
    'css/icomoon.css'
]);

您可以实现自己的方法,例如按优先级导入脚本、同时导入脚本或同时导入样式和脚本。

如果您想了解更多有关 Promise 的信息,请阅读更多这里


8
投票

我认为注入任何 HTML 字符串的最简单方法是通过:

insertAdjacentHTML

// append style block in <head>

const someStyle = `
<style>
    #someElement { color: green; }
</style>
`;

document.head.insertAdjacentHTML('beforeend', someStyle);

2
投票

我最近有同样的需求,并编写了一个函数来执行与 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 存储库 下载。或者在此处查看更多示例用法

我的偏好是将其与 RequireJS 一起使用,但在没有 AMD 加载程序的情况下它也可以作为全局函数工作。


1
投票

创建一个

style
标签,并将 css 样式作为字符串添加到
textContent
属性中。将这些附加到文档头中。繁荣,你可以走了。

var styles = document.createElement("style");
styles.setAttribute("type", "text/css");
styles.textContent = `#app{background-color:lightblue;}`;
document.head.appendChild(styles);

0
投票

使用

CSSStyleSheet

的现代变体

创建风格:

const sheet = new CSSStyleSheet();
// Apply the rules to the sheet
sheet.replaceSync(styleString);

然后将样式表应用到文档和/或影子根;

document.adoptedStyleSheets = [sheet]; // replace all the styles with the newly created one

document.adoptedStyleSheets.push(sheet) // add the style to the end of the "cascade" (highest importants)

当然,适用于常规数组的内容也适用于

document.adoptedStyleSheets
属性,它可以是过滤器,可以重新定位元素等等。

这同样适用于 Shadow dom

el.shadowRoot.addoptedStyleSheet.push(sheet)

如果存在

shadowRoot
,则在其上附加一个,例如:

const div = document.createElement('div');
div.attachShadow({mode: 'opened'});

此变体为您提供了更多编程选项,可以在阴影组件之间共享样式或微调文档上的样式

© www.soinside.com 2019 - 2024. All rights reserved.