What are good ways to detect whether a style sheet has loaded using vanilla JavaScript? I understand they do not have the same load event that images and scripts fire.
Loading as packed into a .js file (like with WebPack 'loaders') is not an option.
2022 update: All major browsers have now supported onload= on <link rel=stylesheet> tags for years, so that would be the obvious way to detect when CSS has loaded. Not also that external stylesheets in the head are blocking during page load, but can be added later with JS to make them asynchronous. It’s that scenario in which my question is relevant.
Test page: https://alanhogan.com/files/async-css/head-async-test-with-js.html
<link> elements have load and error events, but they are garanteed only for Chrome, Firefox and Opera. If you don't need to support IE or Safari, I think this is just enough:
<link rel="stylesheet" href="some_style.css" onload="anounceReady()">
EDIT: Just tested with IE11 and IE8, onload is supported but onerror isn't. I have no Mac at hand so I don't know how Safari handles them.
If you are going to support browsers don't have load event for <link> elements, or very old Chrome/Firefox, there is a commonly used easy dirty but working solution. Add a piece of probing rule set at the end of your CSS file, and detect the computed style of a certain probing element (usually invisible) via JavaScript.
HTML:
<div id="probe"></div>
CSS:
#probe {
position: absolute;
z-index: -1000;
}
JavaScript:
var probeStyle = getComputedStyle(document.getElementById('probe'));
probeStyle.zIndex; // expect "-1000" after CSS is loaded
Something like this:
function checkSheetLoaded (urlSpec) {
var ss = document.styleSheets;
for (var ii = 0, max = ss.length; ii < max; ii++) {
if (ss[ii].href.indexOf(urlSpec) >=0)
return true;
}
return false;
}
checkSheetLoaded('foo/bar.css');
Basically iterates over the stylesheet collection looking for a string match.
Related
One way would be to check if there is a .shadowRoot property on an element, however I need to return a boolean before the page is rendered.
One simple feature test would be:
if (document.head.createShadowRoot || document.head.attachShadow) {
// I can shadow DOM
} else {
// I can't
}
This will work even if you include the script in the head section and assumes no malicious scripts were added prior to yours (a safe assumption).
Currently, Chrome, Opera, and derived browsers (like Android browsers) support it.
For more information, visit: https://caniuse.com/#feat=shadowdomv1 and http://caniuse.com/#feat=shadowdom
Say I'm embedding a bit of HTML code in an existing website. I'd like to know what CSS classes are already available. Currently I could do this as follows:
View the source for the page
Search for links that include .css files
Browse the contents of those until I find a useful class
That's tedious, and not exhaustive.
What's a better way?
EDIT You can also do this in Chrome:
Inspect Element
Select "Resources" tab
Navigate to Frames/../Stylesheets
View contents of individual stylesheets
I guess what I'm looking for is a higher level, interpreted view of the CSS styles available: not simply the contents of the CSS files. So if one style was defined identically in multiple places, I'd only want to see it twice. If two different styles applied to the same element, I'd want to see the two side by side.
Let's assume I can't do this by embedding code.
Press F12 in Chrome and select a magnifying glass.
In IE it's Also F12 and then select a little arrow.
Firefox has a similar feature or you can download Firebug which is great for web developers.
I think Web Developer plugin for firefox might be help you. You can add it from here.
The W3 CSS validator tool http://jigsaw.w3.org/css-validator/ will show all available css styles available to a webpage you specify, underneath a list of faulty styles.
copy this code immediately before the closing tag of the page's body :
I got code from here: http://snipplr.com/view/6488/
Tested in Chrome
//CODE
<div id="allclasses" style="text-align:left">
</div>
<script type="text/javascript">
var allTags = document.body.getElementsByTagName('*');
var classNames = {};
for (var tg = 0; tg< allTags.length; tg++) {
var tag = allTags[tg];
if (tag.className) {
var classes = tag.className.split(" ");
for (var cn = 0; cn < classes.length; cn++){
var cName = classes[cn];
if (! classNames[cName])
{
classNames[cName] = true;
}
}
}
}
var classList = [];
for (var name in classNames)
classList.push(name+'<br />');
document.getElementById('allclasses').innerHTML = classList.sort();
</script>
Apparently adding <link rel="stylesheet" ... in the document body is considered a bad practice by W3C standards. The same for adding <style> blocks in the body...
So are there any standard-compliant solutions to add CSS outside of the <head> tag? Like at the end of the document.
If you only want to include your CSS styles on a specific events, there's nothing stopping you from doing so at the head:
var linkElement = document.createElement("link");
linkElement.rel = "stylesheet";
linkElement.href = "path/to/file.css"; //Replace here
document.head.appendChild(linkElement);
This has the added benefit of adding your stylesheet in an async way, which doesn't block the browser from downloading anything else.
One way to solve that issue is to load the CSS with .get() and, appending it to the head tag only when needed:
JQUERY
var css = "foobar.css";
var callback = function() {
alert("CSS is now included");
// your jquery plugin for a navigation menu or what ever...
};
$.get(css, function(data){
$("<style type=\"text/css\">" + data + "</style>").appendTo(document.head);
callback();
});
The callback function is useful to allow script code that depends on the CSS file to be properly formatted, to run only after the CSS as been added!
Only HTML5 allows it with the scoped attribute, but make sure you declare the DOCTYPE correctly.
<style type="text/css" scoped>
.textbox {
color: pink
}
</style>
I think this standard gets largely ignored by most once you start doing things like server side programming or DHTML.
For static HTML files, you definitely can/should follow the rule of only including CSS within the HEAD tag but for conditional output and interactivity it can sometimes simplify things to have conditional styling as well. Consider that in the end, this convolutes the resulting document. Even though browsers may render it just fine, if you yourself were to look at the source, it's just plain easier to read if all the styles defining the layout/display were within the HEAD. There are, of course, a number of other examples and reasons as to why it's bad practice.
The HTML standard exists apart from things like server side scripting and DHTML i.e. it's not the HTML/SSS/JavaScript standard.
If you are talking about an external css sheet, then the correct way is as follows:
<link href="....link to your style...." rel="stylesheet">
If you want to include an inline css, then you just need to do as follows:
<style>
....Your style here...
</style>
I have this simple import of a stylesheet with media-query condition:
<style>#import url(/red.css) (min-width:400px) and (max-width:599px);</style>
I was assuming that browser will not use and not even download the stylesheet. However, stylesheet gets downloaded (tested in Chrome). Therefore I want to ask, if there is simple pure-CSS way how to make browsers not covered by media query to ignore and forbid them downloading the stylesheet.
Thank you for any help.
EDIT: I will re-phrase my question. Can I by using CSS3 specify stylesheet which should be loaded by browser depending on media-query condition (viewport width) ?
Well as #BoltClock and #Wesley Murch already mentioned, the browser will download the CSS even if is not able to supported or even if is not going to use it at that time, cause he needs to be prepared for the time he will be able to do so.
So if you really do not want to download the CSS file until something happens, the you can try to validate when the page loads if certain conditions are meet and if so, then you can do a "lazy load" and store the commented code (type 8 element, that would be in this case your style tag) inside a newly created style tag child, and that will make the browser to validate the newly created content and will download the CSS file for the style to work.
Any question you may face trying to implement it, do not hesitate in asking some clarification, maybe i can help you with your problem.
UPDATE:
I already tested it and IT WORKS :D, so you can use this code to start, hope it helps
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>TEST CODE</title>
<script type="text/javascript">
function test(){
var elems = document.body.childNodes;
alert(elems);
for (var i = 0, il = elems.length; i < il; i++) {
var el = elems[i];
alert(el.nodeType);
if (el.nodeType == 8) {
var style = document.createElement('style');
style.innerHTML = el.nodeValue;
document.getElementById("css").appendChild(style);
break;
}
}
}
</script >
<style id="css">
</style>
</head>
<body onload="test()">
<!--#import url(red.css) (min-width:400px) and (max-width:599px);-->
</body>
</html>
NOTE:
I have not tried this on a style tag, just in images and stuffs like that, but i am sure (i have tried) that if you comment your style tag the browser do not download the CSS file, so maybe this is the way to go to accomplish what you want.
Is it possible to create a new property in CSS? For example, say you're developing a control that displays a photo and you want to add a property to css to control what style frame to have around the photo. Something like:
#myphoto { frame-style: fancy }
Is there some way to do this in a cross browser compatible manner, and how would you define whether the style inherits or not?
EDIT: It's a custom control - your JS code would deal with the style - I'm not expecting the browser to magically know what to do. I want the user to be able to style the control with CSS instead of JS.
Sure, why not. Check this out as an example: http://bililite.com/blog/2009/01/16/jquery-css-parser/
You may also be able to get away with using CSS classes instead of properties. Not sure if that works for what you're doing.
You can't. Browsers interpret CSS based on how their layout engines are coded to do so.
Unless you took an existing open source engine like WebKit or Gecko, added custom code to handle your custom CSS and made a browser that used your customized layout engine. But then only your implementation would understand your custom CSS.
Re your edit: it'd depend on whether you're able to read that style somehow. Typically browsers just instantly discard any properties they don't recognize, and CSS is not normally reachable by JavaScript because CSS code is not part of the DOM.
Or you could look at Jordan's answer.
If you'd prefer a straight JavaScript solution that uses no JS libraries, you could use the query string of a background-image to keep "custom properties" inside your CSS.
HTML
<div id="foo">hello</div>
CSS
#foo {
background: url('images/spacer.gif?bar=411');
}
JavaScript
getCustomCSSProperty('foo', 'bar');
Supporting JavaScript Functions
function getCustomCSSProperty(elId, propName)
{
var obj = document.getElementById(elId);
var bi = obj.currentStyle ? obj.currentStyle.backgroundImage : document.defaultView.getComputedStyle(obj, null).getPropertyValue('background-image');
var biurl = RegExp('url\\(["\\\']?([^"\\\']+)["\\\']?\\)').exec(bi);
return getParameterByName(propName, biurl[1]);
}
function getParameterByName(name, qs) {
var match = RegExp('[?&]' + name + '=([^&]*)').exec(qs);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
Demo:
http://jsfiddle.net/t2DYk/1/
Explanation:
http://refactorer.blogspot.com/2011/08/faking-custom-css-properties.html
I've tested the solution in IE 5.5-9, Chrome, Firefox, Opera, and Safari.