Access CSS file contents via JavaScript - javascript

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!

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.

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.

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');

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);
});

Yep, you can use $.get.
Example:
$.get('/path/to/css/file.css', function (resp) {
// resp now should contain your CSS file content.
});

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?

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

Related

Is it possible to apply CSS on a web page with respective to URL of web page?

I have a basic question with CSS as am quite new to web development.
Can we apply CSS styles on a web page specific to the URL ?
I know CSS do not have if else conditions like we have for Javascript but I just to check if there is any smart way of doing it. Or it is not at all possible.
For example in javascript you do something like following:
if (window.location.href.indexOf("webpage1.com") > -1) {
.................
...................
................
}
Can we do something similar with CSS as well ?
Please provide me your valuable suggestions.
No. CSS has nothing that can read the URL of the page it is embedded on.
Uniquely identifying pages is usually done by adding an id to the html or body element.
It is not possible to connect CSS with the URL of the page but you can add a class or an id to the HTML element of your pages
HTML:
<html class="subpage">
CSS:
.subpage{ add some rules }
HTML:
<html class="main">
CSS:
.main{ add some different rules}
Its possible if you don't mind running a script after your content gets loaded.
The script could get the hostname and use it as a className to attach to the element you want to change the styles based on the specific url, provided of course that the style are predefined. Example:
HTML
<div id="main">Hello World</div>
...
...
...
<script>document.getElementById("main").className = window.location.hostname.split( '.' ).join( '-' )</script>
CSS
#main {
color : red;
}
#main.fiddle-jshell-net {
color : green;
}
#main.google-net {
color : black;
}
see fiddle
If there are a lot of styles to be updated - to the extent that it would be worth adding an entirely new stylesheet to the bottom of the cascade - simply:
create a new stylesheet (eg. extra-styles.css)
if the condition is true, add a reference to that stylesheet to the DOM
Eg.
if (window.location.href.indexOf('page1') > -1) {
var extraStyles = document.createElement('link');
extraStyles.setAtttribute('rel', 'stylesheet');
extraStyles.setAtttribute('href', '/path/to/extra-styles.css');
document.head.appendChild('extraStyles');
}

Using JS, is it possible to return a list of all CSS stylesheets included in a page, when it loads?

Using jQuery or plain JavaScript, can I return a list of every stylesheet included in a page when it initially loads?
All I want to do is print out a list of stylesheet names into the console, no additional info on the stylesheets is required.
If I am correct, by Names you mean the file name of each stylesheet.
Consider this example:
jQuery("link[href*='.css']").each(function(){
console.log(jQuery(this).attr('href').split('/').pop());
});
Here I am using this link[href*='.css'] selector to select all (include the inactive) stylesheets.
if using jQuery:
console.log($('link[rel=stylesheet]'));
If you're using jQuery, you could do something along the lines of:
$(document).ready(function() {
console.log($("link[rel='stylesheet']").attr("href"));
});
https://jsfiddle.net/vzfhjg16/
This piece of code collects all links with the rel attribute on stylesheet, then iterates over them and logs their attribute href. You can use the line in the loop to display the stylesheet names anywhere you want to.
$("head link[rel='stylesheet']").each(function (){
console.log($(this).attr("href"));
});
Working example
try this,
var styles = document.styleSheets;
$(styles).each(function(index,value){
console.log(value.href==null ? null : value.href.split('/').pop())
});
var styleSheetList = document.styleSheets;
ref: https://developer.mozilla.org/en-US/docs/Web/API/Document/styleSheets

Need JS to modify the element following the script

