Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

chrome extension inject dynamic css before dom is loaded

I'm building a chrome extension and I would like to inject dynamic (from a storage.sync.get) css into a webpage when the user visits that webpage. With my current implementation it technically works, however, the page loads, and after it has loaded it will inject the new css, which makes it look really slow. I'd like to have the css load in before the dom loads. Is that possible?

This is how I currently have it:

inject.js:

chrome.storage.sync.get("color", function(storedTheme) {
     $('.theme-wrap').removeClass('selected');
     $('.' + storedTheme.color).addClass('selected');
     path = chrome.extension.getURL("src/options/themes/" + storedTheme.color + ".css");
      $('<link/>', {
      rel: 'stylesheet',
      type: 'text/css',
      href: path
    }).appendTo('head');
});

and here is my manifest.json content_script information:

"content_scripts": [{
    "matches": ["http://*/*", "https://*/*"],
    "css": ["src/inject/inject.css", "src/inject/font-awesome.min.css"],
    "js": ["js/jquery/jquery.min.js", "src/inject/inject.js"],
    "run_at" : "document_end"
 }]

The src/inject/inject.css seems to load before the dom, which is exactly what I want, but I want it to work for the user-specified css file. Does anyone know how I can do this? Thank you

like image 461
Katie Avatar asked Apr 16 '16 19:04

Katie


1 Answers

You have defined "run_at": "document_end" in your manifest.json, which means inject.css is injected immediately after the DOM is complete, but before subresources like images and frames have loaded.

Take a look at run_at, you could set "run_at": "document_start", which means the files are injected after any files from css, but before any other DOM is constructed or any other script is run. However, in this case, if your asynchronous method (chrome.storage.sync.get) is executed fast enough, it can't get correct right result since the DOM is not constructed.

I would suggest you inject inject.css before the DOM is constructed, then listen to DOMContentLoaded event to execute your inject.js logic.

The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading.

manifest.json

"content_scripts": [{
    "matches": ["http://*/*", "https://*/*"],
    "css": ["src/inject/inject.css", "src/inject/font-awesome.min.css"],
    "js": ["js/jquery/jquery.min.js", "src/inject/inject.js"],
    "run_at" : "document_start"
 }]

inject.js

window.addEventListener("DOMContentLoaded", function() {
    chrome.storage.sync.get("color", function(storedTheme) {
        $('.theme-wrap').removeClass('selected');
        $('.' + storedTheme.color).addClass('selected');
        path = chrome.runtime.getURL("src/options/themes/" + storedTheme.color + ".css");
        $('<link/>', {
            rel: 'stylesheet',
            type: 'text/css',
            href: path
        }).appendTo('head');
    });
}, false);
like image 200
Haibara Ai Avatar answered Sep 22 '22 06:09

Haibara Ai