【问题标题】:Flickering during CSS injection in Chrome Extension在 Chrome 扩展中的 CSS 注入期间闪烁
【发布时间】:2015-12-28 20:57:46
【问题描述】:

我有一个插件,它通过注入 CSS 文件来完全改变网站的外观。它可以工作,但是在新外观出现之前的一瞬间,旧外观就在那里,因此每次加载页面时都会导致“闪烁”。新外观改变了背景颜色等,因此开关非常明显。 (我只在我的台式机上注意到这一点,而不是在我的笔记本电脑上。我不知道为什么,但其他用户也报告了这一点,也许更快的计算机使页面显示速度比注入 CSS 所需的速度更快?)。需要进行 CSS 注入,因此注入的 CSS 是最重要的(如上所示)。

我尝试过导致此问题的方法(之后的代码):

  1. 清单:确保 CSS 位于 web_accessible_resources
  2. 清单:直接在 content_scripts 中进行注入
  3. 清单:通过从 content_scripts 运行的 javascrip 来实现
  4. 清单:确保所有内容脚本都在 document_start 运行
  5. 清单:尝试从后台页面上运行的脚本运行注入
  6. JS 注入时机:为 DOMSubtreeModified 添加了事件监听器
  7. JS 注入时机:为 chrome.webNavigation.onCommitted 添加了事件监听器
  8. JS 注入时机:等待 document.head / document.body
  9. JS 注入方法:appendChild
  10. JS 注入方法:chrome.tabs.executeScript()
  11. JS 注入代码:链接元素链接到扩展中的 css 文件
  12. JS注入代码:直接执行javascript

代码示例:

清单:

{
  "manifest_version": 2,
  "name": "foo",
  "short_name": "bar",
  "description": "baz",
  "options_page": "options.html",
  "version": "2.1.1",
  "homepage_url": "http://google.com/",
  "permissions": ["storage", "*://google.com/*", "webNavigation", "tabs", "activeTab"],
  "browser_action": {
    "default_icon": "icon16.png",
    "default_title": "title",
    "default_popup": "popup.html"
  },
  "icons": {
    "16": "icon16.png",
    "48": "icon48.png",
    "128": "icon128.png"
  },
  "content_scripts": [
    {
      "matches": ["*://google.com/*"],
      "js": ["carbonicEditionScript.js"],
      "all_frames": true,
      "run_at": "document_start"
    }
  ],
  "background": {
    "page": "popup.html"
  },
  "web_accessible_resources": ["carbonicEditionStyle.css"]
}

carbonicEditionScript.js

document.addEventListener('DOMSubtreeModified', injectStyle, false);
function injectStyle(){
    document.removeEventListener('DOMSubtreeModified', injectStyle, false);
    var style = document.createElement('style');
    style.setAttribute("id", "CarbonicEditionStyle");
    style.setAttribute("class", "CarbonicEditionStyle");
    style.setAttribute("type", "text/css");
    style.appendChild(document.createTextNode(css));
    document.getElementsByTagName("html")[0].appendChild(style);
}

carbonicEditionScript替代.js

document.addEventListener('DOMSubtreeModified', injectCSS, false);
function injectCSS(){
var style = document.createElement('link');
style.rel = 'stylesheet';
style.type = 'text/css';
style.href = chrome.extension.getURL('carbonicEditionStyle.css');
if(document.head){
  document.removeEventListener('DOMSubtreeModified', injectCSS, false);
  (document.head||document.documentElement).appendChild(style);
}}

background.js

chrome.webNavigation.onCommitted.addListener(function(o) {
  chrome.tabs.executeScript(o.tabId, {
        code: "var css = 'body{background-color: green !important;}'; var style = document.createElement('style'); style.setAttribute('id', 'CarbonicEditionStyle'); style.setAttribute('class', 'CarbonicEditionStyle'); style.setAttribute('type', 'text/css'); style.appendChild(document.createTextNode(css)); document.getElementsByTagName('html')[0].appendChild(style);"
  });
}, {
  url: [{hostContains: 'google.com'}]
});

有人知道发生了什么吗?上述所有解决方案都有效,但闪烁仍在发生。

【问题讨论】:

    标签: javascript html css google-chrome-extension


    【解决方案1】:

    Stylish-chrome 扩展 fixed the flicker 只需使用 webNavigation.onCommited 事件,因此您应该已经能够解决问题。但是,由于您提到web_accessible_resources,您遇到的问题可能是由于从扩展包中异步读取css代码引起的。在这种情况下,将其缓存在 chrome.storage.localsessionStoragelocalStorage 中。或者考虑将 CSS 嵌入到您的内容脚本中。

    关于您发布的代码的一些 [可能是多余的] 注释:

    1. 不要使用 DOMSubtreeModified 事件,因为它 a) 实际上并不需要 - (您甚至可以在网页被解析之前注入元素)并且 b) 它是古老的/不推荐使用的/缓慢的/坏的。

      所以整个内容脚本可能是:

      var style = document.createElement('style');
      style.id = "CarbonicEditionStyle";
      style.className = "CarbonicEditionStyle";
      style.type = "text/css";
      style.textContent = "body{background-color: green !important;}";
      (document.body || document.head || document.documentElement).appendChild(style);
      
    2. executeScript 中使用runAt: "document_start",默认情况下它是document_idle,这通常仅在加载和解析DOM 时出现:

      chrome.tabs.executeScript(o.tabId, {runAt: "document_start", code: "......"});
      
    3. 考虑通过insertCSS 直接注入 CSS(实际上并不需要消除闪烁,它不会让您禁用注入的样式,但为了完整起见):

      chrome.tabs.insertCSS(o.tabId, {runAt: "document_start", code: "body{background....."});
      
    4. "matches": ["*://google.com/*"], 与默认使用的 www.google.com 不匹配,因此应为 "matches": ["*://*.google.com/*"],
    5. google.com 不是唯一的域,还有很多国际域。

    【讨论】:

    • 我已经尝试将 css 嵌入到内容脚本中。看看本地存储是否有所作为。
    • 1.上面提到的代码不会产生闪烁,但是它的插入速度非常快,以至于它是第一个要读取的 CSS,因此最不重要,这使得大多数 CSS 注入无用。由于站点已经在执行此操作,因此无法使用 !important 等更改注入的 CSS,而我无法控制。注入的 CSS 应该最后添加/读取,因此它具有优先权。 2. 看起来有道理,我看看能不能搞定,避免(1)4+5中的问题。修改了manifest中的url,这个可以忽略
    • 好吧,问题 1 听起来基本上是无法解决的,除非你用 webRequest 阻止实际的 CSS 文件。
    • @user1800592,这是一个单独的问题。我认为可以通过在将第一个元素添加到BODY 时将注入的STYLE 元素移动到HEAD 的末尾来解决。见an example。我仍然建议为此提出一个新问题。
    • @wOxxOm 你关于强制执行脚本到 runAt: "document_start" 的第二/第三篇文章已经成功了。
    猜你喜欢
    • 2012-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-02
    • 1970-01-01
    • 2021-07-05
    • 1970-01-01
    • 2013-10-12
    相关资源
    最近更新 更多