Inject CSS stylesheet as string using Javascript - javascript

I'm developing a Chrome extension, and I'd like users to be able to add their own CSS styles to change the appearance of the extension's pages (not web pages). I've looked into using document.stylesheets, but it seems like it wants the rules to be split up, and won't let you inject a complete stylesheet. Is there a solution that would let me use a string to create a new stylesheet on a page?
I'm currently not using jQuery or similar, so pure Javascript solutions would be preferable.

There are a couple of ways this could be done, but the simplest approach is to create a <style> element, set its textContent property, and append to the page’s <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;
}
`);
If you want, you could change this slightly so the CSS is replaced when addStyle() is called instead of appending it.
/**
* 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 edit: Be aware that IE9 and below only allows up to 32 stylesheets, so watch out when using the first snippet. The number was increased to 4095 in IE10.
2020 edit: This question is very old but I still get occasional notifications about it so I’ve updated the code to be slightly more modern and replaced .innerHTML with .textContent. This particular instance is safe, but avoiding innerHTML where possible is a good practice since it can be an XSS attack vector.

Thanks to this guy, I was able to find the correct answer. Here's how it's done:
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)};
fiddle

Have you ever heard of Promises? They work on all modern browsers and are relatively simple to use. Have a look at this simple method to inject css to the 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);
});
}
You can implement it as follows:
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));
}
It's really cool, right? This is a way to decide the priority of the styles using Promises.
Or, if you want to import all styles at the same time, you can do something like this:
function loadStyles(srcs) {
let promises = [];
srcs.forEach(src => promises.push(loadStyle(src)));
return Promise.all(promises);
}
Use it like this:
loadStyles([
'css/style.css',
'css/icomoon.css'
]);
You can implement your own methods, such as importing scripts on priorities, importing scripts simultaneously or importing styles and scripts simultaneously. If i get more votes, i'll publish my implementation.
If you want to learn more about Promises, read more here

I had this same need recently and wrote a function to do the same as Liam's, except to also allow for multiple lines of 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; } ');
The source of this function. You can download from the Github repo. Or see some more example usage here.
My preference is to use it with RequireJS, but it also will work as a global function in the absence of an AMD loader.

I think the easiest way to inject any HTML string is via: insertAdjacentHTML
// append style block in <head>
const someStyle = `
<style>
#someElement { color: green; }
</style>
`;
document.head.insertAdjacentHTML('beforeend', someStyle);

Create a style tag and add the css styles into the textContent property as a string. Append these in the document head. Boom you are good to go.
var styles = document.createElement("style");
styles.setAttribute("type", "text/css");
styles.textContent = `#app{background-color:lightblue;}`;
document.head.appendChild(styles);

Related

Change h1 tag's color globally using javascript

I'm trying to implement a dark mode that activates according to the current time.
That's how I change the body's background color:
if (darkMode) {
document.body.style.backgroundColor = '#31403E';
} else {
document.body.style.backgroundColor = '#F2EDE4';
}
Can I change the h1 tag's color in some kind of global way? Or do I have to check for the property darkMode in every single doc and then assign the proper color.
In modern JavaScript, it could be:
const elements = document.querySelectorAll('h1')
Array.from(elements).forEach(el => el.style.color = '#31403E')
Hope this helps.
You can define a custom CSS stylesheet for dark mode:
#media (prefers-color-scheme: dark) {
color: white;
background: black
}
Where you can define your custom rules accordingly.
There's a nice trick about using filter as well that you can read a bit further over here
You can see this example over here:
https://codepen.io/rikschennink/pen/GLMLj
Where a class .dark-mode is set to the HTML document when toggling using
html.dark-mode {
filter: invert(100%);
img {
filter: invert(100%);
}
}
Docs
first of all they added dark mode preferences in css, they work like so:
#media (prefers-color-scheme: dark) {
h1 {
color: white;
}
}
but a common workaround to this back when we were developing theme switches was adding a "dark" class to the body and doing the following in css
body.dark h1 {
color: white;
}
IF YOU HAVE TO DO IT WITH JAVASCRIPT you have to loop through each and every h1's in the DOM, but it wont work on newly made h1s using javascript since it'll run on page load only as is.
let h1s = document.querySelectorAll("h1"); //gets all the h1s in the page
h1s.forEach( h1 => h1.style.color = "white");
With javascript you can do it like this:
var elements = document.getElementsByTagName("h1");
for(var i = 0; i < elements.length; i++) {
elements[i].style.color = "#000";
}

