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

IT技术 javascript css dom google-chrome-extension
2021-01-19 00:02:37

我正在开发 Chrome 扩展程序,我希望用户能够添加自己的 CSS 样式来更改扩展程序页面(而不是网页)的外观。我已经研究过 using document.stylesheets,但它似乎希望将规则分开,并且不会让您注入完整的样式表。有没有一种解决方案可以让我使用字符串在页面上创建新的样式表?

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

4个回答

有几种方法可以做到这一点,但最简单的方法是创建一个<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 攻击媒介。

不能追加到节点的innerHTML 上连续添加吗?例如类似的东西node.innerHTML = node.innerHTML + " " + str;
2021-03-17 00:02:37
两个片段都给我错误:TypeError: document.body is null document.body.appendChild(node);
2021-03-24 00:02:37
@runrunforest 我很遗憾听到这个消息,你在什么浏览器上运行这个?浏览器支持document.body应该回到 IE5.5 quirksmode.org/dom/w3c_html.html#t10
2021-04-04 00:02:37
我最终会想出innerHTML,但你提供的第二个片段真的很酷!
2021-04-11 00:02:37

多亏了这个人,我才能找到正确的答案。这是它的完成方式:

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 head 的简单方法:

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 的更多信息,请在此处阅读更多内容

我想这是更好的解决方案,因为与公认的解决方案相比,promise 将异步运行并且不会阻塞渲染
2021-03-15 00:02:37
一次加载它们肯定更有效。但是,在某些情况下,可能需要分配某个优先级。我已经发布了一个同步样式加载实现。
2021-03-25 00:02:37
确实很有趣。在这里,您等待 css 的结尾加载下一个,尽管一次性加载所有内容不是更有效吗?
2021-04-08 00:02:37

我最近有同样的需求,并编写了一个与 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 加载器的情况下作为全局函数工作。

我会说这是一种危险的滥用。CSS 也允许多行注释,因此从现有样式表复制粘贴样式时要小心。
2021-04-09 00:02:37
您使用多行注释的方法很有趣。我不确定它有多“好”,但它确实很有趣。
2021-04-13 00:02:37