7

Goal

In my program I want to do both things with jquery/javascript:

  1. Change styling of css classes dynamically
  2. Add/remove classes to elements

Problem

To do the first thing I use $(".className").css() method, but it changes style only for those elements that already have className class, i.e. if I later add className to an element its style won't be new. How can I solve this?

Example

See it also at jsfiddle.

$("p").addClass("redclass");
$(".redclass").css("color", "darkRed");
$("span").addClass("redclass");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>I want to be red! And I am.</p>
<span>I want to be red too but I'm not :'(</span>

Result:

enter image description here

chirag
  • 1,761
  • 1
  • 17
  • 33
Filipp Voronov
  • 4,077
  • 5
  • 25
  • 32
  • 3
    Possible duplicate of [How to dynamically create CSS class in JavaScript and apply?](http://stackoverflow.com/questions/1720320/how-to-dynamically-create-css-class-in-javascript-and-apply) – Andreas Oct 01 '16 at 12:25
  • Nice question! my query: why `css` is appending `inline` in it? – Kunj Oct 01 '16 at 12:42
  • `css()` modifies the style attribute. So it doesn't matter *what* or *how many* classes you add. It does not define a *rule*, where a *property* is associated with a *selector*. – AA2992 Oct 01 '16 at 12:43
  • @Andreas, I want to change existing classes (some elements have it, some elements don't, some elements will have it via `.addClass(..)`), not create new one – Filipp Voronov Oct 01 '16 at 12:43
  • @AnkithAmtange, thank you for explaining _why_ this approach doesn't work! but the question is how to do it right :) – Filipp Voronov Oct 01 '16 at 12:45
  • 1
    I saw you marked an answer right. Just thought it would be nice to leave this. – AA2992 Oct 01 '16 at 12:46
  • 1
    @PhilipVoronov The linked question does exactly the same as the accepted answer... O.o – Andreas Oct 01 '16 at 12:46

4 Answers4

12

A more shorten format:

$("<style/>", {text: ".redclass {color: darkRed;}"}).appendTo('head');

The snippet:

$("<style/>", {text: ".redclass {color: darkRed;}"}).appendTo('head');


$("p").addClass("redclass");

$("span").addClass("redclass");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


<p>I want to be red! And I am.</p>
<span>I want to be red too but I'm not :'(</span>
gaetanoM
  • 41,594
  • 6
  • 42
  • 61
  • Only works so long as there's not a style tag affecting the element in the body. If so, it appears after anything in the head and thus still overrides your new stylesheet! Hint: try adding the following as the last element in the html `` - an unusual and unlikely scenario, sure - still worth a mention though. ;) – enhzflep Oct 01 '16 at 14:47
7

While other (working) answers have been supplied, they don't actually answer your question - namely, they don't change the specified css class, but instead override it by adding another rule later in the document.

They achieve this, basically:

Before

.someClass
{
  color: red;
}

After

.someClass
{
  color: red;
}

.someClass
{
  color: white;
}

When in many cases, a better option would see the color attribute of the existing rule altered.

Well, as it turns out - the browser maintains a collection of style-sheets, style-sheet rules and attributes of said rules. We may prefer instead, to find the existing rule and alter it. (We would certainly prefer a method that performed error checking over the one I present!)

The first console msg comes from the 1 instance of a #coords rule. The next three come from the 3 instances of the .that rule

function byId(id){return document.getElementById(id)}

window.addEventListener('load', onDocLoaded, false);

function onDocLoaded(evt)
{
 byId('goBtn').addEventListener('click', onGoBtnClicked, false);
}

function onGoBtnClicked(evt)
{
 alterExistingCSSRuleAttrib('#coords', 'background-color', 'blue');
 alterExistingCSSRuleAttrib('.that', 'color', 'red');
}

// useful for HtmlCollection, NodeList, String types (array-like types)
function forEach(array, callback, scope){for (var i=0,n=array.length; i<n; i++)callback.call(scope, array[i], i, array);} // passes back stuff we need

function alterExistingCSSRuleAttrib(selectorText, tgtAttribName, newValue)
{
 var styleSheets = document.styleSheets;
 forEach(styleSheets, styleSheetFunc);

 function styleSheetFunc(CSSStyleSheet)
 {
  forEach(CSSStyleSheet.cssRules, cssRuleFunc);
 }

 function cssRuleFunc(rule)
 {
  if (selectorText.indexOf(rule.selectorText) != -1)
  forEach(rule.style, cssRuleAttributeFunc);

  function cssRuleAttributeFunc(attribName)
  {
   if (attribName == tgtAttribName)
            {
    rule.style[attribName] = newValue;
                console.log('attribute replaced');
            }
  }
 }
}
#coords
{
    font-size: 0.75em;
 width: 10em;
 background-color: red;
}
.that
{
 color: blue;
}
<style>.that{color: green;font-size: 3em;font-weight: bold;}</style>

<button id='goBtn'>Change css rules</button>
 <div id='coords' class='that'>Test div</div>

<style>.that{color: blue;font-size: 2em;font-weight: bold;}</style>
enhzflep
  • 12,927
  • 2
  • 32
  • 51
5

@synthet1c has described the problem. My solution is:

$("head").append('<style></style>');
var element = $("head").children(':last');
element.html('.redclass{color: darkred;}');
0

What you are having issue with is that when you use the jQuery selector $('.redclass').css('color', 'darkRed') you are getting all the elements that currently have that class and using javascript to loop over the collection and set the style property.

You then set the class on the span after. Which was not included in the collection at the time of setting the color

You should set the class in your css file so it is distributed to all elements that have that class

console.log($('.redclass').length)
$("p").addClass("redclass");
console.log($('.redclass').length)
// $(".redclass").css("color", "darkRed");
$("span").addClass("redclass");
console.log($('.redclass').length)
.redclass {
  color: darkRed;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>I want to be red! And I am.</p>
<span>I want to be red too but I'm not :'(</span>
synthet1c
  • 6,152
  • 2
  • 24
  • 39
  • Yes, when it didn't work I thought about this (that `.css()` implemented this way), I just mentioned what I've tried. My question is how to do what I want right? – Filipp Voronov Oct 01 '16 at 12:30
  • changed the answer. The correct way is to create a class in your stylesheet as stated above. The only interaction with your style javascript should have is changing classes unless you are doing physics based animation. – synthet1c Oct 01 '16 at 12:32
  • what if I want to allow a user to change 'theme' (color of a table cells, for example) and at the same time the page can dynamically add these cells while a user works with the page? – Filipp Voronov Oct 01 '16 at 12:41
  • fair point, that is very specific and was not in the question. – synthet1c Oct 01 '16 at 12:44
  • I've tried to refine my situation to pure problem for better understanding – Filipp Voronov Oct 01 '16 at 12:52