31

Is it possible to get the entire text content of a CSS file in a document? F.ex:

<link rel="stylesheet" id="css" href="/path/to/file.css">
<script>
    var cssFile = document.getElementById('css');
    // get text contents of cssFile
</script>

I’m not really into getting all the CSS rules via document.styleSheets, is there another way?

Update: There is the ajax option of course, I appreciate the answers given. But it seems rather unnecessary to reload a file using ajax that is already loaded in the browser. So if anyone knows another way to extract the text contents of a present CSS file (NOT the CSS rules), please post!

David Hellsing
  • 106,495
  • 44
  • 176
  • 212
  • possible duplicate of [How to read from CSS files with jQuery](http://stackoverflow.com/questions/2964439/how-to-read-from-css-files-with-jquery) – Diodeus - James MacFarlane Feb 07 '12 at 16:44
  • Do you want to edit css properties of an element using jquery or some other js technology. ? – Thilanka Feb 07 '12 at 16:46
  • you want the complete css file ?? – Vivek Chandra Feb 07 '12 at 16:47
  • @Diodeus it’s not a dup, as stated I’m not interested in parsing CSS values from a stylesheet, I’d like to extract the entire text contents. – David Hellsing Feb 07 '12 at 16:48
  • @Thilanka no, I want the entire content. Like you get when you do an ajax request to a text file. – David Hellsing Feb 07 '12 at 16:49
  • Note in regard to your update: the CSS file should be in your browser cache and assuming your server does not tell the browser that the file should not be cached for some reason, you will end up reading the cached version and not the server version and that should be fast. – Alexis Wilke Jul 06 '15 at 00:13

7 Answers7

31

With that specific example (where the CSS is on the same origin as the page), you could read the file as text via ajax:

$.ajax({
    url: "/path/to/file.css",
    dataType: "text",
    success: function(cssText) {
        // cssText will be a string containing the text of the file
    }
});

If you want to access the information in a more structured way, document.styleSheets is an array of the style sheets associated with the document. Each style sheet has a property called cssRules (or just rules on some browsers), which is an array of the text of each rule in the style sheet. Each rule has a cssText property. So you could loop through those, e.g.:

$.each(document.styleSheets, function(sheetIndex, sheet) {
    console.log("Looking at styleSheet[" + sheetIndex + "]:");
    $.each(sheet.cssRules || sheet.rules, function(ruleIndex, rule) {
        console.log("rule[" + ruleIndex + "]: " + rule.cssText);
    });
});

Live example - That example has one stylesheet with two rules.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • The document.styleSheet thing is nice, but not what I need. I need the EXACT text contents, not an array of rules to loop though. Perhaps I wasn’t clear on this. – David Hellsing Feb 07 '12 at 17:06
  • 1
    @David: Then you'll have to do the extra GET. Once the CSS text is loaded and parsed, as far as I'm aware the browser doesn't retain the original source of it. (This is true of HTML pages as well, which is why you see "view source" do a request to get the source text.) – T.J. Crowder Feb 07 '12 at 17:07
  • it would be possible load the content of css file via ajax and then create a – Fabrizio Calderan Feb 07 '12 at 17:18
  • @FabrizioCalderan: Oooh, cool idea! That would do the job with just a single GET. Seems to work, too, at least in Chrome, Firefox, Opera, and IE9: http://jsbin.com/avocar I wouldn't be surprised if earlier IE's required you to use `createTextNode` rather than just using jQuery's `text` function, but... (Update: IE6 doesn't even like it with `createTextNode`, but fine, so you have two GETs on old IEs.) – T.J. Crowder Feb 07 '12 at 17:26
  • @T.J.Crowder I think the HTML contents of a page would be accessible via `document.documentElement.innerHTML`. – David Hellsing Feb 08 '12 at 08:50
  • 1
    @David: No, when you access the `innerHTML` property, the browser *creates* an HTML string representing the current state of the DOM tree for the element (in that case, the whole document) you access it on. It's not at all the same as the source of the page, which may be formatted differently, may have actually *been* different because DOM manipulation has been done since, could have omitted tags that the browser includes, may have had comments browsers don't retain, different quoting around attributes, etc., etc. – T.J. Crowder Feb 08 '12 at 09:15
  • I just want to add, in case someone comes looking for this, the cssRules do not retain the browser specific (prefixed) styles so in case you are looking for editing css file, the only possible way to do is load the css data using ajax (as far as I know) – Kshitiz Apr 02 '13 at 09:25
  • Another note for folks is that as of recent Chrome update the above code won't work for external stylesheets (considered a CORS violation, but not enforced in old chrome) – Slater Victoroff Feb 04 '21 at 19:35
  • 1
    @SlaterVictoroff - Which part? I'd be surprised at an [SOP](http://en.wikipedia.org/wiki/Same_origin_policy) (not [CORS](http://www.w3.org/TR/access-control/), which is a way to loosen the SOP) violation for something on the same origin. – T.J. Crowder Feb 04 '21 at 22:22
  • Not on the same origin, but if you've got your css on a CDN for instance. Accessing .cssRules will throw an error. Mostly making a note because that was decidedly not true when this answer was originally written. – Slater Victoroff Feb 10 '21 at 17:58
22

you could load the content with a simple ajax get call, if stylesheet is included from the same domain

Edit after your update:
I tried this code (on FX10) as a proof of concept that uses only one request to the CSS but it seems a bit hacky to me and should be tested and verified. it also should be improved with some fallback if javascript is not available.

CSS (external file test.css)

div { border: 3px solid red;}

HTML/jQuery

<!doctype html >
<html>
    <head>
       <!-- provide a fallback if js not available -->
       <noscript>
          <link rel="stylesheet" href="test.css" />
       </noscript>
    </head>
    <body>

        <div></div>

        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.js"></script>
        <script>
        $(document).ready(function() {

            $.when($.get("test.css"))
            .done(function(response) {
                $('<style />').text(response).appendTo($('head'));
                $('div').html(response);
            });
        })
        </script>
    </body>
</html>

You should see the CSS code inside the div with a red border all around :)
Enjoy.

