204

Usually I have a CSS file which has the following rule:

#my-window {
    position: fixed;
    z-index: 102;
    display:none;
    top:50%;
    left:50%;
}

How can I avoid creating such a static CSS file by adding the CSS information during runtime actions to the body, or something similar? (only using jQuery)

I want to define it once but with jQuery and use it many times later; that's why I do not want to add it each time to the specific DOM elements.

I know the simple features (css("attr1", "value");), but how can I create a complete reusable CSS rule?

tckmn
  • 57,719
  • 27
  • 114
  • 156
stephan
  • 2,321
  • 4
  • 19
  • 15

22 Answers22

285

You can create style element and insert it into DOM

$("<style type='text/css'> .redbold{ color:#f00; font-weight:bold;} </style>").appendTo("head");
$("<div/>").addClass("redbold").text("SOME NEW TEXT").appendTo("body");

tested on Opera10 FF3.5 iE8 iE6

Taras Bulba
  • 2,867
  • 1
  • 15
  • 2
  • The gist is self sufficient. You can create it locally, and it will work just fine. Direct link to the download link: https://gist.github.com/gists/714352/download – Daniel Ribeiro Nov 25 '10 at 19:43
  • No problem. Sometimes it can be jQuery minor version bug, or just an incorrect setup. The deal with js apps is this: if they don't work, they just don't work at all. No forgiveness. – Daniel Ribeiro Nov 27 '10 at 00:37
  • 1
    Throws an '[Unexpected call to method or property access](http://jsfiddle.net/K5zpD/1/)' error for me in IE8. I had to follow [this article](http://www.phpied.com/dynamic-script-and-style-elements-in-ie/) to get it working. – Brandon Boone May 07 '12 at 13:24
  • 6
    There can be only 31 styles in page in IE9- http://blogs.msdn.com/b/ieinternals/archive/2011/05/14/internet-explorer-stylesheet-rule-selector-import-sheet-limit-maximum.aspx – IvanH Nov 16 '12 at 13:22
  • 1
    If it doesn't work. Try append style to `body`. i.e. `$("").appendTo("body");` – inDream Mar 21 '13 at 11:33
  • Problem with that method is you can only ADD rules that cannot be removed afterwards. – andreszs Dec 21 '14 at 01:22
  • 1
    @Andrew Can't you just define the style tag with an ID and then remove it later matching that ID? – Koert van Kleef Jan 15 '15 at 15:07
  • I never heard of style tags with ID, but that might be possible, yes. – andreszs Jan 15 '15 at 22:00
133

Simply

$("<style>")
    .prop("type", "text/css")
    .html("\
    #my-window {\
        position: fixed;\
        z-index: 102;\
        display:none;\
        top:50%;\
        left:50%;\
    }")
    .appendTo("head");

Noticed the back slashes? They are used to join strings that are on new lines. Leaving them out generates an error.

joerick
  • 16,078
  • 4
  • 53
  • 57
Shadrack Orina
  • 7,713
  • 2
  • 31
  • 36
18

you can apply css an an object. So you can define your object in your javascript like this:

var my_css_class = { backgroundColor : 'blue', color : '#fff' };

And then simply apply it to all the elements you want

$("#myelement").css(my_css_class);

So it is reusable. What purpose would you do this for though?

Yuval Karmi
  • 26,277
  • 39
  • 124
  • 175
  • 22
    I would say this is a CSS rule and *not* a CSS class. – hippietrail Nov 22 '12 at 08:42
  • 18
    This answer is misleading. The asker wanted to create a CSS rule at runtime, not set the style of a particular element to a constant (reusable) CSS declaration. – Dan Dascalescu Dec 18 '12 at 12:28
  • 4
    It's not quite what they asked for, but it is the right solution :) Filling the dom with extra – Kevin Mar 24 '13 at 21:36
  • 3
    How will you remove these rules applied when you need to, that's possible with other solutions... – Vishwanath Aug 19 '14 at 05:20
  • @Kevin - that may be so but there are times when that's just what you need. for example - when an element is being re-created by some ajax script and you need to persist a new style rule. – But those new buttons though.. Mar 18 '16 at 16:45
  • This also doesn't work for modifying or creating pseudo-element styles rules. – ksoo Dec 10 '18 at 19:52
13

You can use insertRule if you don't need to support IE < 9, according to dottoro. There's a bit of cross browser code over there as well.

document.styleSheets[0].insertRule('#my-window {\
    position: fixed;\
    z-index: 102;\
    display:none;\
    top:50%;\
    left:50%;\
}', 0)
Sean
  • 2,632
  • 2
  • 27
  • 35
11

Here is a jquery plugin that allows you to inject CSS:

https://github.com/kajic/jquery-injectCSS

Example:

$.injectCSS({
    "#my-window": {
        "position": "fixed",
        "z-index": 102,
        "display": "none",
        "top": "50%",
        "left": "50%"
    }
});
Robert Kajic
  • 8,689
  • 4
  • 44
  • 43
9

If you don't want to hardcode the CSS into a CSS block/file, you can use jQuery to dynamically add CSS to HTML Elements, ID's, and Classes.

$(document).ready(function() {
  //Build your CSS.
  var body_tag_css = {
    "background-color": "#ddd",
    "font-weight": "",
    "color": "#000"
  }
  //Apply your CSS to the body tag.  You can enter any tag here, as
  //well as ID's and Classes.
  $("body").css(body_tag_css);
});
Mike Trpcic
  • 25,305
  • 8
  • 78
  • 114
  • 6
    This answer is not quite what the asker asked for. The asker wanted to create a CSS rule at runtime, not set the style of a particular element to a constant CSS declaration. – Dan Dascalescu Dec 18 '12 at 12:29
  • I understand, but this is an alternative solution, so I provided it. – Mike Trpcic Dec 18 '12 at 20:00
  • 2
    @MikeTrpcic The problem is that there are other people searching for this solution too - to add css rules to a page - and your answer doesn't solve that. – pinate Jul 01 '14 at 13:00
9

This isn't anything new compared to some of the other answers as it uses the concept described here and here, but I wanted to make use of JSON-style declaration:

function addCssRule(rule, css) {
  css = JSON.stringify(css).replace(/"/g, "").replace(/,/g, ";");
  $("<style>").prop("type", "text/css").html(rule + css).appendTo("head");
}

Usage:

addCssRule(".friend a, .parent a", {
  color: "green",
  "font-size": "20px"
});

I'm not sure if it covers all capabilities of CSS, but so far it works for me. If it doesn't, consider it a starting points for your own needs. :)

Community
  • 1
  • 1
sjngm
  • 12,423
  • 14
  • 84
  • 114
  • Just for clarity, I would suggest naming parameters `selector` and `body`. Replacement of comma will cause problems when specifying fonts or using rgb(), etc., but overall this idea is good. – Palec Aug 25 '20 at 14:29
6

Note that jQuery().css() doesn't change stylesheet rules, it just changes the style of each matched element.

Instead, here's a javascript function I wrote to modify the stylesheet rules themselves.

    /**
     * Modify an existing stylesheet.
     * - sheetId - the id of the <link> or <style> element that defines the stylesheet to be changed
     * - selector - the id/class/element part of the rule.  e.g. "div", ".sectionTitle", "#chapter2"
     * - property - the CSS attribute to be changed.  e.g. "border", "font-size"
     * - value - the new value for the CSS attribute.  e.g. "2px solid blue", "14px"
     */
    function changeCSS(sheetId, selector, property, value){
        var s = document.getElementById(sheetId).sheet;
        var rules = s.cssRules || s.rules;
        for(var i = rules.length - 1, found = false; i >= 0 && !found; i--){
            var r = rules[i];
            if(r.selectorText == selector){
                r.style.setProperty(property, value);
                found = true;
            }
        }
        if(!found){
            s.insertRule(selector + '{' + property + ':' + value + ';}', rules.length);
        }
    }

Advantages:

  • Styles can be computed in a <head> script before the DOM elements are created and therefore prior to the first rendering of the document, avoiding a visually-annoying render, then compute, then re-render. With jQuery, you'd have to wait for the DOM elements to be created, then re-style and re-render them.
  • Elements that are added dynamically after the restyle will automatically have the new styles applied without an extra call to jQuery(newElement).css()

Caveats:

  • I've used it on Chrome and IE10. I think it might need a little modification to make it work well on older versions of IE. In particular, older versions of IE might not have s.cssRules defined, so they will fall back to s.rules which has some peculiarities, such as odd/buggy behavior related to comma-delimited selectors, like "body, p". If you avoid those, you might be ok in older IE versions without modification, but I haven't tested it yet.
  • Currently selectors need to match exactly: use lower case, and be careful with comma-delimited lists; the order needs to match and they should be in the format "first, second" i.e the delimiter is a comma followed by a space character.
  • One could probably spend some additional time on it trying to detect and intelligently handle overlapping selectors, such as those in comma-delimited lists.
  • One could also add support for media queries and the !important modifier without too much trouble.

If you feel like making some improvements to this function, you'll find some useful API docs here: https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet

Craig
  • 555
  • 1
  • 4
  • 11
6

In (unusual) cases where you want to be able to dynamically change styles often -- e.g. a theme builder app -- adding <style> tags or calling CSSStyleSheet.insertRule() will result in a growing stylesheet, which can have performance and design debugging implications.

My approach only allows a single rule per selector/property combo, clearing any existing on setting any rule. The API is simple and flexible:

function addStyle(selector, rulename, value) {
    var stylesheet = getAppStylesheet();
    var cssRules = stylesheet.cssRules || stylesheet.rules;
    var rule = stylesheet.insertRule(selector + ' { ' + rulename + ':' + value + ';}', cssRules.length);
}

function clearStyle(selector, rulename) {
    var stylesheet = getAppStylesheet();
    var cssRules = stylesheet.cssRules || stylesheet.rules;
    for (var i=0; i<cssRules.length; i++) {
        var rule = cssRules[i];
        if (rule.selectorText == selector && rule.style[0] == rulename) {
            stylesheet.deleteRule(i);
            break;
        }
    }       
}

function addStyles(selector, rules) {
    var stylesheet = getAppStylesheet();
    var cssRules = stylesheet.cssRules || stylesheet.rules;
    for (var prop in rules) {
        addStyle(selector, prop, rules[prop]);
    }
}

function getAppStylesheet() {
    var stylesheet = document.getElementById('my-styles');
    if (!stylesheet) {
        stylesheet = $('<style id="my-styles">').appendTo('head')[0];
    }
    stylesheet = stylesheet.sheet;
    return stylesheet;
}

Usage:

addStyles('body', {
    'background-color': 'black',
    color: 'green',
    margin: 'auto'
});

clearStyle('body', 'background-color');
addStyle('body', 'color', '#333')
Jason Boyd
  • 1,192
  • 1
  • 9
  • 19
6

Adding custom rules is useful if you create a jQuery widget that requires custom CSS (such as extending the existing jQueryUI CSS framework for your particular widget). This solution builds on Taras's answer (the first one above).

Assuming your HTML markup has a button with an id of "addrule" and a div with an id of "target" containing some text:

jQuery code:

$( "#addrule" ).click(function () { addcssrule($("#target")); });

function addcssrule(target) 
{ 
var cssrules =  $("<style type='text/css'> </style>").appendTo("head");

cssrules.append(".redbold{ color:#f00; font-weight:bold;}"); 
cssrules.append(".newfont {font-family: arial;}"); 
target.addClass("redbold newfont");     
}       

The advantage of this approach is that you can reuse variable cssrules in your code to add or subtract rules at will. If cssrules is embedded in a persistent object such as a jQuery widget you have a persistent local variable to work with.

fbloggs
  • 179
  • 1
  • 9
  • What a nice idea! I used it in conjunction with the snippet on this page http://www.ssdtutorials.com/tutorials/title/jquery-flashing-text.html to allow for toggling a colour (the original would toggle a class only). Thanks! – bgmCoder Mar 27 '13 at 15:11
3

What if you dynamically wrote a < script > section on your page (with your dynamic rules) and then used jQuerys .addClass( class ) to add those dynamically created rules?

I have not tried this, just offering a theory that might work.

Bryan Denny
  • 27,363
  • 32
  • 109
  • 125
2

Bit of a lazy answer this, but the following article may help: http://www.javascriptkit.com/dhtmltutors/externalcss3.shtml

Also, try typing "modify css rules" into google

Not sure whatwould happen if you tried to wrap a document.styleSheets[0] with jQuery() though you could give it a try

James Wiseman
  • 29,946
  • 17
  • 95
  • 158
2

You can use this lib called cssobj

var result = cssobj({'#my-window': {
  position: 'fixed',
  zIndex: '102',
  display:'none',
  top:'50%',
  left:'50%'
}})

Any time you can update your rules like this:

result.obj['#my-window'].display = 'block'
result.update()

Then you got the rule changed. jQuery is not the lib doing this.

James Yang
  • 1,306
  • 4
  • 15
  • 25
2

You can use a the cssRule plug-in. The code was simple then:

$.cssRule("#my-window {
    position: fixed;
    z-index: 102;
    display:none;
    top:50%;
    left:50%;
}");

One of the comments so far asked why one would want to do such a thing. For example, creating styles for a list where each item needs a distinct background colour (eg. GCal's list of calendars) where the number of columns is not known until run time.

Robert Gowland
  • 7,677
  • 6
  • 40
  • 58
2

Here's a setup that gives command over colors with this json object

 "colors": {
    "Backlink": ["rgb(245,245,182)","rgb(160,82,45)"],
    "Blazer": ["rgb(240,240,240)"],
    "Body": ["rgb(192,192,192)"],
    "Tags": ["rgb(182,245,245)","rgb(0,0,0)"],
    "Crosslink": ["rgb(245,245,182)","rgb(160,82,45)"],
    "Key": ["rgb(182,245,182)","rgb(0,118,119)"],
    "Link": ["rgb(245,245,182)","rgb(160,82,45)"],
    "Link1": ["rgb(245,245,182)","rgb(160,82,45)"],
    "Link2": ["rgb(245,245,182)","rgb(160,82,45)"],
    "Manager": ["rgb(182,220,182)","rgb(0,118,119)"],
    "Monitor": ["rgb(255,230,225)","rgb(255,80,230)"],
    "Monitor1": ["rgb(255,230,225)","rgb(255,80,230)"],
    "Name": ["rgb(255,255,255)"],
    "Trail": ["rgb(240,240,240)"],
    "Option": ["rgb(240,240,240)","rgb(150,150,150)"]
  }

this function

 function colors(fig){
    var html,k,v,entry,
    html = []
    $.each(fig.colors,function(k,v){
        entry  = "." + k ;
        entry += "{ background-color :"+ v[0]+";";
        if(v[1]) entry += " color :"+ v[1]+";";
        entry += "}"
        html.push(entry)
    });
    $("head").append($(document.createElement("style"))
        .html(html.join("\n"))
    )
}

to produce this style element

.Backlink{ background-color :rgb(245,245,182); color :rgb(160,82,45);}
.Blazer{ background-color :rgb(240,240,240);}
.Body{ background-color :rgb(192,192,192);}
.Tags{ background-color :rgb(182,245,245); color :rgb(0,0,0);}
.Crosslink{ background-color :rgb(245,245,182); color :rgb(160,82,45);}
.Key{ background-color :rgb(182,245,182); color :rgb(0,118,119);}
.Link{ background-color :rgb(245,245,182); color :rgb(160,82,45);}
.Link1{ background-color :rgb(245,245,182); color :rgb(160,82,45);}
.Link2{ background-color :rgb(245,245,182); color :rgb(160,82,45);}
.Manager{ background-color :rgb(182,220,182); color :rgb(0,118,119);}
.Monitor{ background-color :rgb(255,230,225); color :rgb(255,80,230);}
.Monitor1{ background-color :rgb(255,230,225); color :rgb(255,80,230);}
.Name{ background-color :rgb(255,255,255);}
.Trail{ background-color :rgb(240,240,240);}
.Option{ background-color :rgb(240,240,240); color :rgb(150,150,150);}
Chris Glasier
  • 791
  • 2
  • 10
  • 21
1

Here you have a function to get the full definition of a CSS class:

getCSSStyle = function (className) {
   for (var i = 0; i < document.styleSheets.length; i++) {
       var classes = document.styleSheets[i].rules || document.styleSheets[i].cssRules;
       for (var x = 0; x < classes.length; x++) {
           if (classes[x].selectorText  && - 1 != classes[x].selectorText.indexOf(className)) {
               return classes[x].cssText || classes[x].style.cssText;
           }
       }
   }
   return '';
};
berniecc
  • 401
  • 4
  • 6
1

if you don' t want to assign a display:none to a css class, the right approach in to append to style, jQuery.Rule do the job.

I some cases you want to apply stiles before the append event of ajax content and fade content after append and this is it!

Mattia
  • 11
  • 1
0

I have been messing with some of this recently and i have used two different approaches when programming an iPhone / iPod site.

The first way I came across when looking for orientation changes so you can see whether the phone is portrait or landscape, this is a very static way but simple and clever:

In CSS :

#content_right,
#content_normal{
 display:none;
}

In JS File:

function updateOrientation(){
  var contentType = "show_";
  switch(window.orientation){
   case 0:
   contentType += "normal";
   break;

   case -90:
   contentType += "right";
   break; document.getElementById("page_wrapper").setAttribute("class",contentType);
}

In PHP/HTML (Import your JS file first then in body tag):

<body onorientationchange="updateOrientation();">

This basically chooses a different pre set CSS block to run depending on the result given back from the JS file.

Also the more dynamic way which I preferred was a very simple addition to a script tag or your JS file:

document.getelementbyid(id).style.backgroundColor = '#ffffff';

This works for most browsers but for IE it's best to take away it's ammunition with something tighter:

var yourID = document.getelementbyid(id); 
 if(yourID.currentstyle) { 
  yourID.style.backgroundColor = "#ffffff";      // for ie :@ 
 } else { 
  yourID.style.setProperty("background-color", "#ffffff");        // everything else :)
 }

Or you can use getElementByClass() and change a range of items.

Hope this helps!

Ash.

hippietrail
  • 15,848
  • 18
  • 99
  • 158
Ash
  • 8,583
  • 10
  • 39
  • 52
0

If you don't want to use any plugins mentioned here on the board, you could use a simple function, e.g.:

var addStyle = function (style) {
    var allStyles = new Array();
    $.each(style, function (selector, rules) {
        var arr = $.map(rules, function (value, prop) { return "    " + prop + ": " + value + ";"; });
        allStyles.push(selector + " {\n" + arr.join("\n") + "\n}");
    });
    $("<style>").prop("type", "text/css").html(allStyles.join("\n")).appendTo("head");
};

and then call:

addStyle({
    "#my-window": {
        "position": "fixed",
        "z-index": 102,
        "display": "none",
        "top": "50%",
        "left": "50%"
    }
});

This is how it looks in html:

<style type="text/css">
    #my-window {
        position: fixed;
        z-index: 102;
        display: none;
        top: 50%;
        left: 50%;
    }
</style>

I got inspired by some answers here on the board, e.g. the "appendTo" portion is borrowed from here

infografnet
  • 3,749
  • 1
  • 35
  • 35
-2

Maybe you can put the style information in a separate class in your css file, e.g.:

.specificstyle {
    position: fixed;
    z-index: 102;
    display:none;
    top:50%;
    left:50%;
}

and then use jQuery at the point of your choosing to add this classname to the element?

JorenB
  • 1,831
  • 2
  • 16
  • 27
  • 1
    and you don't want to put the information in the head section of your page either (between style tags)? – JorenB Jul 31 '09 at 13:45
-2

You could just make a css class called something like .fixed-object that has all your css in it...

.fixed-object{
    position: fixed;
    z-index: 102;
    display:none;
    top:50%;
    left:50%;
}

Then in jquery anytime you want something to have that style just add that class to it...

$(#my-window).addClass('fixed-object');

That seems like the easiest way to do it, unless I'm misunderstanding what you need done.

-10

By using .addClass() in jquery we can dynamically add style to elements on page. eg. we have style

.myStyle
{
  width:500px;
  height:300px;
  background-color:red;
 }

Now in ready state of jquery we can add css like .addClass(myStyle)

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
Avinash
  • 1,279
  • 1
  • 8
  • 3