Clone, Play and Replace the Cloned Dom - Javascript / Jquery

I'm trying to export the whole page as PDF. During certain situation's like, if the CSS is loaded from separate file is not applied in exported PDF. So I'm trying to convert all CSS as inline using this code.
(function ($) {
var rules = document.styleSheets;
for(var rl in rules){
var rule = rules[rl].cssRules;
try{
for (var idx = 0, len = rule.length; idx < len; idx++) {
$(rule[idx].selectorText).each(function (i, elem) {
if($(elem).is(":visible"))
elem.style.cssText += rule[idx].style.cssText;
});
}
}catch(e){
console.log(e);
}
}
})(jQuery);
After I ran this code, my exported PDF is working good. But my DOM is not as before. So is there anyway where I can clone my DOM before operations, and replace the cloned DOM as before after playing with DOM. Hope my question is clear. Thanks in anticipation for the help.
In this Snippet there are 2 much more simpler ways than modifying a stylesheet:
Isolate the <iframe>,<embed>, or <object> by wrapping an element around it then apply styles referencing the wrapper element. This is demonstrated in the Snippet with div.jframe as the wrapper.
Inject a <style> block with new rulesets.
If either one is done with moderate care, you shouldn't be left with conflicting styles.
Note: The PDF in the iframe is sandboxed, so it's not there but everything still applies.
SNIPPET
function injectStyles(rule) {
document.body.insertAdjacentHTML('afterbegin',
'­<style>' + rule + '</style>');
}
injectStyles('iframe:hover { border: 5px solid blue; }');
.jframe iframe {
outline: 10px solid tomato;
}
<div class='jframe'>
<iframe src='http://che.org.il/wp-content/uploads/2016/12/pdf-sample.pdf' height='400' width='400'></iframe>
</div>

How to read less variables in Javascript?

