Access CSS File Contents via JavaScript

Access CSS file contents via JavaScript

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.

Is it possible to get the contents of an external css file using javascript to add to an svg file?

If you are able to use JavaScript you can get the contents of your stylesheet as follows:

[].slice.call(document.styleSheets[1].cssRules).forEach(function(rule){
console.log('rule:', rule.cssText)
})

Where document.styleSheets[1] is your stylesheet.

How do $.get multiple css file contents?

A problem with your code is that $.when() does not accept an array of deferreds/promises as an argument. From the jQuery doc:

If a single argument is passed to jQuery.when() and it is not a Deferred or a Promise, it will be treated as a resolved Deferred and any doneCallbacks attached will be executed immediately.

So, passing an array of deferreds, just gives you the array right back.

Instead, it needs them passed as separate arguments and it provides the results as separate arguments to .done() as in:

$.when(d1, d2, d3).then(function(r1, r2, r3) {
console.log(r1, r2, r3);
});

If you have the deferreds in an array as you do in your code, you can use .apply() to pass them. And, then the results are again not given to you in an array, but in a series of separate arguments to .done() (again, really inconvenient).

So, you can change this code:

// jQuery get each of the css links
for (var i = 0; i < arrLinks.length; i++) {
var link = arrLinks[i];
arrDeferreds.push($.get(link));
}

// Fetch the css documents
$.when(arrDeferreds).done(function (response) {
var result = response; // response here is an array of Deferred objects
}

to this:

// jQuery get each of the css links
for (var i = 0; i < arrLinks.length; i++) {
var link = arrLinks[i];
arrDeferreds.push($.get(link));
}

// Fetch the css documents
$.when.apply($, arrDeferreds).done(function() {
// copy arguments object into an actual array
let results = Array.prototype.slice.call(arguments);
console.log(results);
}

Or, in ES6, you can just use Promise.all() which uses arrays:

// Fetch the css documents
Promise.all(arrDeferreds).then(function(results) {
console.log(results);
});

To make a long story short, in any sort of modern Javascript environment, use Promise.all() instead of $.when().


FYI, if you can't use Promise.all() or a polyfill for it, then I developed this $.all() implementation awhile ago that lets you use arrays:

// jQuery replacement for $.when() that works like Promise.all()
// Takes an array of promises and always returns an array of results, even if only one result
$.all = function(promises) {
if (!Array.isArray(promises)) {
throw new Error("$.all() must be passed an array of promises");
}
return $.when.apply($, promises).done(function () {
// if single argument was expanded into multiple arguments, then put it back into an array
// for consistency
var args = Array.prototype.slice.call(arguments, 0);
if (promises.length === 1 && arguments.length > 1) {
// put arguments into an array for consistency
return [args];
} else {
return args;
}
});
};

How do you read CSS rule values with JavaScript?

Adapted from here, building on scunliffe's answer:

function getStyle(className) {
var cssText = "";
var classes = document.styleSheets[0].rules || document.styleSheets[0].cssRules;
for (var x = 0; x < classes.length; x++) {
if (classes[x].selectorText == className) {
cssText += classes[x].cssText || classes[x].style.cssText;
}
}
return cssText;
}

alert(getStyle('.test'));

Replacing css file on the fly (and apply the new style to the page)

You can create a new link, and replace the old one with the new one. If you put it in a function, you can reuse it wherever it's needed.

The Javascript:

function changeCSS(cssFile, cssLinkIndex) {

var oldlink = document.getElementsByTagName("link").item(cssLinkIndex);

var newlink = document.createElement("link");
newlink.setAttribute("rel", "stylesheet");
newlink.setAttribute("type", "text/css");
newlink.setAttribute("href", cssFile);

document.getElementsByTagName("head").item(cssLinkIndex).replaceChild(newlink, oldlink);
}

The HTML:

<html>
<head>
<title>Changing CSS</title>
<link rel="stylesheet" type="text/css" href="positive.css"/>
</head>
<body>
<a href="#" onclick="changeCSS('positive.css', 0);">STYLE 1</a>
<a href="#" onclick="changeCSS('negative.css', 0);">STYLE 2</a>
</body>
</html>

For simplicity, I used inline javascript. In production you would want to use unobtrusive event listeners.

Convert CSS file to string in Javascript/Node.js

You just have to load the contents of the CSS file using NodeJS fs.readFileSync.

const fs = require('fs');

try {
const documentStyles = fs.readFileSync('styles/style.css');
const document = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
${documentStyles}
</style>
</head>
<body>
<p>Here's the test</p>
</body>
</html>
`;
} catch(e) {
console.log('Error:', e.stack);
}

How to load up CSS files using Javascript?

Here's the "old school" way of doing it, which hopefully works across all browsers. In theory, you would use setAttribute unfortunately IE6 doesn't support it consistently.

var cssId = 'myCss';  // you could encode the css path itself to generate id..
if (!document.getElementById(cssId))
{
var head = document.getElementsByTagName('head')[0];
var link = document.createElement('link');
link.id = cssId;
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = 'http://website.example/css/stylesheet.css';
link.media = 'all';
head.appendChild(link);
}

This example checks if the CSS was already added so it adds it only once.

Put that code into a JavaScript file, have the end-user simply include the JavaScript, and make sure the CSS path is absolute so it is loaded from your servers.

VanillaJS

Here is an example that uses plain JavaScript to inject a CSS link into the head element based on the filename portion of the URL:

<script type="text/javascript">
var file = location.pathname.split( "/" ).pop();

var link = document.createElement( "link" );
link.href = file.substr( 0, file.lastIndexOf( "." ) ) + ".css";
link.type = "text/css";
link.rel = "stylesheet";
link.media = "screen,print";

document.getElementsByTagName( "head" )[0].appendChild( link );
</script>

Insert the code just before the closing head tag and the CSS will be loaded before the page is rendered. Using an external JavaScript (.js) file will cause a Flash of unstyled content (FOUC) to appear.



Related Topics



Leave a reply



Submit