I have a report authoring tool that lets me add descriptive text in the report header, prior to a table containing the data. The examples included with the tool show how include Javascript in the description for various special effects. I would like to change certain cells in the table into links to other reports. Here's the HTML produced by the reporting tool.
<div class="element-info">
<div class="description">My Description</div>
<div class="properties">
<table>...</table>
</div>
</div>
I have tried replacing "My Description" with the following, but (perhaps unsurprisingly) it's changing something other than the table.
<div>My Description
<script type="text/javascript">
// currentScript is supported in my version of Firefox.
var me = document.currentScript;
// go up two levels to get the enclosing div
var element_info = me.parentElement.parentElement;
// from there we want the properties div, then the table
var mytable = element_info.lastChild.firstChild;
mytable.style.color = "red";
</script>
</div>
I expect that the problem is that when the script runs, the HTML in the following div has not yet been parsed. Mozilla says that the defer attribute will be ignored in scripts without a src= attribute, and I've verified that it does nothing.
Although my example code is using plain Javascript, the authoring tool is based on jQuery, so it's full repertoire is available if needed.
If the problem involves the fact that the html hasn't yet been parsed, you can immediately gain a reference to the script, but only later utilize it, once the document is loaded. It would look like this:
<div>My Description
<script type="text/javascript">
// Get the reference immediately...
var script_of_interest = document.currentScript;
// And only use it once everything is loaded:
window.onload = function() {
var element_info = script_of_interest.parentElement.parentElement;
var mytable = element_info.lastChild.firstChild;
mytable.style.color = "red";
};
</script>
</div>
Make sure your the node your script operates on is loaded before the execution, otherwise your the node may be undefined or just nothing. You may try wrap your code with
$(document).ready(function(){
//your code
}).

Extrating embedded styles from an HTML page with JQuery

So, here's the problem...
I have to:
Grab a page of html via a REST API with a AJAX call,
Extract a table with a known id from that html (which, thankfully, is well-formed)
Extract the associated css for the table from a style block,
Append the table to a div on my page, and
Re-apply the original CSS
Therefore the parts of the page that I'm interested in are:
<style>
#tableid td.someclass {
...
}
#tableid td.anotherclass {
...
}
[etc etc ..]
</style>
And
<table id="tableid">
...
</table>
So, going through the list above 1,2 & 4 are no problem at all. It's 3 and 5 that are taxing the brain - there are no external stylesheets to worry about BTW, everything is in the page that I'm grabbing inside a single tag.
I guess I could extract the entire element and then append it to my page - but that is messy and could result in unwanted side-effects. What I'd like to do is just extract the styling that applies to #tableid and then apply them the table appended to my div.
Is there an elegant way to do that?
You could pull the styles from the header using a standard jQuery finder:
var styles = $('head style').text();
Then run a regular expression against it:
var tableID = 'tableid',
pattern = new RegExp('#'+ tableID + '[^}]+}', 'g'),
tableStyles = styles.match(pattern);
This should give you an array of styles for your table’s id. Now you can append these styles to your current document’s head:
$('<style/>', { text: tableStyles.join('\n') }).appendTo('head');
Your use case might require some fine–tuning, but this should approximately give you what you’re after.

How write to page without document.write length limitation