Fabrizio Calderan
  • 120,726
  • 26
  • 164
  • 177
  • 2
    Yea, just realized this and it works, but if there is a solution without an extra request to a file that is already loaded, I’d like to hear about it. – David Hellsing Feb 07 '12 at 16:49
  • @David: There is, and I've posted it. – T.J. Crowder Feb 07 '12 at 16:57
  • Nice approach. You really want to use `text`, not `html`. Live copy of your code using `text`: http://jsbin.com/elopak – T.J. Crowder Feb 07 '12 at 17:40
  • @T.J.Crowder just noticed and updated few seconds ago, thank you. I'd like to include a element inside a block, but i don't think would be valid html inside element. HTML5 would allow this? (http://dev.w3.org/html5/markup/noscript.html) – Fabrizio Calderan Feb 07 '12 at 17:43
  • @FabrizioCalderan: It's fine to use `noscript` in `head` (or nearly anywhere else); [reference](http://www.w3.org/TR/html5/scripting-1.html#the-noscript-element). That said, though, if it's okay to wait for the CSS until an ajax call completes, I'd put the `noscript` at the very bottom of the document instead. – T.J. Crowder Feb 07 '12 at 17:51
  • how would you use on the bottom? I've edited and put it in the header – Fabrizio Calderan Feb 07 '12 at 17:55
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/7433/discussion-between-fabrizio-calderan-and-t-j-crowder) – Fabrizio Calderan Feb 07 '12 at 19:41
  • @FabrizioCalderan: *"how would you use on the bottom?"* Just put the `noscript` stuff at the bottom, just before the ` – T.J. Crowder Feb 08 '12 at 09:17
6

The closest you can get to obtaining the stylesheet without using ajax is to indeed iterate over all CSS rules and concatenate them into a string. This yields the original file with all comments and excess whitespace removed. Which makes sense, as the browser only needs to keep the parsed style sheet in memory, not the original file. It is only 3 lines of code:

function css_text(x) { return x.cssText; }
var file = document.getElementById('css');
var content = Array.prototype.map.call(file.sheet.cssRules, css_text).join('\n');
bcmpinc
  • 3,202
  • 29
  • 36
  • 2
    It also removes styles that the browser doesn't understand. Which is exactly the reason I needed this. – Scindix Jun 20 '19 at 11:45
4

I think your best bet would be to load it with ajax with something like:

$.get("/path/to/file.css", function(cssContent){
    alert("My CSS = " + cssContent);
});
Adam Rackis
  • 82,527
  • 56
  • 270
  • 393
2

Yep, you can use $.get.

Example:

$.get('/path/to/css/file.css', function (resp) {
    // resp now should contain your CSS file content.

});
Geddy
  • 85
  • 11
0

If you used XMLHttpRequest to load the page you could get acces to those files without having to load them a second time.

it's preferable to not duplicate ton reduce bandwidth and efficiency.

what if the css is generated dynamically and is different depending on the time it is requested?

yan bellavance
  • 4,710
  • 20
  • 62
  • 93
0

You can access your loaded CSS by using document.styleSheets.

Devin Spikowski
  • 2,946
  • 2
  • 12
  • 13
Jeramy Usher
  • 31
  • 1
  • 6