Google Chrome Extensions - Can't load local images with CSS - css

I have a simple Chrome extension that uses the content script feature to modify a website. More specifically, the background-image of said website.
For some reason I can't seem to be able to use local images, even though they are packed in the extension.
body {
background: #000 url('image.jpg') !important;
background-repeat: repeat !important;
}
That's it, the simplest CSS... but it won't work. The browser doesn't load the image.

Chrome has i18n support that provides the ability to reference your extension in your CSS. I keep my images in an image folder in the extension, so reference assets in the CSS like so:
background-image:url('chrome-extension://__MSG_##extension_id__/images/main.png');

Your image URL should look like chrome-extension://<EXTENSION_ID>/image.jpg
You would be better off replacing css through javascript. From docs:
//Code for displaying <extensionDir>/images/myimage.png:
var imgURL = chrome.extension.getURL("images/myimage.png");
document.getElementById("someImage").src = imgURL;

There are a lot of older answers and solutions to this question.
As of August 2015 (using Chrome 45 and Manifest version 2), the current "best practice" for linking to local images within Chrome Extensions is the following approach.
1) Link to the asset in your CSS using a relative path to your extension's images folder:
.selector {
background: url('chrome-extension://__MSG_##extension_id__/images/file.png');
}
2) Add the individual asset to to the web_accessible_resources section of your extension's manifest.json file:
"web_accessible_resources": [
"images/file.png"
]
Note: This method is suitable for a few files, but doesn't scale well with many files.
Instead, a better method is to leverage Chrome's support for match patterns to whitelist all files within a given directory:
{
"name": "Example Chrome Extension",
"version": "0.1",
"manifest_version": 2,
...
"web_accessible_resources": [
"images/*"
]
}
Using this approach will allow you to quickly and effortlessly use images in your Chrome Extension's CSS file using natively supported methods.

One option would be to convert your image to base64:
and then put the data right into your css like:
body { background-image: url(data:image/png;base64,iVB...); }
While this might not be an approach you would want to use when regularly developing a webpage, it is a great option due to some of the constraints of building a Chrome Extension.

My solution.
With Menifest v2 you need to add web_accessible_resources to the file and then use chrome-extension://__MSG_##extension_id__/images/pattern.png as the url in your css file.
CSS:
#selector {
background: #fff url('chrome-extension://__MSG_##extension_id__/images/pattern.png');
}
Manifest.json
{
"manifest_version": 2,
"name": "My Extension Name",
"description": "My Description",
"version": "1.0",
"content_scripts": [
{
"matches": ["https://mydomain.com/*"],
"css": ["style.css"]
}
],
"permissions": [
"https://mydomain.com/"
],
"browser_action": {
"default_icon": {
"19": "images/icon19.png",
"38": "images/icon38.png"
},
"default_title": "My Extension Name"
},
"web_accessible_resources": [
"images/pattern.png"
]
}
p.s. Your manifest.json might look different to this one.

This CSS-version-only works in extension environment (app page, popup page, background page, option page) as well as content_scripts CSS file.
In .less file, I always set a variable at the beginning:
#extensionId : ~"__MSG_##extension_id__";
Then later, if you want to refer to extension-local-resource like images, use:
.close{
background-image: url("chrome-extension://#{extensionId}/images/close.png");
}

One thing to mention is that in the web_accessible_resources you can use wildcards. So instead of
"images/pattern.png"
You can use
"images/*"

Just to clarify, according to the documentation, every file in an extension is also accessible by an absolute URL like this:
chrome-extension://<extensionID>/<pathToFile>
Note the <extensionID> is a unique identifier that the extension system generates for each extension. You can see the IDs for all your loaded extensions by going to the URL chrome://extensions. The <pathToFile> is the location of the file under the extension's top folder; it's the same as the relative URL.
...
Changing background image in CSS:
#id { background-image:
url("chrome-extension://<extensionID>/<pathToFile>"); }
Changing background image in CSS through JavaScript:
document.getElementById('id').style.backgroundImage =
"url('chrome-extension://<extensionID>/<pathToFile>')");
Changing background image in CSS through jQuery:
$("#id").css("background-image",
"url('chrome-extension://<extensionID>/<pathToFile>')");

For manifest v3, there are some modifications:
chrome.extension.getUrl() -> chrome.runtime.getUrl()
"web_accessible_resources" -> "web_accessible_resources.resources"
fill in "web_accessible_resources.matches"
2, 3 like this:
"web_accessible_resources": [{
"resources": ["images/logo.png"],
"matches": ["<all_urls>"],
}],
reference:
https://developer.chrome.com/docs/extensions/mv3/intro/mv3-migration/#web-accessible-resources

