You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Manifest V3 Chrome扩展:后台注入内容脚本及关联CSS方法

Chrome扩展MV3整段CSS注入实现方案

问题背景

开发Manifest V3版本Chrome扩展时,需要在页面加载完成后自动注入内容脚本,生成圆形悬浮按钮。现有逻辑已通过后台service worker监听标签页更新事件,在页面加载完成时自动注入JS内容脚本,但无法将包含外部字体引入、自定义类样式的多段CSS随脚本一同注入。此前误以为insertCSS()API仅支持注入单行少量样式,查阅文档未找到多段CSS注入方案。
现有初始代码如下:

  • 后台脚本(background.js)
//BACKGROUND
try {
    chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
        if(changeInfo.status == 'complete') {
            chrome.scripting.executeScript({
                files: ['content-script.js'],
                target: {tabId: tab.id}
            });
        }
    });
} catch (e) {
    console.log(e);
}
  • 内容脚本(content-script.js)
//CONTENT-SCRIPT (in another file, wasn't sure how to add it to the question
if (typeof init === 'undefined') {
    const init = function() {
        const injectElement = document.createElement("button");
        injectElement.className = 'button_attempt';
        injectElement.innerHTML = "T";
        document.body.appendChild(injectElement);
    }
    init();
}
  • 待注入CSS样式
//CSS
@import url('https://fonts.googleapis.com/css2?family=Prociono&family=Sorts+Mill+Goudy&display=swap');

@font-face {
    font-family: 'Goudy Bookletter 1911';
    font-style: normal;
    font-weight: 400;
    src: url(https://fonts.gstatic.com/s/goudybookletter1911/v13/sykt-z54laciWfKv-kX8krex0jDiD2HbY6IJshzW.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212,  U+2215, U+FEFF, U+FFFD;
}

.button_attempt {
      background-image: url(icon.png);
      width: 2.5rem;
      height: 2.5rem;
      font-family: 'Goudy Bookletter 1911';
      font-size: 1.25rem;
      color: white;
      background-color: #A485C7;
      cursor: pointer;
      border: 2px solid #D0B3F1;
      border-radius: 50%;
      position: absolute;
      top: 0;
      left: 0;
      z-index: 10;
      /*display: none;*/
      transition: color 0.2s, background-color 0.2s ease-in-out;
}

.button_attempt:hover {
      color: #A485C7;
      background-color: white;
}
  • 清单文件(manifest.json)
//MANIFEST
{
"name" : "Practice",
"version" : "1.0.0",
"manifest_version" : 3,
"background" : {
    "service_worker": "background.js"
},
"permissions" : ["scripting"],
"host_permissions": ["<all_urls>"]
}

可落地方案

chrome.scripting.insertCSS()本身支持直接注入独立CSS文件,不存在仅能注入单行样式的限制,和executeScript注入JS文件逻辑一致,通过files参数指定扩展内的CSS文件路径即可完成整段样式注入。

方案一:通过insertCSS注入独立CSS文件(推荐)

  1. 将待注入的CSS代码保存为扩展根目录下的content-style.css文件,注意删除CSS文件中的//开头单行注释(原生CSS仅支持/* */格式块注释,单行注释会导致后续样式解析失效),同时建议将按钮定位改为fixed、z-index设为较高值,避免按钮随页面滚动、被页面元素遮挡。
    修正后的CSS文件内容:
@import url('https://fonts.googleapis.com/css2?family=Prociono&family=Sorts+Mill+Goudy&display=swap');

@font-face {
    font-family: 'Goudy Bookletter 1911';
    font-style: normal;
    font-weight: 400;
    src: url(https://fonts.gstatic.com/s/goudybookletter1911/v13/sykt-z54laciWfKv-kX8krex0jDiD2HbY6IJshzW.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212,  U+2215, U+FEFF, U+FFFD;
}

.button_attempt {
      background-image: url(icon.png);
      width: 2.5rem;
      height: 2.5rem;
      font-family: 'Goudy Bookletter 1911';
      font-size: 1.25rem;
      color: white;
      background-color: #A485C7;
      cursor: pointer;
      border: 2px solid #D0B3F1;
      border-radius: 50%;
      position: fixed;
      top: 20px;
      left: 20px;
      z-index: 99999;
      transition: color 0.2s, background-color 0.2s ease-in-out;
}

.button_attempt:hover {
      color: #A485C7;
      background-color: white;
}
  1. 修改后台脚本background.js,在注入JS内容脚本前先注入CSS文件,同时增加页面协议过滤,避免在chrome://等禁止注入的内置页面报错:
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    if(changeInfo.status === 'complete' && tab.url?.startsWith('http')) {
        // 先注入CSS文件
        chrome.scripting.insertCSS({
            files: ['content-style.css'],
            target: {tabId: tab.id}
        }).then(() => {
            // CSS注入完成后再注入JS脚本
            chrome.scripting.executeScript({
                files: ['content-script.js'],
                target: {tabId: tab.id}
            });
        }).catch(err => console.log('资源注入失败:', err));
    }
});
  1. 修正原内容脚本的重复注入判断逻辑:原代码中init为块级作用域const变量,外层无法访问,会导致每次脚本执行都重复注入按钮,改为全局标记判断更稳妥,修正后的content-script.js:
