Related
I am looking for a way to retrieve the style from an element that has a style set upon it by the style tag.
<style>
#box {width: 100px;}
</style>
In the body
<div id="box"></div>
I'm looking for straight javascript without the use of libraries.
I tried the following, but keep receiving blanks:
alert (document.getElementById("box").style.width);
alert (document.getElementById("box").style.getPropertyValue("width"));
I noticed that I'm only able to use the above if I have set the style using javascript, but unable to with the style tags.
The element.style property lets you know only the CSS properties that were defined as inline in that element (programmatically, or defined in the style attribute of the element), you should get the computed style.
Is not so easy to do it in a cross-browser way, IE has its own way, through the element.currentStyle property, and the DOM Level 2 standard way, implemented by other browsers is through the document.defaultView.getComputedStyle method.
The two ways have differences, for example, the IE element.currentStyle property expect that you access the CCS property names composed of two or more words in camelCase (e.g. maxHeight, fontSize, backgroundColor, etc), the standard way expects the properties with the words separated with dashes (e.g. max-height, font-size, background-color, etc).
Also, the IE element.currentStyle will return all the sizes in the unit that they were specified, (e.g. 12pt, 50%, 5em), the standard way will compute the actual size in pixels always.
I made some time ago a cross-browser function that allows you to get the computed styles in a cross-browser way:
function getStyle(el, styleProp) {
var value, defaultView = (el.ownerDocument || document).defaultView;
// W3C standard way:
if (defaultView && defaultView.getComputedStyle) {
// sanitize property name to css notation
// (hypen separated words eg. font-Size)
styleProp = styleProp.replace(/([A-Z])/g, "-$1").toLowerCase();
return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
} else if (el.currentStyle) { // IE
// sanitize property name to camelCase
styleProp = styleProp.replace(/\-(\w)/g, function(str, letter) {
return letter.toUpperCase();
});
value = el.currentStyle[styleProp];
// convert other units to pixels on IE
if (/^\d+(em|pt|%|ex)?$/i.test(value)) {
return (function(value) {
var oldLeft = el.style.left, oldRsLeft = el.runtimeStyle.left;
el.runtimeStyle.left = el.currentStyle.left;
el.style.left = value || 0;
value = el.style.pixelLeft + "px";
el.style.left = oldLeft;
el.runtimeStyle.left = oldRsLeft;
return value;
})(value);
}
return value;
}
}
The above function is not perfect for some cases, for example for colors, the standard method will return colors in the rgb(...) notation, on IE they will return them as they were defined.
I'm currently working on an article in the subject, you can follow the changes I make to this function here.
I believe you are now able to use Window.getComputedStyle()
Documentation MDN
var style = window.getComputedStyle(element[, pseudoElt]);
Example to get width of an element:
window.getComputedStyle(document.querySelector('#mainbar')).width
In jQuery, you can do alert($("#theid").css("width")).
-- if you haven't taken a look at jQuery, I highly recommend it; it makes many simple javascript tasks effortless.
Update
for the record, this post is 5 years old. The web has developed, moved on, etc. There are ways to do this with Plain Old Javascript, which is better.
Use getComputedStyle function, Computed style contains all the CSS properties set to an element. Even if do not set a property to an element. You will still find that property in the computed styles.
Example:
<style>
#Body_element {
color: green;
}
</style>
<body id="Body_element">
<script>
alert(getComputedStyle(Body_element).color)
</script>
</body>
This is a helper function if you want to get multiple style rules from the same element.
You pass it the element and the styles you want as arguments, and it will return their values
const convertRestArgsIntoStylesArr = ([...args]) => {
return args.slice(1);
}
const getStyles = function () {
const args = [...arguments];
const [element] = args;
let stylesProps = [...args][1] instanceof Array ? args[1] : convertRestArgsIntoStylesArr(args);
const styles = window.getComputedStyle(element);
const stylesObj = stylesProps.reduce((acc, v) => {
acc[v] = styles.getPropertyValue(v);
return acc;
}, {});
return stylesObj;
};
Now, you can use this function like this:
const styles = getStyles(document.body, "height", "width");
OR
const styles = getStyles(document.body, ["height", "width"]);
I'm writing a script that needs to check if certain CSS properties are defined inside the <style> tag.
<style type="text/css">
#bar {width: 200px;}
</style>
<div id="foo" style="width: 200px;">foo</div>
<div id="bar">bar</div>
// 200px
console.log(document.getElementById("foo").style.width);
// an empty string
console.log(document.getElementById("bar").style.width);
if(property_width_defined_in_style_tag) {
// ...
}
Is this possible?
I'm not trying to get the getComputedStyle(ele).width btw.
I'm not sure this is what you want, it works closest to your first pseudo code where you had an element instance, anyway hope it helps:
var proto = Element.prototype;
var slice = Function.call.bind(Array.prototype.slice);
var matches = Function.call.bind(proto.matchesSelector ||
proto.mozMatchesSelector || proto.webkitMatchesSelector ||
proto.msMatchesSelector || proto.oMatchesSelector);
// Returns true if a DOM Element matches a cssRule
var elementMatchCSSRule = function(element, cssRule) {
return matches(element, cssRule.selectorText);
};
// Returns true if a property is defined in a cssRule
var propertyInCSSRule = function(prop, cssRule) {
return prop in cssRule.style && cssRule.style[prop] !== "";
};
// Here we get the cssRules across all the stylesheets in one array
var cssRules = slice(document.styleSheets).reduce(function(rules, styleSheet) {
return rules.concat(slice(styleSheet.cssRules));
}, []);
// get a reference to an element, then...
var bar = document.getElementById("bar");
// get only the css rules that matches that element
var elementRules = cssRules.filter(elementMatchCSSRule.bind(null, bar));
// check if the property "width" is in one of those rules
hasWidth = elementRules.some(propertyInCSSRule.bind(null, "width"));
I think you can reuse all of this code for your purpose, or just some piece of it, it's modular on purpose – for instance, once you have all the cssRules flatten, or the elementRules, you can still use a for loop and check what you need.
It uses ES5 functions and matchesSelector so in old browsers won't work without shims. Plus, you could also filter by priority and so on – you could for instance remove all the properties has a lower priority than the inline style ones, etc.
You can completely explore in javascript the styleSheets.
Start with the document.styleSheets array. The values are the different style elements or CSS files that are used by your document.
I got this style applied to a div
div#content {
border: 1px solid skyblue;
}
and i want to be able to alert the width of the border, I have tried with this:
window.alert( document.getElementById( "content" ).style.borderWidth );
I heard that depends of the browser maybe you can help me
I'm using Firefox 18
Please try the below javascript:
alert($("#content").css("border-left-width")); //using jquery.
or
alert(getComputedStyle(document.getElementById('content'),null).getPropertyValue('border-left-width'));//without jquery.
getComputedStyle(element, pseudo)
element:The element to get a styling for
pseudo:A pseudo-selector like ‘hover’ or null if not needed.
Reference link: http://javascript.info/tutorial/styles-and-classes-getcomputedstyle
I might be too late but as you never marked it as answered, I thought I could give it a try.
If your problem was compatibility between browser I would create a custom method that I could use in almost every browser there is (that means going back to the very basics).
I actually dug a lot to do this. I use some of the code from jQuery because I did not want to use jQuery but still have the backwards compatibility that jQuery does.
This function solves your question and at the bottom there are some examples on how to use it.
This functions uses the "module pattern" through the immediate function that will be run as soon as the script loads creating a method that will NOT polute the global scope but extend its functionality through a function to do what you wanted.
// I give it a name but it can also be anonymous
(function preloadedFunctions(){
// Preseted methods.
if(window.getComputedStyle){
window.getComputedStylePropertyValue = function(element, prop){
var computedStyle = window.getComputedStyle(element, null);
if(!computedStyle) return null;
if(computedStyle.getPropertyValue) {
return computedStyle.getPropertyValue(prop);
} else if (computedStyle.getAttribute) {
return computedStyle.getAttribute(prop);
} else if(computedStyle[prop]) {
return computedStyle[prop];
};
};
}
// jQuery JavaScript Library v1.9.0
// http://www.minhacienda.gov.co/portal/pls/portal/PORTAL.wwsbr_imt_services.GenericView?p_docname=6240612.JS&p_type=DOC&p_viewservice=VAHWSTH&p_searchstring=
// For IE8 or less
else if ( document.documentElement.currentStyle ) {
var rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
rposition = /^(top|right|bottom|left)$/,
core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source;
window.getComputedStylePropertyValue = function(element, prop){
var left, rsLeft,
ret = element.currentStyle && element.currentStyle[ prop ],
style = element.style;
if ( ret == null && style && style[ prop ] ) {
ret = style[ prop ];
}
if ( rnumnonpx.test( ret ) && !rposition.test( prop ) ) {
left = style.left;
rsLeft = element.runtimeStyle && element.runtimeStyle.left;
if ( rsLeft ) {
element.runtimeStyle.left = element.currentStyle.left;
}
style.left = prop === "fontSize" ? "1em" : ret;
ret = style.pixelLeft + "px";
style.left = left;
if ( rsLeft ) {
element.runtimeStyle.left = rsLeft;
}
}
return ret === "" ? "auto" : ret;
};
};
})();
i.e.
1.-
var borderWidth = getComputedStylePropertyValue(document.getElementsByTagName("div")[0], "border-width");
console.log(borderWidth);
2.-
var div = document.getElementById("someID");
console.log(getComputedStylePropertyValue(div, "border-width"));
If somebody is still looking, this seems to be easiest way to do it with plain JS.
let border =
+getComputedStyle((document.getElementById("idOfYourElement")))
.borderTopWidth.slice(0, -2)
Explanation below:
document.getElementById("idOfYourElement") - Return our HTML element.
getComputedStyle - Return css attributes of chosen element as object.
.borderTopWidth - Corresponding attribute from getComputedStyle object (return array like this: ("10px")).
.slice(0, -2) - Cut the last 2 characters from our array so we get rid of px at the end.
And + at the start - Parse rest of our string, that contains number we want, to the integer.
You can try this:
var border = document.getElementById("yourDiv").clientWidth - document.getElementById("yourDiv").offsetWidth;
alert(border);
Note, that the value will be rounded to an integer. If fractional value is required, you need to use getComputedStyle instead (see other answers).
Very old question, but anyway...
This solution is plain JavaScript, and should work in older browsers too.
It measures the size of the element, with, and without borders.
The following example should work correctly if the borders around the element are all the same size.
If not, the procedure doesn't change much, you just have to set the borders equal to zero, one by one.
var ele=document.getElementById("content");
// measures the element width, WITH borders
var w=ele.offsetWidth;
var cssBackup=ele.style.cssText;
// sets the borders to zero
ele.style.border="0px";
// computes the border size
var bord=(w-ele.offsetWidth)/2;
// resets the css
ele.style.cssText=cssBackup;
alert(bord);
When left & right border has same width:
function getWidth(div) {
return (div.offsetWidth - div.clientWidth) /2
}
getWidth(document.querySelector('#content'))
According to W3Schools, this property is supported by major browsers. Thus you shouldn't have any difficulty in using it.
However, using a JavaScript framework like jQuery would always help you not worrying about trivial issues like this.
Works for me
let content = document.querySelector('#content');
// here 'borderWidth' is similar to element.style syntax
let contentBorderWidth = getComputedStyle(content).borderWidth; // 1px
// number, without 'px'
let contentBorderWidthNumber = parseFloat(getComputedStyle(content).borderWidth); // 1
// demo
content.innerHTML = contentBorderWidth +', '+ contentBorderWidthNumber;
// in your case, to alert
window.alert(contentBorderWidth +', '+ contentBorderWidthNumber);
div#content {
border: 1px solid skyblue;
}
<div id="content"></div>
More about getComputedStyle.
I know it is possible to add new CSS classes definitions at runtime through JavaScript. But...
How to change/remove CSS classes definitions at runtime?
For instance, supose a I have the class below:
<style>
.menu { font-size: 12px; }
</style>
What I want is, at runtime, change the font-size rule of the .menu class, so that every element in the page who uses this class will be affected.
And, I also want to know how to remove the .menu class definition.
It's not difficult to change CSS rules at runtime, but apparently it is difficult to find the rule you want. PPK has a quick tour of this on quirksmode.org.
You'll want to use document.styleSheets[i].cssRules which is an array you need to parse through to find the one you want, and then rule.style.setProperty('font-size','10px',null);
I found an answer at http://twelvestone.com/forum_thread/view/31411 and I'm reproducing parts of the thread here, verbatim, because I'm afraid the thread, and the very helpful answer, will evaporate.
Flip 2006.06.26, 02:45PM —
[ Crunchy Frog ]
posts: 2470 join date: 2003.01.26
Well after about 10 to 12 hours of searching, reading, and tinkering I've done it! I am CSS/JS code Ninja today!
The JS code used is as follows:
<script language="JavaScript">
function changeRule(theNumber) {
var theRules = new Array();
if (document.styleSheets[0].cssRules) {
theRules = document.styleSheets[0].cssRules;
} else if (document.styleSheets[0].rules) {
theRules = document.styleSheets[0].rules;
}
theRules[theNumber].style.backgroundColor = '#FF0000';
}
</script>
I've tested this on FF(Mac), Safari(Mac), O9(Mac), IE5(Mac), IE6(PC), FF(PC) and they all work. The reason for the 'if' statement is some of the browsers use cssRules... some use just rules... And the only other hair is that you can't use "background-color" to refer to the style, you have to get rid of the hyphen and capitalize the first letter after the hyphen.
To refer to the first CSS rule you'd use "changeRule(0)", the second "changeRule(1)" and the third "changeRule(2)" and so on...
I haven't found a browser it doesn't work on.... yet....
Anything you say can and will be used against you. Over and over and over.
BillyBones 2011.01.20, 11:57AM —
[ in the barrel ]
posts: 1 join date: 2011.01.20
Hello, I registered in these forums just to add this little bit as I could not conveniently find it elsewhere:
function changeStyle(selectorText)
{
var theRules = new Array();
if (document.styleSheets[0].cssRules) {
theRules = document.styleSheets[0].cssRules;
}
else if (document.styleSheets[0].rules) {
theRules = document.styleSheets[0].rules;
}
for (n in theRules)
{
if (theRules[n].selectorText == selectorText) {
theRules[n].style.color = 'blue';
}
}
}
This simply makes the CSS rule identifiable by its selector name rather than by its index number in the cssRules array.
In other words, you can execute the Javascript function with the string argument "selectorText" instead of a number that is difficult to remember and susceptible to frequent changes if new styles are added.
Thank you for your 10 to 12 hours of research, Flip, I hope I made a worthy addition.
i think you are looking for this:
http://www.hunlock.com/blogs/Totally_Pwn_CSS_with_Javascript
this lets you change the actual rules with javascript. ive used it once, a few years ago it seemed to have worked.
I've made a simple helper function for anyone that want to do that:
function getCSSRule(search) {
return [].map.call(document.styleSheets, function(item) {
return [].slice.call(item.cssRules);
}).reduce(function(a, b) {
return b.concat(a);
}).filter(function(rule) {
return rule.selectorText.lastIndexOf(search) === rule.selectorText.length - search.length;
})[0];
}
And then, you can use it like that:
getCSSRule('.mydiv').style.fontSize = '20px';
Take a look at the example below:
function getCSSRule(search) {
return [].map.call(document.styleSheets, function(item) {
return [].slice.call(item.cssRules);
}).reduce(function(a, b) {
return b.concat(a);
}).filter(function(rule) {
return rule.selectorText.lastIndexOf(search) === rule.selectorText.length - search.length;
})[0];
}
document.querySelector('button').addEventListener('click', function(e) {
getCSSRule('.iframe').style.backgroundColor = 'orange';
});
.iframe {
height: 200px;
width: 200px;
display: inline-block;
border: 1px solid #000;
}
<p>
<button>Change .iframe background-color</button>
</p>
<div class="iframe"></div>
<div class="iframe"></div>
I took the best of the answers here, and combined them, for ease of use, and cross browser compatibility. Also, I covered when threw errors if no stylesheets were on the page, or if the css rule did not exist yet.
https://github.com/Frazer/dynamicallyAccessCSS.js
Here's an embarrassingly simple trick I've been using for dynamically manipulating CSS class rules, which dodges the complications (like parsing through the rules to locate the one you need, as noted by the expected answer), and even provides some extra flexibility for free.
(A side-note: the prev. attempt of adding this answer got instanty downvoted, within seconds, without feedback, by one of the few auto-notification targets of this page. I'm not sure the short knee-jerk reaction time was enough to see why this is a reliable solution that covers the OP's use case well, nevertheless I've rephrased it, guessing the narrative may have somehow been the trigger. Or the lack of semicolons (which I've now added for him). Or the lack of unnecessary curly braces (also added). Or the lack of notes on non-effects (added). Or not using a sufficiently complicated method (won't fix, even simplified the code yet some more). I'm sure he'll hit again anonymously, but still retry, because this is a clean & robust technique worth using.)
NOTE: This approach assumes you have sufficient control over the styling of the page to make sure the same class rule would not get created by a different method. (And it expects the HEAD element to exist.)
(One potential cost of this approach could be re-rendering on innerHtml, but since we are changing CSS anyway, repaint is imminent. Also, innerHtml is done to a non-displayed element, so browsers could optimize it out even if it otherwise mattered.)
OK. Since you can have any number of STYLE elements, it's perfectly fine to wrap your dynamic class in its own separate one. Um, that's it. :) Then, add an id or, even better*, a class attribute to the wrapper STYLE, so you can practically access and manipulate your class rule as if it was a DOM element. Just make sure it's wrapped in <style class="..."> ... </style>, when adding/replacing.
Bonus: you can also group multiple related rules and replace them all at once this way, if you wish (with trivial modifications):
function replace_class(classname, block) {
// Remove old:
var s = document.head.querySelector("style." + classname);
if (s) { document.head.removeChild(s); }
// Just delete?
if (!block) { return; }
// Add new:
s = document.createElement("style");
s.className = classname;
s.innerHTML = ("." + classname + block); // <style class="classname">.classname{...}</style>
document.head.appendChild(s);
}
Then, to update: replace_class("menu", "{font-size: 8px;}").
Or delete: replace_class("menu", null).
* Since CSS applies to every element, you may wonder why won't STYLE itself get unexpectedly rendered, if your new class had a display: ... with something else than none. Well, it would, if it was put in the BODY! But, since we add it to HEAD, rendering is skipped (unless, of course, you opt to display HEAD, too). Or, you could also use id instead, but then you had to invent/use proper scoping/prefixing, and why would you want that if it can be spared? (And I also like the subtle cheekiness of setting class when it's a class wrapper anyway...)
It is difficult to find the rule you want because you have to iterate through the document.styleSheets[i].cssRules array. (and compare your class name with the selectorText attribute)
So my solution to this problem is to add a new CSS class, remove the old CSS class from the HTML element and add this class instead of it.
var length = getCssRuleLength();
var newClassName = "css-class-name" + length;
//remove preview css class from html element.
$("#your-html-element").removeClass("css-class-name");
$("#your-html-element").removeClass("css-class-name" + (length-1));
$("#your-html-element").addClass(newClassName);
//insert a css class
insertCssRule("." + newClassName + ' { max-width: 100px; }', length);
function getCssRuleLength() {
var length = 0;
if (document.styleSheets[1].cssRules) {
length = document.styleSheets[1].cssRules.length;
} else if (document.styleSheets[1].rules) { //ie
length = document.styleSheets[1].rules.length;
}
return length;
}
function insertCssRule(rule, index) {
if (document.styleSheets[1].cssRules) {
document.styleSheets[1].insertRule(rule, index);
} else if (document.styleSheets[1].rules) { //ie
document.styleSheets[1].addRule(rule, index);
}
}
Below is an approach that will work for any given rule-selector and rule-change function:
// general function for selecting rules and applying changes
function change_css_rules(changeRuleFunc, selectorFunc) {
[].concat.apply([], // flattens arrays
Array.from(document.styleSheets).map(function(sheet) { // each ss
return Array.from(sheet.cssRules).filter(function(rule) { // each rule
return selectorFunc(rule); // only select desired rules
});
})
).map(changeRuleFunc); // change the selected rules
}
Example use:
var my_changeRuleFunc = function(rule) {
rule.style.fontSize = '20px';
}
var my_selectorFunc = function(rule) {
return rule.selectorText == '.myClass'; // return true to select this rule
}
change_css_rules(my_changeRuleFunc, my_selectorFunc); // apply change to selected rules
I know it is possible to add new CSS classes definitions at runtime through JavaScript. But...
How to change/remove CSS classes definitions at runtime?
For instance, supose a I have the class below:
<style>
.menu { font-size: 12px; }
</style>
What I want is, at runtime, change the font-size rule of the .menu class, so that every element in the page who uses this class will be affected.
And, I also want to know how to remove the .menu class definition.
It's not difficult to change CSS rules at runtime, but apparently it is difficult to find the rule you want. PPK has a quick tour of this on quirksmode.org.
You'll want to use document.styleSheets[i].cssRules which is an array you need to parse through to find the one you want, and then rule.style.setProperty('font-size','10px',null);
I found an answer at http://twelvestone.com/forum_thread/view/31411 and I'm reproducing parts of the thread here, verbatim, because I'm afraid the thread, and the very helpful answer, will evaporate.
Flip 2006.06.26, 02:45PM —
[ Crunchy Frog ]
posts: 2470 join date: 2003.01.26
Well after about 10 to 12 hours of searching, reading, and tinkering I've done it! I am CSS/JS code Ninja today!
The JS code used is as follows:
<script language="JavaScript">
function changeRule(theNumber) {
var theRules = new Array();
if (document.styleSheets[0].cssRules) {
theRules = document.styleSheets[0].cssRules;
} else if (document.styleSheets[0].rules) {
theRules = document.styleSheets[0].rules;
}
theRules[theNumber].style.backgroundColor = '#FF0000';
}
</script>
I've tested this on FF(Mac), Safari(Mac), O9(Mac), IE5(Mac), IE6(PC), FF(PC) and they all work. The reason for the 'if' statement is some of the browsers use cssRules... some use just rules... And the only other hair is that you can't use "background-color" to refer to the style, you have to get rid of the hyphen and capitalize the first letter after the hyphen.
To refer to the first CSS rule you'd use "changeRule(0)", the second "changeRule(1)" and the third "changeRule(2)" and so on...
I haven't found a browser it doesn't work on.... yet....
Anything you say can and will be used against you. Over and over and over.
BillyBones 2011.01.20, 11:57AM —
[ in the barrel ]
posts: 1 join date: 2011.01.20
Hello, I registered in these forums just to add this little bit as I could not conveniently find it elsewhere:
function changeStyle(selectorText)
{
var theRules = new Array();
if (document.styleSheets[0].cssRules) {
theRules = document.styleSheets[0].cssRules;
}
else if (document.styleSheets[0].rules) {
theRules = document.styleSheets[0].rules;
}
for (n in theRules)
{
if (theRules[n].selectorText == selectorText) {
theRules[n].style.color = 'blue';
}
}
}
This simply makes the CSS rule identifiable by its selector name rather than by its index number in the cssRules array.
In other words, you can execute the Javascript function with the string argument "selectorText" instead of a number that is difficult to remember and susceptible to frequent changes if new styles are added.
Thank you for your 10 to 12 hours of research, Flip, I hope I made a worthy addition.
i think you are looking for this:
http://www.hunlock.com/blogs/Totally_Pwn_CSS_with_Javascript
this lets you change the actual rules with javascript. ive used it once, a few years ago it seemed to have worked.
I've made a simple helper function for anyone that want to do that:
function getCSSRule(search) {
return [].map.call(document.styleSheets, function(item) {
return [].slice.call(item.cssRules);
}).reduce(function(a, b) {
return b.concat(a);
}).filter(function(rule) {
return rule.selectorText.lastIndexOf(search) === rule.selectorText.length - search.length;
})[0];
}
And then, you can use it like that:
getCSSRule('.mydiv').style.fontSize = '20px';
Take a look at the example below:
function getCSSRule(search) {
return [].map.call(document.styleSheets, function(item) {
return [].slice.call(item.cssRules);
}).reduce(function(a, b) {
return b.concat(a);
}).filter(function(rule) {
return rule.selectorText.lastIndexOf(search) === rule.selectorText.length - search.length;
})[0];
}
document.querySelector('button').addEventListener('click', function(e) {
getCSSRule('.iframe').style.backgroundColor = 'orange';
});
.iframe {
height: 200px;
width: 200px;
display: inline-block;
border: 1px solid #000;
}
<p>
<button>Change .iframe background-color</button>
</p>
<div class="iframe"></div>
<div class="iframe"></div>
I took the best of the answers here, and combined them, for ease of use, and cross browser compatibility. Also, I covered when threw errors if no stylesheets were on the page, or if the css rule did not exist yet.
https://github.com/Frazer/dynamicallyAccessCSS.js
Here's an embarrassingly simple trick I've been using for dynamically manipulating CSS class rules, which dodges the complications (like parsing through the rules to locate the one you need, as noted by the expected answer), and even provides some extra flexibility for free.
(A side-note: the prev. attempt of adding this answer got instanty downvoted, within seconds, without feedback, by one of the few auto-notification targets of this page. I'm not sure the short knee-jerk reaction time was enough to see why this is a reliable solution that covers the OP's use case well, nevertheless I've rephrased it, guessing the narrative may have somehow been the trigger. Or the lack of semicolons (which I've now added for him). Or the lack of unnecessary curly braces (also added). Or the lack of notes on non-effects (added). Or not using a sufficiently complicated method (won't fix, even simplified the code yet some more). I'm sure he'll hit again anonymously, but still retry, because this is a clean & robust technique worth using.)
NOTE: This approach assumes you have sufficient control over the styling of the page to make sure the same class rule would not get created by a different method. (And it expects the HEAD element to exist.)
(One potential cost of this approach could be re-rendering on innerHtml, but since we are changing CSS anyway, repaint is imminent. Also, innerHtml is done to a non-displayed element, so browsers could optimize it out even if it otherwise mattered.)
OK. Since you can have any number of STYLE elements, it's perfectly fine to wrap your dynamic class in its own separate one. Um, that's it. :) Then, add an id or, even better*, a class attribute to the wrapper STYLE, so you can practically access and manipulate your class rule as if it was a DOM element. Just make sure it's wrapped in <style class="..."> ... </style>, when adding/replacing.
Bonus: you can also group multiple related rules and replace them all at once this way, if you wish (with trivial modifications):
function replace_class(classname, block) {
// Remove old:
var s = document.head.querySelector("style." + classname);
if (s) { document.head.removeChild(s); }
// Just delete?
if (!block) { return; }
// Add new:
s = document.createElement("style");
s.className = classname;
s.innerHTML = ("." + classname + block); // <style class="classname">.classname{...}</style>
document.head.appendChild(s);
}
Then, to update: replace_class("menu", "{font-size: 8px;}").
Or delete: replace_class("menu", null).
* Since CSS applies to every element, you may wonder why won't STYLE itself get unexpectedly rendered, if your new class had a display: ... with something else than none. Well, it would, if it was put in the BODY! But, since we add it to HEAD, rendering is skipped (unless, of course, you opt to display HEAD, too). Or, you could also use id instead, but then you had to invent/use proper scoping/prefixing, and why would you want that if it can be spared? (And I also like the subtle cheekiness of setting class when it's a class wrapper anyway...)
It is difficult to find the rule you want because you have to iterate through the document.styleSheets[i].cssRules array. (and compare your class name with the selectorText attribute)
So my solution to this problem is to add a new CSS class, remove the old CSS class from the HTML element and add this class instead of it.
var length = getCssRuleLength();
var newClassName = "css-class-name" + length;
//remove preview css class from html element.
$("#your-html-element").removeClass("css-class-name");
$("#your-html-element").removeClass("css-class-name" + (length-1));
$("#your-html-element").addClass(newClassName);
//insert a css class
insertCssRule("." + newClassName + ' { max-width: 100px; }', length);
function getCssRuleLength() {
var length = 0;
if (document.styleSheets[1].cssRules) {
length = document.styleSheets[1].cssRules.length;
} else if (document.styleSheets[1].rules) { //ie
length = document.styleSheets[1].rules.length;
}
return length;
}
function insertCssRule(rule, index) {
if (document.styleSheets[1].cssRules) {
document.styleSheets[1].insertRule(rule, index);
} else if (document.styleSheets[1].rules) { //ie
document.styleSheets[1].addRule(rule, index);
}
}
Below is an approach that will work for any given rule-selector and rule-change function:
// general function for selecting rules and applying changes
function change_css_rules(changeRuleFunc, selectorFunc) {
[].concat.apply([], // flattens arrays
Array.from(document.styleSheets).map(function(sheet) { // each ss
return Array.from(sheet.cssRules).filter(function(rule) { // each rule
return selectorFunc(rule); // only select desired rules
});
})
).map(changeRuleFunc); // change the selected rules
}
Example use:
var my_changeRuleFunc = function(rule) {
rule.style.fontSize = '20px';
}
var my_selectorFunc = function(rule) {
return rule.selectorText == '.myClass'; // return true to select this rule
}
change_css_rules(my_changeRuleFunc, my_selectorFunc); // apply change to selected rules