58

I've run into a unique situation that I have so far been unable to find a solution for: dynamically assigning a value to a CSS style. I know how to use jQuery to assign width, height, etc. to an element, but what I'm trying to do is actually change the value defined in the stylesheet so that the dynamically-created value can be assigned to multiple elements.

What I'm building is a slideshow of images that occupy the full viewport, recalculating the image's width, height, and left properties on resize so that the image is always centered, favors width over height, except when the viewport is taller than it is wide (resizing does not reload the page, just fires a function to resize the image).

I have successfully been able to get it to work on one image, and now I'm trying to determine the best way to assign those property values to all images in the slideshow without having to specify those three things individually for every image.

My Question:

Can the values of properties in a class be modified on the fly? I'm sure the answer is out there, I'm probably just not using the correct terminology in my searches. Hope I did a good job of describing the problem. TIA.

Dan Beaulieu
20k19 gold badges107 silver badges138 bronze badges
asked Aug 19, 2011 at 17:51
1
  • 1
    See my answer explaining the use of CSS variables and the setProperty() method to change a CSS variable value. Commented Feb 16, 2021 at 21:09

15 Answers 15

30

Contrary to some of the answers here, editing the stylesheet itself with Javascript is not only possible, but higher performance. Simply doing $('.myclass').css('color: red') will end up looping through every item matching the selector and individually setting the style attribute. This is really inefficient and if you have hundreds of elements, it's going to cause problems.

Changing classes on the items is a better idea, but you still suffer from the same problem in that you're changing an attribute on N items, which could be a large number. A better solution might be to change the class on one single parent item or a small number of parents and then hit the target items using the "Cascade" in css. This serves in most situations, but not all.

Sometimes you need to change the CSS of a lot of items to something dynamic, or there's no good way for you to do so by hitting a small number of parents. Changing the stylesheet itself, or adding a small new one to override the existing css is an extremely efficient way to change the display of items. You're only interacting with the DOM in one spot and the browser can handle deploying those changes really efficiently.

jss is one library that helps make it easier to directly edit the stylesheet from javascript.

answered Aug 19, 2011 at 18:20

1 Comment

jss so far is working out to be a good solution to modifying the style directly instead walking the DOM applying styles to things. Wish I'd found this a few years ago.
23

Demo, IE demo

You could use the following function:

function setStyle(cssText) {
 var sheet = document.createElement('style');
 sheet.type = 'text/css';
 /* Optional */ window.customSheet = sheet;
 (document.head || document.getElementsByTagName('head')[0]).appendChild(sheet);
 return (setStyle = function(cssText, node) {
 if(!node || node.parentNode !== sheet)
 return sheet.appendChild(document.createTextNode(cssText));
 node.nodeValue = cssText;
 return node;
 })(cssText);
};

Features:

  • The function is written in vanilla-js, so it has better performance than jQuery alternatives
  • One stylesheet is created after the first call to setStyle, so if you don't call it, it won't create any stylesheet.
  • The same stylesheet is reused for the following calls of setStyle
  • The function return a reference to the node associated with the bunch of CSS that you have added. If you call the function again with that node as a second argument, it will replace the old CSS with the new one.

Example

var myCSS = setStyle('*{ color:red; }');
setStyle('*{ color:blue; }', myCSS); // Replaces the previous CSS with this one

Browser support

At least, it works on IE9, FF3, Chrome 1, Safari 4, Opera 10.5.

There's also an IE version which works both on modern browsers and old versions of IE! (Works on IE8 and IE7, but can crash IE6).

answered Oct 27, 2013 at 1:31

Comments

19

Nice question. A lot of the answers here had a solution directly contradicting what you were asking

"I know how to use jQuery to assign width, height, etc. to an element, but what I'm trying to do is actually change the value defined in the stylesheet so that the dynamically-created value can be assigned to multiple elements.
"