I am working on a project that all of the less variables are compiled to Css by Maven. There is lots of variables for colours in the less file. I want to have access to these colour variables from javascript. In that case I can define the colours once and use it in css and javascript.
Could anyone please help me with introducing a Maven plugin or a method to read the less variables in Javascript?
Here is a code snippet explaining how to access less variables in JavaScript
// getLessVars :: https://gist.github.com/2948738
/**
* getLessVars parses your LESS variables to Javascript (provided you make a dummy node in LESS)
* #param {String} id The CSS-id your variables are listed under.
* #param {Boolean} [parseNumbers=true] Try to parse units as numbers.
* #return {Object} A value object containing your LESS variables.
* #example
* LESS:
* #myLessVariable: 123px;
* #dummyLessId { width: #myLessVariable; }
* Javascript:
* getLessVars('dummyLessId');
* returns:
* {myLessVariable:123}
*/
function getLessVars(id,parseNumbers) {
var bNumbers = parseNumbers===undefined?true:parseNumbers
,oLess = {}
,rgId = /\#[\w-]+/
,rgKey = /\.([\w-]+)/
,rgUnit = /[a-z]+$/
,aUnits = 'em,ex,ch,rem,vw,vh,vmin,cm,mm,in,pt,pc,px,deg,grad,rad,turn,s,ms,Hz,kHz,dpi,dpcm,dppx'.split(',')
,rgValue = /:\s?(.*)\s?;\s?\}/
,rgStr = /^'([^']+)'$/
,sId = '#'+id
,oStyles = document.styleSheets;
for (var i=0,l=oStyles.length;i<l;i++) {
var oRules;
try{ oRules = oStyles[i].cssRules; }
catch (e) { continue; }
if (oRules) {
for (var j=0,k=oRules.length;j<k;j++) {
try { var sRule = oRules[j].cssText; }
catch (e) { continue; }
var aMatchId = sRule.match(rgId);
if (aMatchId&&aMatchId[0]==sId) {
var aKey = sRule.match(rgKey)
,aVal = sRule.match(rgValue);
if (aKey&&aVal) {
var sKey = aKey[1]
,oVal = aVal[1]
,aUnit
,aStr;
if (bNumbers&&(aUnit=oVal.match(rgUnit))&&aUnits.indexOf(aUnit[0])!==-1) {
oVal = parseFloat(oVal);
} else if (aStr=oVal.match(rgStr)) {
oVal = aStr[1];
}
oLess[sKey] = oVal;
}
}
}
}
}
return oLess;
}
// parse less
less.refresh();
// read variables from id #foobar
var oVars = getLessVars('foobar'),
mPre = document.createElement('pre'),
sData = "\n";
for (var s in oVars) sData += "\t" + s + ': ' + oVars[s] + "\n";
mPre.innerHTML = sData;
document.body.appendChild(mPre);
<script src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js"></script>
<html><head>
<style type="text/less">
// less variables
#myWidth: 200px;
#myPadding: 5px;
#myBorderColor: #666;
// add variables as classes to a non-existing id
#foobar {
.myWidth { width: #myWidth; }
.myPadding { width: #myPadding; }
.myBorderColor { color: #myBorderColor; }
}
// variables usage
div {
width: #myWidth;
padding: #myPadding;
border: 2px solid #myBorderColor;
}
</style>
</head><body>
<div>this div uses the following less properties:</div>
</body></html>
You can also refer https://gist.github.com/Sjeiti/2948738
Less can be used on the client as well. Reading from their documentation:
Client-side Usage
Using less.js in the browser is great for development, but it's not recommended for production
Client-side is the easiest way to get started and good for developing with Less, but in production, when performance and reliability is important, we recommend pre-compiling using node.js or one of the many third party tools available.
To start off, link your .less stylesheets with the rel attribute set to "stylesheet/less":
<link rel="stylesheet/less" type="text/css" href="styles.less" />
Next, download less.js and include it in a tag in the element of your page:
Tips
Make sure you include your stylesheets before the script.
When you link more than one .less stylesheet each of them is compiled independently. So any variables, mixins or namespaces you define in a stylesheet are not accessible in any other.
Due to the same origin policy of browsers loading external resources requires enabling CORS
Less CDN
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js"></script>
Defined variables can be found in less data or trough less.Parser or various API.
For some Parser sample see: get variables values

How do you add CSS with Javascript?

How do you add CSS rules (eg strong { color: red }) by use of Javascript?
The simple-and-direct approach is to create and add a new style node to the document.
// Your CSS as text
var styles = `
.qwebirc-qui .ircwindow div {
font-family: Georgia,Cambria,"Times New Roman",Times,serif;
margin: 26px auto 0 auto;
max-width: 650px;
}
.qwebirc-qui .lines {
font-size: 18px;
line-height: 1.58;
letter-spacing: -.004em;
}
.qwebirc-qui .nicklist a {
margin: 6px;
}
`
var styleSheet = document.createElement("style")
styleSheet.innerText = styles
document.head.appendChild(styleSheet)
You can also do this using DOM Level 2 CSS interfaces (MDN):
var sheet = window.document.styleSheets[0];
sheet.insertRule('strong { color: red; }', sheet.cssRules.length);
...on all but (naturally) IE8 and prior, which uses its own marginally-different wording:
sheet.addRule('strong', 'color: red;', -1);
There is a theoretical advantage in this compared to the createElement-set-innerHTML method, in that you don't have to worry about putting special HTML characters in the innerHTML, but in practice style elements are CDATA in legacy HTML, and ‘<’ and ‘&’ are rarely used in stylesheets anyway.
You do need a stylesheet in place before you can started appending to it like this. That can be any existing active stylesheet: external, embedded or empty, it doesn't matter. If there isn't one, the only standard way to create it at the moment is with createElement.
Shortest One Liner
// One liner function:
const addCSS = css => document.head.appendChild(document.createElement("style")).innerHTML=css;
// Usage:
addCSS("body{ background:red; }")
The solution by Ben Blank wouldn't work in IE8 for me.
However this did work in IE8
function addCss(cssCode) {
var styleElement = document.createElement("style");
styleElement.type = "text/css";
if (styleElement.styleSheet) {
styleElement.styleSheet.cssText = cssCode;
} else {
styleElement.appendChild(document.createTextNode(cssCode));
}
document.getElementsByTagName("head")[0].appendChild(styleElement);
}
Here's a slightly updated version of Chris Herring's solution, taking into account that you can use innerHTML as well instead of a creating a new text node:
function insertCss( code ) {
var style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet) {
// IE
style.styleSheet.cssText = code;
} else {
// Other browsers
style.innerHTML = code;
}
document.getElementsByTagName("head")[0].appendChild( style );
}
You can add classes or style attributes on an element by element basis.
For example:
<a name="myelement" onclick="this.style.color='#FF0';">text</a>
Where you could do this.style.background, this.style.font-size, etc. You can also apply a style using this same method ala
this.className='classname';
If you want to do this in a javascript function, you can use getElementByID rather than 'this'.
This easy example of add <style> in head of html
var sheet = document.createElement('style');
sheet.innerHTML = "table th{padding-bottom: 0 !important;padding-top: 0 !important;}\n"
+ "table ul { margin-top: 0 !important; margin-bottom: 0 !important;}\n"
+ "table td{padding-bottom: 0 !important;padding-top: 0 !important;}\n"
+ ".messages.error{display:none !important;}\n"
+ ".messages.status{display:none !important;} ";
document.body.appendChild(sheet); // append in body
document.head.appendChild(sheet); // append in head
Source Dynamic style - manipulating CSS with JavaScript
This is my solution to add a css rule at the end of the last style sheet list:
var css = new function()
{
function addStyleSheet()
{
let head = document.head;
let style = document.createElement("style");
head.appendChild(style);
}
this.insert = function(rule)
{
if(document.styleSheets.length == 0) { addStyleSheet(); }
let sheet = document.styleSheets[document.styleSheets.length - 1];
let rules = sheet.rules;
sheet.insertRule(rule, rules.length);
}
}
css.insert("body { background-color: red }");
YUI just recently added a utility specifically for this. See stylesheet.js here.
In modern browsers, you can use document.adoptedStyleSheets to add CSS.
const sheet = new CSSStyleSheet();
sheet.replace("strong { color: red; }");
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
One advantage of this approach is that you do not have to wait for the <head> element to even become available, which may be a concern in browser extension code that runs very early.
if you know at least one <style> tag exist in page , use this function :
CSS=function(i){document.getElementsByTagName('style')[0].innerHTML+=i};
usage :
CSS("div{background:#00F}");
Another option is to use JQuery to store the element's in-line style property, append to it, and to then update the element's style property with the new values. As follows:
function appendCSSToElement(element, CssProperties)
{
var existingCSS = $(element).attr("style");
if(existingCSS == undefined) existingCSS = "";
$.each(CssProperties, function(key,value)
{
existingCSS += " " + key + ": " + value + ";";
});
$(element).attr("style", existingCSS);
return $(element);
}
And then execute it with the new CSS attributes as an object.
appendCSSToElement("#ElementID", { "color": "white", "background-color": "green", "font-weight": "bold" });
This may not necessarily be the most efficient method (I'm open to suggestions on how to improve this. :) ), but it definitely works.
Here's a sample template to help you get started
Requires 0 libraries and uses only javascript to inject both HTML and CSS.
The function was borrowed from the user #Husky above
Useful if you want to run a tampermonkey script and wanted to add a toggle overlay on a website (e.g. a note app for instance)
// INJECTING THE HTML
document.querySelector('body').innerHTML += '<div id="injection">Hello World</div>';
// CSS INJECTION FUNCTION
//https://stackoverflow.com/questions/707565/how-do-you-add-css-with-javascript
function insertCss( code ) {
var style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet) {
// IE
style.styleSheet.cssText = code;
} else {
// Other browsers
style.innerHTML = code;
}
document.getElementsByTagName("head")[0].appendChild( style );
}
// INJECT THE CSS INTO FUNCTION
// Write the css as you normally would... but treat it as strings and concatenate for multilines
insertCss(
"#injection {color :red; font-size: 30px;}" +
"body {background-color: lightblue;}"
)
Here's my general-purpose function which parametrizes the CSS selector and rules, and optionally takes in a css filename (case-sensitive) if you wish to add to a particular sheet instead (otherwise, if you don't provide a CSS filename, it will create a new style element and append it to the existing head. It will make at most one new style element and re-use it on future function calls). Works with FF, Chrome, and IE9+ (maybe earlier too, untested).
function addCssRules(selector, rules, /*Optional*/ sheetName) {
// We want the last sheet so that rules are not overridden.
var styleSheet = document.styleSheets[document.styleSheets.length - 1];
if (sheetName) {
for (var i in document.styleSheets) {
if (document.styleSheets[i].href && document.styleSheets[i].href.indexOf(sheetName) > -1) {
styleSheet = document.styleSheets[i];
break;
}
}
}
if (typeof styleSheet === 'undefined' || styleSheet === null) {
var styleElement = document.createElement("style");
styleElement.type = "text/css";
document.head.appendChild(styleElement);
styleSheet = styleElement.sheet;
}
if (styleSheet) {
if (styleSheet.insertRule)
styleSheet.insertRule(selector + ' {' + rules + '}', styleSheet.cssRules.length);
else if (styleSheet.addRule)
styleSheet.addRule(selector, rules);
}
}
I always forget how to add a class to an HTML element and this SO comes up early in Google, but no one has added the modern way of doing this so here goes.
To add a CSS style you can select the element and call .classList.add(<className>)
for example:
document.querySelector("#main").classList.add("bg-primary");
You may also need to remove other class(es) which clash with the one you add. To do so:
document.querySelector("#main").classList.remove("bg-secondary");
That's it. Run the sample and you'll see the setInterval() method add & remove the styles every 3 seconds.
let useSecondary = false;
setInterval(changeBgColor, 3000);
function changeBgColor(){
if (useSecondary){
document.querySelector("#main").classList.remove("bg-primary");
document.querySelector("#main").classList.add("bg-secondary");
}
else{
document.querySelector("#main").classList.remove("bg-secondary");
document.querySelector("#main").classList.add("bg-primary");
}
useSecondary = !useSecondary;
}
* {
transition: all 0.5s ease-in-out;
}
.bg-primary {
background-color: green;
}
.bg-secondary{
background-color: yellow;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div >
<div id="main" >
Example text has background color changed every 3 seconds by adding / removing CSS styles.
</div>
</div>
</body>
</html>
use .css in Jquery like $('strong').css('background','red');
$('strong').css('background','red');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<strong> Example
</strong>

How to create a <style> tag with Javascript?

I'm looking for a way to insert a <style> tag into an HTML page with JavaScript.
The best way I found so far:
var divNode = document.createElement("div");
divNode.innerHTML = "<br><style>h1 { background: red; }</style>";
document.body.appendChild(divNode);
This works in Firefox, Opera and Internet Explorer but not in Google Chrome. Also it's a bit ugly with the <br> in front for IE.
Does anyone know of a way to create a <style> tag that
Is nicer
Works with Chrome?
Or maybe
This is a non-standard thing I should avoid
Three working browsers are great and who uses Chrome anyway?
Try adding the style element to the head rather than the body.
This was tested in IE (7-9), Firefox, Opera and Chrome:
var css = 'h1 { background: red; }',
head = document.head || document.getElementsByTagName('head')[0],
style = document.createElement('style');
head.appendChild(style);
style.type = 'text/css';
if (style.styleSheet){
// This is required for IE8 and below.
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
<style> tags should be placed within the <head> element, and each added tag should be added to the bottom of the <head> tag.
Using insertAdjacentHTML to inject a style tag into the document head tag:
Native DOM:
document.head.insertAdjacentHTML("beforeend", `<style>body{background:red}</style>`)
jQuery:
$('<style>').text("body{background:red}").appendTo(document.head)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I'm assuming that you're wanting to insert a style tag versus a link tag (referencing an external CSS), so that's what the following example does:
<html>
<head>
<title>Example Page</title>
</head>
<body>
<span>
This is styled dynamically via JavaScript.
</span>
</body>
<script type="text/javascript">
var styleNode = document.createElement('style');
styleNode.type = "text/css";
// browser detection (based on prototype.js)
if(!!(window.attachEvent && !window.opera)) {
styleNode.styleSheet.cssText = 'span { color: rgb(255, 0, 0); }';
} else {
var styleText = document.createTextNode('span { color: rgb(255, 0, 0); } ');
styleNode.appendChild(styleText);
}
document.getElementsByTagName('head')[0].appendChild(styleNode);
</script>
</html>
Also, I noticed in your question that you are using innerHTML. This is actually a non-standard way of inserting data into a page. The best practice is to create a text node and append it to another element node.
With respect to your final question, you're going to hear some people say that your work should work across all of the browsers. It all depends on your audience. If no one in your audience is using Chrome, then don't sweat it; however, if you're looking to reach the biggest audience possible, then it's best to support all major A-grade browsers
Here's a script which adds IE-style createStyleSheet() and addRule() methods to browsers which don't have them:
if(typeof document.createStyleSheet === 'undefined') {
document.createStyleSheet = (function() {
function createStyleSheet(href) {
if(typeof href !== 'undefined') {
var element = document.createElement('link');
element.type = 'text/css';
element.rel = 'stylesheet';
element.href = href;
}
else {
var element = document.createElement('style');
element.type = 'text/css';
}
document.getElementsByTagName('head')[0].appendChild(element);
var sheet = document.styleSheets[document.styleSheets.length - 1];
if(typeof sheet.addRule === 'undefined')
sheet.addRule = addRule;
if(typeof sheet.removeRule === 'undefined')
sheet.removeRule = sheet.deleteRule;
return sheet;
}
function addRule(selectorText, cssText, index) {
if(typeof index === 'undefined')
index = this.cssRules.length;
this.insertRule(selectorText + ' {' + cssText + '}', index);
}
return createStyleSheet;
})();
}
You can add external files via
document.createStyleSheet('foo.css');
and dynamically create rules via
var sheet = document.createStyleSheet();
sheet.addRule('h1', 'background: red;');
An example that works and are compliant with all browsers :
var ss = document.createElement("link");
ss.type = "text/css";
ss.rel = "stylesheet";
ss.href = "style.css";
document.getElementsByTagName("head")[0].appendChild(ss);
const style = document.createElement("style")
style.textContent = "h1 { background-color: red; }"
document.head.appendChild(style)
The Modern & Easy Way
The code above is the gist of it; continue reading if you want to know the reasoning.
Why another answer? The accepted answer is old and includes redundant code for outdated browsers like the Internet Explorer. Other answers are unnecessarily complex or use properties like .innerHTML that allow for cross-site scripting attacks.
The type property is not needed
Most of the anwsers set the type property like so: style.type = "text/css". Setting this property is not necessary unless you need to support older browsers.
According to <style>: The Style Information element - HTML | MDN, the type attribute is optional and defaults to text/css:
type
This attribute defines the styling language as a MIME type (charset should not be specified). This attribute is optional and defaults to text/css if it is not specified; values other than the empty string or text/css are not used. Note: There is very little reason to include this attribute in modern web documents.
Adding the CSS
To add the CSS, use .textContent as it is safer and faster than alternative methods. Opposite to .innerHTML, it does not parse HTML and can therefore prevent cross-site scripting attacks.
Another similar property, .innerText, is like .textContent but takes CSS styles into account and represents only the "rendered" text content. As we are not interested in "rendered"-only content we prefer .textContent.
What does setting .textContent do?
Setting the .textContent property removes all the node's (element's) children and replaces them with the given string value.
Where to place the element?
The style element should be included in the head: "The <style> element must be included inside the <head> of the document. ...". [<style> ... | MDN]
To get the head use document.head as it has been supported by all major browsers for a long time already so there is no need for other fallbacks.
document.head.innerHTML += `
<style>
h1 {
color: red;
}
p {
color: blue;
}
</style>`
<h1>I'm red!</h1>
<p>I'm blue!</p>
By far the most straightforward solution. All you have to do is type the same as how you'd normally declare style tags, between the backticks
Oftentimes there's a need to override existing rules, so appending new styles to the HEAD doesn't work in every case.
I came up with this simple function that summarizes all not valid "append to the BODY" approaches and is just more convenient to use and debug (IE8+).
window.injectCSS = (function(doc){
// wrapper for all injected styles and temp el to create them
var wrap = doc.createElement('div');
var temp = doc.createElement('div');
// rules like "a {color: red}" etc.
return function (cssRules) {
// append wrapper to the body on the first call
if (!wrap.id) {
wrap.id = 'injected-css';
wrap.style.display = 'none';
doc.body.appendChild(wrap);
}
// <br> for IE: http://goo.gl/vLY4x7
temp.innerHTML = '<br><style>'+ cssRules +'</style>';
wrap.appendChild( temp.children[1] );
};
})(document);
Demo: codepen, jsfiddle
This object variable will append style tag to the head tag with type attribute and one simple transition rule inside that matches every single id/class/element. Feel free to modify content property and inject as many rules as you need. Just make sure that css rules inside content remain in one line (or 'escape' each new line, if You prefer so).
var script = {
type: 'text/css', style: document.createElement('style'),
content: "* { transition: all 220ms cubic-bezier(0.390, 0.575, 0.565, 1.000); }",
append: function() {
this.style.type = this.type;
this.style.appendChild(document.createTextNode(this.content));
document.head.appendChild(this.style);
}}; script.append();
Here is a variant for dynamically adding a class
function setClassStyle(class_name, css) {
var style_sheet = document.createElement('style');
if (style_sheet) {
style_sheet.setAttribute('type', 'text/css');
var cstr = '.' + class_name + ' {' + css + '}';
var rules = document.createTextNode(cstr);
if(style_sheet.styleSheet){// IE
style_sheet.styleSheet.cssText = rules.nodeValue;
} else {
style_sheet.appendChild(rules);
}
var head = document.getElementsByTagName('head')[0];
if (head) {
head.appendChild(style_sheet);
}
}
}
You wrote:
var divNode = document.createElement("div");
divNode.innerHTML = "<br><style>h1 { background: red; }</style>";
document.body.appendChild(divNode);
Why not this?
var styleNode = document.createElement("style");
document.head.appendChild(styleNode);
Henceforward you can append CSS rules easily to the HTML code:
styleNode.innerHTML = "h1 { background: red; }\n";
styleNode.innerHTML += "h2 { background: green; }\n";
...or directly to the DOM:
styleNode.sheet.insertRule("h1 { background: red; }");
styleNode.sheet.insertRule("h2 { background: green; }");
I expect this to work everywhere except archaic browsers.
Definitely works in Chrome in year 2019.
All good, but for styleNode.cssText to work in IE6 with node created by javascipt, you need to append the node to the document before you set the cssText;
further info # http://msdn.microsoft.com/en-us/library/ms533698%28VS.85%29.aspx
This function will inject css whenever you call the function appendStyle like this:
appendStyle('css you want to inject')
This works by injecting a style node into the head of the document. This is a similar technique to what is commonly used to lazy-load JavaScript.
It works consistently in most modern browsers.
appendStyle = function (content) {
style = document.createElement('STYLE');
style.type = 'text/css';
style.appendChild(document.createTextNode(content));
document.head.appendChild(style);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1>Lorem Ipsum</h1>
<p>dolar sit amet</p>
<button onclick='appendStyle("body { background-color: #ff0000;}h1 { font-family: Helvetica, sans-serif; font-variant: small-caps; letter-spacing: 3px; color: #ff0000; background-color: #000000;}p { font-family: Georgia, serif; font-size: 14px; font-style: normal; font-weight: normal; color: #000000; background-color: #ffff00;}")'>Press me to inject CSS!</button>
</body>
</html>
You can also lazy-load external CSS files by using the following snippet:
appendExternalStyle = function (content) {
link = document.createElement('LINK');
link.rel = 'stylesheet';
link.href = content;
link.type = 'text/css';
document.head.appendChild(link);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
html {
font-family: sans-serif;
font-display: swap;
}
</style>
</head>
<body>
<h1>Lorem Ipsum</h1>
<p>dolar sit amet</p>
<button onclick='appendExternalStyle("data:text/css;base64,OjotbW96LXNlbGVjdGlvbntjb2xvcjojZmZmIWltcG9ydGFudDtiYWNrZ3JvdW5kOiMwMDB9OjpzZWxlY3Rpb257Y29sb3I6I2ZmZiFpbXBvcnRhbnQ7YmFja2dyb3VuZDojMDAwfWgxe2ZvbnQtc2l6ZToyZW19Ym9keSxodG1se2NvbG9yOnJnYmEoMCwwLDAsLjc1KTtmb250LXNpemU6MTZweDtmb250LWZhbWlseTpMYXRvLEhlbHZldGljYSBOZXVlLEhlbHZldGljYSxzYW5zLXNlcmlmO2xpbmUtaGVpZ2h0OjEuNjd9YnV0dG9uLGlucHV0e292ZXJmbG93OnZpc2libGV9YnV0dG9uLHNlbGVjdHstd2Via2l0LXRyYW5zaXRpb24tZHVyYXRpb246LjFzO3RyYW5zaXRpb24tZHVyYXRpb246LjFzfQ==")'>press me to inject css!</button>
</body>
</html>
as i know there are 4 ways to do that.
var style= document.createElement("style");
(document.head || document.documentElement).appendChild(style);
var rule=':visited { color: rgb(233, 106, 106) !important;}';
//no 1
style.innerHTML = rule;
//no 2
style.appendChild(document.createTextNode(rule));
//no 3 limited with one group
style.sheet.insertRule(rule);
//no 4 limited too
document.styleSheets[0].insertRule('strong { color: red; }');
//addon
style.sheet.cssRules //list all style
stylesheet.deleteRule(0) //delete first rule
If the problem you're facing is injecting a string of CSS into a page it is easier to do this with the <link> element than the <style> element.
The following adds p { color: green; } rule to the page.
<link rel="stylesheet" type="text/css" href="data:text/css;charset=UTF-8,p%20%7B%20color%3A%20green%3B%20%7D" />
You can create this in JavaScript simply by URL encoding your string of CSS and adding it the HREF attribute. Much simpler than all the quirks of <style> elements or directly accessing stylesheets.
let linkElement: HTMLLinkElement = this.document.createElement('link');
linkElement.setAttribute('rel', 'stylesheet');
linkElement.setAttribute('type', 'text/css');
linkElement.setAttribute('href', 'data:text/css;charset=UTF-8,' + encodeURIComponent(myStringOfstyles));
This will work in IE 5.5 upwards
Anyone who is looking for Typescript version,
const addStyles = (styles) => {
let styleNode : HTMLStyleElement = document.createElement('style');
styleNode.type = 'text/css';
if (styleNode.style)
styleNode.style.cssText = styles;
else
styleNode.appendChild(document.createTextNode(styles));
/* Append style to the head element */
document.head.appendChild(styleNode);
}
Also, in react/vue/angular if direct injection of CSS is needed, you can use posstcss-js to convert CSS into JSS and use CSS-in-JSS to inject a new styleSheet directly. For more info, please follow this documentation.
Update
You can use document.head as well as per #Brandon McConnell's comment.
The most trival answer:
function addStyle (styleText) {
const styleNode = document.createElement('style');
styleNode.type = 'text/css';
styleNode.textContent = styleText;
document.documentElement.appendChild(styleNode);
return styleNode;
}
this link may helpful to you:
http://jonraasch.com/blog/javascript-style-node

Categories