if (!window.extFloatButtonInjected) {
    window.extFloatButtonInjected = true;
    const injectElement = document.createElement("button");
    injectElement.className = 'button_attempt';
    injectElement.innerHTML = "T";
    document.body.appendChild(injectElement);
}

方案二:在内容脚本中动态插入style标签

如果不想单独维护CSS文件,也可以直接在内容脚本中创建style标签,将所有CSS代码作为文本内容插入页面head,不需要调用insertCSSAPI,示例代码:

if (!window.extFloatButtonInjected) {
    window.extFloatButtonInjected = true;
    // 插入样式
    const styleNode = document.createElement('style');
    styleNode.textContent = `
    @import url('https://fonts.googleapis.com/css2?family=Prociono&family=Sorts+Mill+Goudy&display=swap');
    @font-face {
        font-family: 'Goudy Bookletter 1911';
        font-style: normal;
        font-weight: 400;
        src: url(https://fonts.gstatic.com/s/goudybookletter1911/v13/sykt-z54laciWfKv-kX8krex0jDiD2HbY6IJshzW.woff2) format('woff2');
        unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212,  U+2215, U+FEFF, U+FFFD;
    }
    .button_attempt {
          background-image: url(icon.png);
          width: 2.5rem;
          height: 2.5rem;
          font-family: 'Goudy Bookletter 1911';
          font-size: 1.25rem;
          color: white;
          background-color: #A485C7;
          cursor: pointer;
          border: 2px solid #D0B3F1;
          border-radius: 50%;
          position: fixed;
          top: 20px;
          left: 20px;
          z-index: 99999;
          transition: color 0.2s, background-color 0.2s ease-in-out;
    }
    .button_attempt:hover {
          color: #A485C7;
          background-color: white;
    }
    `;
    document.head.appendChild(styleNode);
    // 插入按钮
    const injectElement = document.createElement("button");
    injectElement.className = 'button_attempt';
    injectElement.innerHTML = "T";
    document.body.appendChild(injectElement);
}

这种方式下后台脚本不需要修改注入逻辑,保持原有注入content-script.js的代码即可。

注意事项

  • 现有manifest配置已满足注入要求,不需要额外新增权限。
  • 如果CSS中引用了扩展本地资源(如示例中的icon.png),建议将图片转为base64格式嵌入CSS,或在manifest中配置web_accessible_resources暴露资源路径,避免出现跨域加载失败问题。
  • 不要在浏览器内置页面、扩展商店页面尝试注入脚本,这类页面有安全限制,会直接抛出注入错误。

内容的提问来源于stack exchange,提问作者cheese-berry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 02:33:44