jQuery .css styles elements inline: it doesn't change the physical CSS rule! If you want to do this, I would suggest using a vanilla JavaScript solution:

document.styleSheets[0].cssRules[0].cssText = "\
 #myID {
 myRule: myValue;
 myOtherRule: myOtherValue;
 }";

This way, you're setting the stylesheet css rule, not appending an inline style.

Hope this helps!

answered Oct 27, 2013 at 1:38

3 Comments

I an unable to see any effect. Oriol's solution works but this one doesn't. My code is: document.styleSheets[0].cssRules[0].cssText = ".myClass{ background-color:red; }"; I don't get an error, but nothing is changed. Tried in Chrome 48 and IE8. What am I doing wrong?
cssText is IE only. :-(
This answer is contrary to the browsers I am using and developing for.
8

Like @benvie said, its more efficient to change a style sheet rather than using jQuery.css (which will loop through all of the elements in the set). It is also important not to add a new style to the head every time the function is called because it will create a memory leak and thousands of CSS rules that have to be individually applied by the browser. I would do something like this:

//Add the stylesheet once and store a cached jQuery object
var $style = $("<style type='text/css'>").appendTo('head'); 
function onResize() {
 var css = "\
 .someClass {\
 left: "+leftVal+";\
 width: "+widthVal+";\
 height: "+heightVal+";\
 }";
 $style.html(css);
}

This solution will change your styles by modifying the DOM only once per resize. Note that for effective js minification and compression, you probably don't want to pretty-print the css, but I did for clarity.

answered Oct 26, 2013 at 21:50

Comments

7

Use jquery to add a style override in the <head>:

$('<style>.someClass {color: red;} input::-webkit-outer-spin-button: {display: none;}</style>')
.appendTo('head'); 
Mike
24.5k14 gold badges84 silver badges93 bronze badges
answered Feb 4, 2013 at 22:53

1 Comment

+1 Your answer is much better than the others which use $('.myClass'). But yours could have a bad performance too if used lots of times (see Brian Peacock's answer)
5

I've got a solution for changing a value in specific CSS class. But it only works if you keep your CSS in the tag. If you just keep a link to your CSS from external files ex.

<style src='script.js'></style>

this solution won't work.

If your css looks like this for example:

<style id='style'>
.foo {
height:50px;
}
</style>

You can change a value of the tag using JS/jQuery.

I've written a function, perhaps it's not the best one but it works. You can improve it if you want.

function replaceClassProp(cl,prop,val){
if(!cl || !prop || !val){console.error('Wrong function arguments');return false;}
// Select style tag value
var tag = '#style';
 var style = $(tag).text();
 var str = style;
// Find the class you want to change
 var n = str.indexOf('.'+cl);
 str = str.substr(n,str.length);
 n = str.indexOf('}');
 str = str.substr(0,n+1);
 var before = str;
// Find specific property
 n = str.indexOf(prop);
 str = str.substr(n,str.length);
 n = str.indexOf(';');
 str = str.substr(0,n+1);
// Replace the property with values you selected
 var after = before.replace(str,prop+':'+val+';');
 style=style.replace(before,after);
// Submit changes
 $(tag).text(style);
}

Then just change the tag variable into your style tag id and exegute:

replaceClassProp('foo','height','50px');

The difference between this and $('.foo').css('height','50px'); is that when you do it with css method of jQuery, all elements that have .foo class will have visible style='height:50px' in DOM. If you do it my way, elements are untouched and the only thing youll see is class='foo'

Advantages

  • Clear DOM
  • You can modify the property you want without replacing the whole style

Disadvantages

  • Only internal CSS
  • You have to find specific style tag you want to edit

Hope it helps anyhow.

Manikandan C
6941 gold badge9 silver badges22 bronze badges
answered Apr 17, 2014 at 21:20

Comments

5

The way to dynamically modify a CSS property value in a CSS class is by using a CSS variable in the CSS class property value, and then use JavaScript and the DOM to change the CSS variable. The end result is that the styling on the device screen will immediately change when the code runs that sets the new CSS variable value. So, code changes the CSS variable, and the CSS variable is used in the CSS class setting. Note that a CSS class name and a JavaScript Class are two different things.

  • Use a CSS Variable
  • Put the CSS variable where the static CSS class property value would normally be
  • Use code to set a new CSS variable value
  • The change to the CSS variable changes the CSS class property value and that causes the styling on the device screen to change

CSS - Styling

<style>
 :root { /* Set CSS variable values - These values can be changed with JavaScript 
 and DOM */
 --myCSS_ValueOne: initialValue;
 }
 .classNameHere {
 property_Name_Here: var(--myCSS_ValueOne);/* This CSS property gets its value from
 the CSS variable */
 }
</style>

JavaScript and DOM

<script>
 var r = document.querySelector(':root');//Get global root element
 function setA_NewCSS_VariableValue() {
 r.style.setProperty('--myCSS_ValueOne', 'the_New_Value');// Set a new CSS variable
 //value which immediately changes the CSS class setting because the CSS
 //property setting uses a CSS Variable -
 }
</script>

It is also possible to run a function in response to media queries (changes in the device viewport - like width of the device screen) using the matchMedia() method.

var x = window.matchMedia("(max-width: 300px)")
x.addListener(setA_NewCSS_VariableValue) // create a listener function that runs
//when the viewport is less than, or equal to, 300 pixels wide.
answered Feb 16, 2021 at 20:50

Comments

3

You can't modify the members of a CSS class on the fly. However, you could introduce a new <style> tag on the page with your new css class implementation, and then switch out the class. Example:

Sample.css
.someClass { border: 1px solid black; font-size: 20px; }

You want to change that class entirely, so you create a new style element:

<style>
 .someClassReplacement { border: 1px solid white; font-size: 14px; } 
</style>

You then do a simple replacement via jQuery:

$('.someClass').removeClass('someClass').addClass('someClassReplacement');
answered Aug 19, 2011 at 17:57

Comments

3
function changeStyle(findSelector, newRules) {
 // Change original css style declaration. 
 for ( s in document.styleSheets ) {
 var CssRulesStyle = document.styleSheets[s].cssRules;
 for ( x in CssRulesStyle ) {
 if ( CssRulesStyle[x].selectorText == findSelector) {
 for ( cssprop in newRules ) {
 CssRulesStyle[x].style[cssprop] = newRules[cssprop];
 }
 return true;
 }
 }
 }
 return false;
}
changeStyle('#exact .myStyle .declaration', {'width':'200px', 'height':'400px', 'color':'#F00'});
answered Jul 22, 2017 at 21:19

Comments

2

Why not just use a .class selector to modify the properties of every object in that class?

ie:

$('.myclass').css('color: red;');

Teja Kantamneni
17.5k12 gold badges58 silver badges86 bronze badges
answered Aug 19, 2011 at 17:56

2 Comments

Because it's very inefficient
Also, this applies the style directly to the element, so if you add other elements with this class to the DOM, the above jQuery will need to be rerun to see those effects.
1

YUI 2 and 3 has a module stylesheet that will let you do just that (edit stylesheets on the fly with javascript). http://yuilibrary.com/yui/docs/stylesheet/. So I think it is possible. This is not the same as $(".some").css({...}) but really change/add/remove styles definition from stylesheet, just like the user asked.

answered Aug 19, 2013 at 14:11

Comments

1

Okay.. had the same problem and fixed it, but the solution may not be for everyone.

If you know the indexes of the style sheet and rule you want to delete, try something like document.styleSheets[1].deleteRule(0); .

From the start, I had my main.css (index 0) file. Then, I created a new file, js_edit.css (index 1), that only contained one rule with the properties I wanted to remove when the page had finished loading (after a bunch of other JS functions too).

Now, since js_edit.css loads after main.css, you can just insert/delete rules in js_edit.css as you please and they will override the ones in main.css.

var x = document.styleSheets[1];
x.insertRule("p { font-size: 2rem; }", x.cssRules.length);

x.cssRules.length returns the number of rules in the second (index 1) style sheet thus inserting the new rule at the end.

I'm sure you can use a bunch of for-loops to search for the rule/property you want to modify and then rewrite the whole rule within the same sheet, but I found this way simpler for my needs.

http://www.quirksmode.org/dom/w3c_css.html helped me a lot.

answered Dec 1, 2015 at 17:26

Comments

1

This may be late to the discussion, but I needed something like what is being talked about here, but didn't find anything that really did what I wanted, and did it easily. What I needed was to hide and show numerous elements without explicitly visiting each element individually to update them in some way that changed the display style to and from hidden. So I came up with the following:

<style>
 /* The bulk of the css rules should go here or in an external css file */
 /* None of these rules will be changed, but may be overridden */
 .aclass { display: inline-block; width: 50px; height: 30px; }
</style>
<style id="style">
 /* Only the rules to be changed should go in this style */
 .bclass { display: inline-block; }
</style>
<script>
 //
 // This is a helper function that returns the named style as an object.
 // This could also be done in other ways.
 // 
 function setStyle() { return document.getElementById( 'style' ); }
</script>
<div id="d1" class="aclass" style="background-color: green;">
 Hi
</div>
<!-- The element to be shown and hidden --> 
<div id="d2" class="aclass bclass" style="background-color: yellow;">
 there
</div>
<div id="d3" class="aclass" style="background-color: lightblue;">
 sailor
</div>
<hr />
<!-- These buttons demonstrate hiding and showing the d3 dive element -->
<button onclick="setStyle().innerHTML = '.bclass { display: none; }';">
 Hide
</button>&nbsp;&nbsp;
<button onclick="setStyle().innerHTML = '.bclass { display: inline-block; }';">
 Show
</button>

By toggling the bclass rule in the embedded and named stylesheet, which comes after the any other relevant style sheets, in this case one with the aclass rule, I could update the just the display css rule in one place and have it override the aclass rule, which also had it's own display rule.

The beauty of this technique is that it is so simple, effectively one line that does the actual work, it doesn't require any libraries, such as JQuery or plug-ins, and the real work of updating all of the places where the change applies is performed by the browser's css core functionality, not in JavaScript. Also, it works in IE 9 and above, Chrome, Safari, Opera, and all of the other browsers that MicroSoft Edge could emulate, for desktop and tablet/phones devices.

answered Aug 22, 2016 at 10:25

Comments

1

You should really rethink your approach to this issue. Using a well crafted selector and attaching the class may be a more elegant solution to this approach. As far as I know you cannot modify external CSS.

Cornelius Dol
64.2k26 gold badges142 silver badges189 bronze badges
answered Aug 19, 2011 at 17:55

Comments

0

This solution modifies Cycne's to use ES6 syntax and exit the loop early for external stylesheets. This solution does not modify external stylesheets

function changeStyle(findSelector, newDeclarations) {
 // Change original css style declaration.
 document.styleSheets.forEach((sheet) => {
 if (sheet.href) return;
 const cssRulesList = sheet.cssRules;
 cssRulesList.forEach((styleRule) => {
 if (styleRule.selectorText === findSelector) {
 Object.keys(newDeclarations).forEach((cssProp) => {
 styleRule.style[cssProp] = newDeclarations[cssProp];
 });
 }
 });
 });
 }
 const styleDeclarations = {
 'width': '200px',
 'height': '400px',
 'color': '#F00'
 };
 changeStyle('.paintBox', styleDeclarations);

You must also have at least one style tag in your HTML head section, for example

<style> .paintBox {background-color: white;}</style>
answered Dec 12, 2017 at 11:54

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.