Those answers above are great but your extension gets a new id every time it gets installed, so putting the id manually doesn't work if you gonna make it public at some point.
Here's my solution using manifest v.3:
//Get the url from some file within your extension's folder and store it on a global variable
var url = chrome.runtime.getURL('my_extension/img/Icon.svg');
//Take off the last part from the url string
url = url.replace('img/Icon.svg', '');
Now replace the src attribute for a custom one on every img tag and keep the file path as it's value like this:
<img ref-file="img/IconStop.svg" alt="">
Then run this function after loading the html:
loadImgs = function () {
$("img[ref-file]").each(function() {
var ref_file = $(this).attr('ref-file');
url = url + ref_file;
$(this).attr('src', url);
});
}

Related

Is there a way to fetch colors stored from the Back End and place them in SCSS file

At the moment i'am currently re-factoring my code . So that means more clearness and higher maintance . I have an idea in my head , but unfortunately i don't know how this can be realeased.
In order to be more clean and effecient i want to create an isolated _colors.scss file that will contain all of my colors for the app . In other words i want it to look something like this
$colorPrimary: branding.colorPrimary,
$colorSecondary: branding.colorSecondary
...
At the moment is pretty messy because the color styling is maintened at the component level , but i want to do this seperately .
Ex:
<button style={
color: branding.colorPrimary,
background: branding.colorSecondary>
Hello
</button>
The colors are stored on the BE side so if i want to react them i have to do a call . I will be glad if someone can give me a hand with this mindf****. Thank you .
to acheive this behavior you have two main way to do it. the first one describe are not compatible with Internet Explorer.
On last CSS version describe on W3C we are able to have variable directly on CSS.
Like this backend can do something like this :
<head>
<style type="text/css">
:root {
--primary-color: #cecece;
--secondary-color: #fefefe;
}
</style>
</head>
then on your scss (or css) you can do something like :
.mySelector {
color: var(--primary-color, black);
}
which will be basically interpret as :
.mySelector {
color: #cecece;
}
Or fallback in color black if --primary-color is not defined.
As you can imagine, is very easy for backend to prepare the configuration for frontend. And from your side (as front end) you can simply use what is already available on CSS API tools.
But if you are looking for something which are compatible with IE. You probably need more complex infrastructure.
Goal is to spawn webpack sass compilation, on each User color change,
to build css output with relevant variable configuration.
for that you will need SaSS ressource loader which automatically inject sass file on all other file. Is like adding #import "_colors" automatically.
then backend server will have to :
Write _color.scss file somewhere (let say /user/123/_color.scss)
Ask for compilation like webpack client 123
read the output webpack folder for client 123 and detect if specific CSS exist
Inject on your head HTML.
For webpack configuration
on your webpack you will have something like :
const argv = require("yargs").argv;
entry: {
[...]
},
output: {
// Take the argument as clientId and craft dedicated output folder.
path: helpers.root(`public/themes/front/${argv.client}`),
filename: "[name].[contenthash].js",
chunkFilename: "[name].[contenthash].js"
}
Like this base on the client id you will store the outputed CSS on specific folder.
Finally the SaSS rules will looks like :
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'sass-loader',
{
loader: 'sass-resources-loader',
options: {
resources: (argv.client) ? `/user/${ argv.client }/_color.scss` : `/user/default/_color.scss`,
},
},
],
}

Custom background for Chrome new tab replacement extension

I'm developing a new tab replacement extension for Google Chrome and I'd like to allow the user to customize the background, to do so I'm using the storage.sync API as suggested by this page.
The problem is that the style changes are applied asynchronously, so the default background (white) is briefly used during the page load resulting in unpleasing flashes.
Possible (unsatisfying) solutions are:
do not allow to change the background;
hard code a black background in the CSS (and move the problem to custom light backgrounds);
use a CSS transition (still super-ugly).
What could be an alternative approach?
Follows a minimal example.
manifest.json
{
"manifest_version": 2,
"name": "Dummy",
"version": "0.1.0",
"chrome_url_overrides": {
"newtab": "newtab.html"
},
"permissions": [
"storage"
]
}
newtab.html
<script src="/newtab.js"></script>
newtab.js
chrome.storage.sync.get({background: 'black'}, ({background}) => {
document.body.style.background = background;
});
I come up with a reasonable solution. Basically since the localStorage API is synchronous we can use it as a cache for storage.sync.
Something like this:
newtab.js
// use the value from cache
document.body.style.background = localStorage.getItem('background') || 'black';
// update the cache if the value changes from the outside (will be used the next time)
chrome.storage.sync.get({background: 'black'}, ({background}) => {
localStorage.setItem('background', background);
});
// this represents the user changing the option
function setBackground(background) {
// save to storage.sync
chrome.storage.sync.set({background}, () => {
// TODO handle error
// update the cache
localStorage.setItem('background', background);
});
}
This doesn't work 100% of the times but neither do the simple:
document.body.style.background = 'black';
So it's good enough.¹
¹ In the real extension I change the CSS variables directly and I obtain much better results than setting the element style.