I'm very much not a javascript/html/css person.
Even so I find myself in the position of having to do a webpage. It's static the only thing you can do on it is click on flags to change dispay-language based on a cookie.
If the cookie says "this" I write text in one language, and if the cookie says "that" I write in another language. This works perfectly but I have to use lots of document.write statements and it's ugly and cumbersome.
Right now I type the text I want and use a macro in emacs to fold the text at about
80 chars and put document.write(" in the beginning of each line and "); at the end. I then paste it into the web page in a if(cookie_this) { } else { }.
There must be a better way to do it... Please?
Edit:
I was looking workaround for the limitations in document.write
Constraints:
No server side magic, that means no ruby/php/perl
One page only, or rather only one visible url
The solution should be simpler than the working one I have
Expanding on artlung's answer:
You can display or hide things given a lang attribute (or any other criteria, such as a class name). In jQuery and HTML:
<p>Language:
<select id="languageSelector">
<option value="en">English</option>
<option value="es">Español</option>
</select>
</p>
<div lang="en-us">
Hello
</div>
<div lang="es">
Hola
</div>
<script type="text/javascript">
var defaultLanguage = 'en';
var validLanguages = ['en', 'es'];
function setLanguage(lang, setCookie) {
if(!$.inArray(languages, lang))
lang = defaultLang;
if(typeof(setCookie) != 'undefined' && setCookie) {
$.cookie('language', lang);
}
// Hide all things which can be hidden due to language.
$('*[lang]').filter(function() { return $.inArray(languages, $(this).attr('lang')); }).hide();
// Show currently selected language.
$('*[lang^=' + lang + ']).show();
}
$(function() {
var lang = $.cookie('language'); // use jQuery.cookie plugin
setLanguage(lang);
$('#languageSelector').change(function() {
setLanguage($(this).val(), true);
});
});
</script>
jQuery can do this with I lot less ease, but you could create an element then set that elements innerHTML property. You may have to change your call slightly so that you append the child element. See createElement function for more info. For example
<script type="text/javascript">
function writeElement(language, elementId) {
var newElement = document.createElement("span");
if (language = "this") {
newElement.innerHTML = "text for this";
}
else {
newElement.innerHTML = "text for that";
}
var element = document.getElementById(elementId);
element.appendChild(newElement);
}
</script>
Usage
<span id="data1"></span>
<script type="text/javascript">
writeElement("this", "data1")
</script>
Add a comment if you can support jQuery and you want a sample of that instead.
I think that the right way to approach this is to parse the Accept-Language header, and do this server-side.
But in the instance that you are stuck with client-side scripting. Say your content was marked like this
<script type="text/javascript">
if(cookie_this) {
document.getElementById('esContent').style.display = 'block';
} else {
document.getElementById('enContent').style.display = 'block';
}
</script>
<div id="esContent" style="display:none">
Hola, mundo.
</div>
<div id="enContent" style="display:none">
Hello, world.
</div>
This does not degrade for people with CSS enabled, and JavaScript disabled. Other approaches might include using Ajax to load content based on a cookie value (you could use jQuery for this).
If you just want one visible URL, but can host multiple pages on the server you could also try XHR. I use jQuery because I am most familiar with it although it would be possible to implement in javascript alone:
<html>
<head>
<script type="text/javascript" src="path/to/jquery.js"> </script>
<script type="text/javascript">
$(document).ready(function () {
if (cookie_this) {
$("body").load("onelanguage.html body");
} else {
$("body").load("otherlanguage.html body");
}
});
</script>
</head>
<body>
</body>
</html>
The detection should be on the server (preferably based on the Accept-Language header the client sent), and you should send a static file that has already been localized.
This does not fit the (edited) criteria of the original question, but may be useful regardless.
Use a server-side script. What you're looking for can easily be done in PHP. You'd probably want a hierarchy of documents based on language, and would look up given that. For example, a directory tree:
/en/
/en/page1.html
/en/page2.html
/es/
/es/page1.html
/es/page2.html
In PHP it's as simple as
$language = $_GET['lang'];
$page = $_GET['page'];
include($language . '/' . $page);
// URL is: /whatever.php?lang=LANGUAGE_HERE&page=PAGE_HERE
However, that has many security issues along with it. Sanitize your input and make sure the directory and file exist. Fuller example:
$contentRoot = './'; // CHANGE ME. Do include trailing /.
$defaultLanguage = 'en'; // CHANGE ME.
$defaultPage = 'home'; // CHANGE ME.
if(isset($_GET['lang']))
$language = $_GET['lang'];
else
$language = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 2);
if(isset($_GET['page']))
$page = $_GET['page'];
else
$page = $defaultPage;
$languageDir = basename($_GET['lang']) . '/';
$pageFile = basename($page) . '.html';
if(!file_exists($contentRoot . $languageDir) || !is_dir($contentRoot . $languageDir))
$languageDir = $defaultLanguage;
$fullFileName = $contentRoot . $languageDir . $pageFile;
if(!file_exists($fullFileName) || !is_file($fullFileName) || !is_readable($fullFileName))
$pageFile = $defaultPage;
readfile($fullFileName);
// Or, if you want to parse PHP in the file:
include($fullFileName);
You may also want to use mod_rewrite (Apache) to allow URL's such as http://www.mysite.com/en/page1. (Just be sure to hide the actual page.)
// TODO mode_rewrite rules
Another approach is putting the above hierarchy into the document root and handing out URL's directly. This gives you less power (e.g. templating is more difficult), however, and you have to worry about external media being referenced properly.
If you're looking for a dynamic approach, on the client side use Javascript to fetch the data using Ajax. This is also trivial, and does not require a dynamic server backend. I recommend a Javascript framework such as jQuery to make this as easy as possible.
There is no good way to do this in JS. The best way is to use VERY simple PHP code.
But, if you want, there is a way in JS - prepare pages like these:
some pages with different language versions, like index_en.html, index_ru.html
main index.html page, where you have code like
if(cookie) windows.location.replace('index_en.html') else ...

Categories