3

Is there a quick and easy way to 'permanently' change properties of CSS with Javascript, D3JS, or JQuery? I've found this question which will change geometry already existing:

$('.myClass').css({ ...Your CSS properties here... });

However, I want to change a CSS property so that the geometry that is created in that session will have these updated changes as well. How can I, using Javascript, change the CSS class below from a stroke of steelblue to a stroke of light grey?

.P0{ fill:none;  stroke-width:1.25px; stroke:steelblue;}
Community
  • 1
  • 1
ekatz
  • 1,050
  • 1
  • 11
  • 29
  • 1
    do you want to update the css file? – Nouphal.M Jan 24 '14 at 03:22
  • Its not possible..all the changes gets reflected only on rendered page..whatever you do affects the DOM only... – Deepak Ingole Jan 24 '14 at 03:23
  • 1
    Save the styles to a cookie and then on page load inject them back into a ` – jammykam Jan 24 '14 at 04:17
  • If you want to change the CSS rule for the current webpage (existing and to-be-created elements) without creating cookies and reloading, you need to modify the CSSOM -- the CSS equivalent to the DOM: [MDN](https://developer.mozilla.org/en-US/docs/CSSOM) [W3 CSS Working Group](http://dev.w3.org/csswg/cssom/). This is different from (and more efficient than) the JQuery `.css` method or the d3 `.style` method, which both set inline styles on individual elements. (P.S., if you get it working, come back and answer your own question; if not, tag me in a comment and I'll work on it later.) – AmeliaBR Jan 24 '14 at 19:06
  • Thanks @AmeliaBR, this is exactly what I'm trying to do. Haven't figured it out yet though. – ekatz Jan 25 '14 at 00:45

1 Answers1

2

Magic CSS colour changing fiddle:

http://fiddle.jshell.net/8xkv3/3/

The key idea is to access the last stylesheet in the CSS Object Model, and add at the end of that stylesheet a CSS rule specifying the property you want for the selector you want. You want the last rule of the last stylesheet, so that it over-rides anything else in the cascade (except inline styles, of course).

The stylesheet objects in effect for the document are available as a list at document.styleSheets. Each one has a property cssRules which is a list of rules, which each represent a selector plus a list of property-value pairs.

The stylesheet.insertRule() method creates a new rule from a string, and adds it to the sheet at the specified index. Unfortunately, it just returns the index, not the rule object, so we have to re-select it to save for future modification.

You could just repeatedly add on new rules, each over-riding the previous, but that's not very efficient. The rule object has a "style" map with keys and values acting pretty much as you'd predict.

Edit

I realized there is a problem with the above approach. What happens if the last stylesheet in the list isn't being used by the current web-page? What if it's a print stylesheet? Or a stylesheet for tiny screenss, or speech synthesizers, or any other media-query limited situation? You could add a rule to that stylesheet object, but it wouldn't have any effect.

Clearly, what you need to do is create a new stylesheet object with no restrictions and/or with only the restrictions you chose. Then you can add this stylesheet to the end of the list and add your dynamic style rules to it.

You can't create a stylesheet object directly, but you can create a <style> element and add it to the html head object in the DOM. When the <style> object is added to the document a stylesheet object will be created for it, and can be accessed as the .sheet property of the element.

The amended fiddle is here: http://fiddle.jshell.net/8xkv3/6/

Key code:

    if (!rule) {
        //create a new page-wide style element            
        var styleElement = document.createElement("style");
        styleElement.type = "text/css"; 
        //probably not necessary (CSS is default), 
        //but it doesn't hurt to be explicit

        document.head.insertBefore(styleElement, null);  
        //once inserted in the document, a valid
        //CSSStyleSheet object is created and attached
        //to the styleElement object

        var styleSheet = styleElement.sheet;

        var ruleNum = styleSheet.cssRules.length;
        //console.log(styleSheet);
        styleSheet.insertRule(
            ".changeable{color:#"+hex[1]+";}", 
            ruleNum);
        rule = styleSheet.cssRules[ruleNum];
        //console.log(rule);
    }
    else { 
       rule.style["color"] = "#"+hex[1];
    };

By the way, I don't know why this didn't show up when I searched MDN previously, but here's a good article on the various ways of dynamically manipulating the CSS OM:
https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Using_dynamic_styling_information

AmeliaBR
  • 27,344
  • 6
  • 86
  • 119
  • P.S. Tested in latest Chrome, Firefox and Opera, and IE10. Only the webkit browsers give you colour picker dialogs, but everything else works the same. Testing on other browsers would be appreciated; leave a comment with results. *(IE8 had problems with standard Javascript like `getElementsByClassName` and `addEventListener` so I gave up trying to test if it supported CSSOM methods. If someone wants to write up a JQuery version of the fiddle and test it on IE8 that would be great.)* – AmeliaBR Jan 25 '14 at 02:49