Using browser_action to apply css styling

I am new to chrome extension development. I am writing a chrome extension that will inject CSS into the page. I've been successful in doing this by specifying the css file in manifest.json.
I now want to apply different css (files) depending on a link or button selected on a popup triggered through a browser_action. So clicking link 1 will apply style-red.css and clicking link 2 will apply style-blue.css. A third "reset" button should reset css back to its original state (removing the custom style red or blue css files).
My manifest.json is as follows:
{
"name": "Redesign",
"version": "1.0",
"manifest_version": 2,
"content_scripts": [
{
"matches": ["*://*.my-site.com/*"],
"js": ["jquery-3.1.0.min.js", "script.js"]
}
],
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"tabs", "*://*.my-site.com/*"
]
}
My current approach is to have a listener in script.js listening for the button pressed in popup.html. Depending on the button pressed, the following script.js will add the corresponding CSS file into my-site.com using the jquery below:
$(document).ready(function() {
var path = chrome.extension.getURL('style-red.css');
$('head').append($('<link>')
.attr("rel","stylesheet")
.attr("type","text/css")
.attr("href", path));
});
I tried to use the above jquery in script.js (without the browser_action in the manifest.json) thinking script.js will get automatically loaded but the CSS does not get applied to my-site.com. What am I doing wrong or is there simpler Javascript without the need for a full jquery library to be added?
And even if the jquery works, how do I apply a different CSS file based on the choice in popup.html as well as reset the css back to its original styling upon user choice?
To insert css file in content scripts, you need to declare the css file as web_accessible_resources
To dynamically insert css files, see chrome.tabs.insertCSS, it can be called in extension context, such as popup page.

Firefox Extension - including CSS in manifest.json

My manifest is not working when I add CSS into it, while it works in Chrome Extension when I do like that.
Here how my manifest looks:
"css": ["css/jquery-ui.css", "css/font-awesome.css", "css/simplegrid.css", "css/basic.css"],
"js": ["jquery.js", "jquery-ui.js", "myPeaceFile.js"],
myPeaceFile.js works, jquery's are working. But CSS files are not.
I previously asked question about jquery's not working. It looked like this:
"js": ["peace.js", "jquery.js"] - didn't work.
Then I was suggested this and it worked:
"js": ["jquery.js", "peace.js"]
Is it something similar? Please help.
Thanks!
You can attach CSS to pages using Style, in your main.js define a style and attach this style to the contentscript.
var { Style } = require('sdk/stylesheet/style');
var style = Style({
uri: './bootstrap.css'
});
tabs.on('ready', function(tab) {
let worker = tab.attach({
contentScriptFile: [
data.url("jquery.min.js"),
data.url("jquery-ui/jquery-ui.min.js"),
data.url("mycontent-script.js"),
]
});
attach(style, tab);
});
At the Style constructor in the second line you can pass a string, or an array of strings, that represents local URI to stylesheet. In this case the ./bootstrap.css is in the data folder of the extension.

CSS content script issue in Google Chrome extension

I am creating a simple Chrome extension that blocks the "Google" logo image on the Google homepage using a content script. I followed the directions on the content-script page, but it still does not seem to be working. Can anyone spot what I'm doing wrong?
EDIT: I have tested it with other website like flickr.com and it works perfectly. I've also searched through the Google homepage CSS and cannot figure out which CSS rule is overriding my CSS. Any ideas? How can I make a stronger CSS injection so that no other CSS can override mine?
manifest.json:
{
"manifest_version": 2,
"name": "Google Logo Blocker",
"description": "This extension blocks the Google logo image.",
"version": "1.0",
"content_scripts": [
{
"matches": ["http://www.google.com/"],
"css": ["blocker.css"]
}
],
"browser_action": {
"default_icon": "icon.png"
}
}
blocker.css:
img {
display: none !important;
}
Your code works for me. You are using straight USA Google, not an international version, right?
Just in case, change your matches to:
"matches": ["http://*.google.com/", "https://*.google.com/"],
And target the logo more directly. This will work in most cases:
#hplogo {
display: none !important;
}
For full-on, international Google support, change the content_scripts portion of your manifest to:
"content_scripts": [ {
"matches": ["http://*/*", "https://*/*"],
"include_globs": ["http://*.google.*/*", "https://*.google.*/*"],
"css": ["blocker.css"]
} ],
Optionally also using exclude_matches and/or exclude_globs as desired.
If it still doesn't work, state the usual:
Exact URL
Chrome version
OS
Other extensions active
It is <img> tag in modern version and is a <div> tag with background image for international version. Regardless, of the differences they bear same id = hplogo, so this can work for you.
Click for Larger Image
Use
#hplogo{
display:none !important;
}
it will remove google Logo.

Resources