How do you add CSS with Javascript? - 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>

Related

How to read CSS value of pseudo class [duplicate]

I made a function that overwrite the the :hover of some elements on a page. It fades between the normal and the :hover effect. That for i had to create a .hover class in my CSS file. I think this is a little unclean. How could i read the the :hover pseudo class contents?
Using getComputedStyle as on the accepted answer won't work, because:
The computed style for the hover state is only available when the element is actually on that state.
The second parameter to getComputedStyle should be empty or a pseudo-element. It doesn't work with :hover because it's a pseudo-class.
Here is an alternative solution:
function getCssPropertyForRule(rule, prop) {
var sheets = document.styleSheets;
var slen = sheets.length;
for(var i=0; i<slen; i++) {
var rules = document.styleSheets[i].cssRules;
var rlen = rules.length;
for(var j=0; j<rlen; j++) {
if(rules[j].selectorText == rule) {
return rules[j].style[prop];
}
}
}
}
// Get the "color" value defined on a "div:hover" rule,
// and output it to the console
console.log(getCssPropertyForRule('div:hover', 'color'));
Demo
You could access document.styleSheets and look for a rule that is applied on that specific element. But that’s not any cleaner than using a simple additional class.
UPDATE: I somehow got this wrong. The below example doesn't work. See #bfavaretto's comment for an explanation.
In Firefox, Opera and Chrome or any other browser that correctly implements window.getComputedStyle is very simple. You just have to pass "hover" as the second argument:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style type="text/css">
div {
display: block;
width: 200px;
height: 200px;
background: red;
}
div:hover {
background: green;
}
</style>
</head>
<body>
<div></div>
<script type="text/javascript">
window.onload = function () {
var div = document.getElementsByTagName("div")[0];
var style = window.getComputedStyle(div, "hover");
alert(style.backgroundColor);
};
</script>
</body>
</html>
But I don't believe there's yet a solution for Internet Explorer, except for using document.styleSheets as Gumbo suggested. But there will be differences. So, having a .hover class is the best solution so far. Not unclean at all.
If there are any people here who use the questions accepted answer but it won't work, here's a nice function that might:
function getPseudoStyle(id, style) {
var all = document.getElementsByTagName("*");
for (var i=0, max=all.length; i < max; i++) {
var targetrule = "";
if (all[i].id === id) {
if(all[i].selectorText.toLowerCase()== id + ":" + style) { //example. find "a:hover" rule
targetrule=myrules[i]
}
}
return targetrule;
}
}
There is an alterantive way to get :hover pseudo class with javascript. You can write your styles of hover pseudo class in a content property.
p::before,
p::after{
content: 'background-color: blue; color:blue; font-size: 14px;';
}
then read from it via getComputedStyle() method:
console.log(getComputedStyle(document.querySelector('p'),':before').getPropertyValue('content'));

Inject CSS stylesheet as string using 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);

Javascript-triggered CSS effects

I'm working on a small project where if the user enters the Konami code on a site, a filter is applied to every element (for now, will be better in the final version). Right now I have:
<script type="text/javascript">
var success = function() {
var css = 'div { -webkit-filter: blur(10px); }',
head = document.getElementsByTagName('head')[0],
style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
var konami = new Konami(success);
</script>
and I'm using http://snaptortoise.com/konami-js/ which has successfully run when used with a redirect instead of a function (documentation says I can create a new Konami with the method shown above, or with a url string to be used as a redirect).
I've gotten javascript alert messages to show, but cannot implement this filter. What did I do wrong?
Keep the class in your stylesheet:
.blurred {
-webkit-filter: blur(10px);
}
And then add it to your <body> tag:
var success = function() {
document.body.className = 'blurred';
};
You never append style to the head:
head.appendChild(style);
http://jsfiddle.net/ExplosionPIlls/2mTJf/
You need to add head.appendChild(style).
JS Fiddle http://jsfiddle.net/NMetj/

controlling css with javascript works with Mozilla & Chrome however not with IE

Im having problems with this function applying css(using a text variable) working with Internet Explorer but it works in Firefox & Chrome.
the code:
/*! addCssStyle() applies the text value $CssText$ to the the specified document
$Doc$ e.g. an IFrame; or if none specified, default to the current document,
*/function addCssStyle(CssText, Doc){
//Secure $Head$ for the current $Doc$
Doc = Doc||document; var head = Doc.getElementsByTagName('head')[0];
if(!head || head == null){
head = Doc.createElement('div'); Doc.body.appendChild(head);
} if(!head || head == null){return false;}
//createElement('style')
var PendingStyle = Doc.createElement('style');
// if (is_gecko){PendingStyle.href = 'FireFox.css';}//???needeed???
PendingStyle.type = 'text/css';
PendingStyle.rel = 'stylesheet';
// PendingStyle.media = 'screen';//???needeed???
PendingStyle.innerHTML = CssText;
head.appendChild(PendingStyle);
}/*___________________________________________________________________________*/
the use of the function:
var NewSyleText = //The page styling
"h1, h2, h3, h4, h5 {font-family: 'Verdana','Helvetica',sans-serif; font-style: normal; font-weight:normal;}" +
"body, b {background: #fbfbfb; font-style: normal; font-family: 'Cochin','GaramondNo8','Garamond','Big Caslon','Georgia','Times',serif;font-size: 11pt;}" +
"p { margin: 0pt; text-indent:2.5em; margin-top: 0.3em; }" +
"a { text-decoration: none; color: Navy; background: none;}" +
"a:visited { color: #500050;}" +
"a:active { color: #faa700;}" +
"a:hover { text-decoration: underline;}";
addCssStyle(NewSyleText);//inserts the page styling
var style = document.createElement('style');
Adding new stylesheets and scripts by creating elements using DOM methods is something that has always been dicey cross-browser. This won't work in IE or WebKit.
style.rel = 'stylesheet';
style.href = 'FireFox.css';
There's no such properties on an HTMLStyleElement. <style> contains inline code. For external stylesheets, use a <link>. By luck, it happens this does work:
var link= document.createElement('link');
link.rel= 'stylesheet';
link.href= 'something.css';
head.appendChild(link);
But doesn't give you a convenient way to insert rules from script.
You can also add new rules to an existing stylesheet (eg. an empty style in the <head>) by using the document.styleSheets interface. Unfortunately, IE's interface doesn't quite match the standard here so you need code branching:
var style= document.styleSheets[0];
if ('insertRule' in style)
style.insertRule('p { margin: 0; }', 0);
else if ('addRule' in style)
style.addRule('p', 'margin: 0', 0);
I know this is a old thread but i was looking for a solution to insert CSS styles dynamicly that works with all common/major browsers. I want to share my solution with you. The solution of david doesn't work well (sorry). I have made a tooltip javascript/jQuery class that can work with inline styles for example but can also work with CSS styled styles. (offtopic: Also the class can auto align tooltips like the default tooltips).
Maybe you wonder what the benefits are when you insert CSS like the example above. Well, you don't need an extra CSS file with the styles and you can dynamicly add styles from script and when you working with images you can dynamicly change the path to the images if you want (so you don't need to change any file). Also you can insert the styles ABOVE other stylesheets/style rules and the aplied style rules can be modified in the other stylesheets below (this is not possible when you use inline styles or when placing the inserted rules BELOW any existing stylesheet).
This function works with Opera/Firefox/IE7/IE8/IE9/Chrome/Safari (without any hack applied!):
function addHtmlStyles( sCss, oBefore )
{
var oHead = document.getElementsByTagName('head')[0];
if( !oHead || oHead == null )
{ return false; }
var bResult = false,
oStyle = document.createElement('style');
oStyle.type = 'text/css';
oStyle.rel = 'stylesheet';
oStyle.media = 'screen';
if( typeof oStyle.styleSheet == 'object' )
{ // IE route (and opera)
try{ oStyle.styleSheet.cssText = sCss; bResult = true; }
catch(e) {}
}
else {
// Mozilla route
try{ oStyle.innerHTML = sCss; bResult = true; }
catch(e) {};
if( !bResult )
{
// Webkit route
try{ oStyle.innerText = sCss; bResult = true; }
catch(e) {};
}
}
if( bResult )
{
try
{
if( typeof oBefore == 'object' )
{ oHead.insertBefore(oStyle, oBefore ); }
else { oHead.appendChild(oStyle); }
}
catch(e) { bResult = false; }
}
return bResult;
}
It returns true when ok or false when fail. For example:
var sCss = '#tooltip {background:"#FF0000";}';
// get first stylesheet with jQuery, we don't use $('head') because it not always working
// If there is no stylesheet available, it will be added at the end of the head tag.
var oHead = $(document.getElementsByTagName('head')[0]),
oFirst = oHead.find('[rel=stylesheet]').get(0);
if( addHtmlStyles( sCss, oFirst ))
{ alert( 'OK' ); }
else { alert( 'NOT OK' ); }
That's all. Hope you like the solution.
Greetz,
Erwin Haantjes
This has been tested to work on all major browsers (Chrome/Safari/FF/Opera/IE) including IE6,7+8:
function createCSS(css, doc) {
doc = doc || document;
var style = doc.createElement("style");
style.type = "text/css";
if (!window.opera && 'styleSheet' in style && 'cssText' in style.styleSheet) {
// Internet Explorer 6-8 don't support adding text nodes to
// styles, so use the proprietary `styleSheet.cssText` instead
style.styleSheet.cssText = css;
}
else {
// Otherwise use the standard method
style.appendChild(doc.createTextNode(css));
}
// Note the `|| document.body` as getting the
// head doesn't always work on e.g. Safari 1.0
var head = doc.getElementsByTagName("head")[0] || doc.body;
// Add the new style of higher priority than the last
// ones if there's already other elements in the head
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
}
else {
head.appendChild(style);
}
}
As that code is written, it is relative to the document being served so may need to be modified to make it relative to another path, or you could use absolute image paths in the CSS.
EDIT: Removed all the innerHTML references in favour of using the more standard createTextNode when possible and cleaned various things up.
#GlassGost: Weird is not working for you because i test it in several browsers (also on the mobile ones). Maybe it helps to add css when the DOM is ready:
$(document).ready( function()
{
.......
});
Also sometimes it helps to change the order of loading scripts.
Greetz,
Erwin Haantjes
This works fine for me on all current browsers with any type of document (which I assume you must be dealing with multiple documents, or otherwise you wouldn't have a Doc parameter):
function add_css_style(css_rules, document) {
document = document || self.document;
var style = document.createElementNS("http://www.w3.org/1999/xhtml", "style");
style.type = "text/css";
style.appendChild(document.createTextNode(css_rules));
document.documentElement.appendChild(style);
}
If you want to use the CSSOM instead:
function add_css_style(css_rules, document) {
document = document || self.document;
var stylesheet = document.documentElement.appendChild(
this.createElementNS("http://www.w3.org/1999/xhtml", "style")
).sheet;
stylesheet.insertRule("#media all{" + rules + "}", 0);
}

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