Dynamic Loading of CSS files (continued)-cruel truth

Source: Internet
Author: User

Note: This article mainly references Stoyan Stefanov's article "When is a stylesheet really loaded?"

In the previous article "dynamic loading of CSS files", we mentioned how to detect whether to load CSS files dynamically.Complete. Note that loading is completed in two cases:

1) Loading successful 2) Loading failed

That is to say, there is no distinction between success and failure. You may be confused here. I loaded a CSS file dynamically and wrote 100 or 200 lines of code without even distinguishing whether the file was loaded successfully or not. This seems incomprehensible.

Beautiful illusion-how to judge the completion of CSS Loading

I will not throw a conclusion here, but first think about the question: how to dynamically load CSS files?

The following code is simple:

var node = document.createElement('link');node.rel = 'stylesheet';node.href = 'style.css';document.getElementsByTagName('head')[0].appendChild(node);

Well, the next question is: How can I determine whether the CSS file is fully loaded?

That's not easy, just a few lines of code to deal with, front-end old friends onload, onerror Debut:

Var node = document. createElement ('link'); node. rel = 'stylesheet ';
Node. type = 'text/css '; node. href = 'style.css'; node. onload = function () {alert ('loading successful! ') ;}; Node. onerror = function () {alert (' loading failed! ') ;}; Document. getElementsByTagName ('head') [0]. appendChild (node );

Well, that's right... Theoretically... Let's take a look at the description of resource loading in HTML 5, which is summarized as follows:

  1. The CSS file is loaded successfully and the load event is triggered on the link node.
  2. An error is triggered on the link node when the CSS file fails to be loaded.

Once the attempts to obtain the resource and its critical subresources are complete, the user agent must, if the loads were successful, queue a task to fire a simple event namedloadAtlinkElement, or, if the resource or one of its critical subresources failed to completely load for any reason (e.g. DNS error, HTTP 404 response, a connection being prematurely closed, unsupported Content-Type), queue a task to fire a simple event namederrorAtlinkElement. Non-network errors in processing the resource or its subresources (e.g. CSS parse errors, PNG decoding errors) are not failures for the purposes of this paragraph.

It looks pretty good. We know that this world has never been perfect. At least for the front-end, this world has nothing to do with perfection. Javascript has always been criticized for its syntax and poor browser compatibility. Put the above Code in IE (Version 9 and below, 10 has not been tested) and direct the file link to a non-existent file. For example, replace the returned result with 404 in fiddler:

Var node = document. createElement ('link'); node. href = 'none_exist_file.css '; // node. onload = function () {alert (' loaded successfully! ') ;}; Node. onerror = function () {alert (' loading failed! ') ;}; Document. getElementsByTagName ('head') [0]. appendChild (node );

So you see a prompt of Lili:

"Loading successful !"

Seeing whether there was a deep doubt about the world-I admit that I gave greetings to all the brothers who developed Internet Explorer at that time.

Well, this article is not about IE. Although IE is not perfect in detecting the loading status of CSS files, it is not very bad in comparison.

Slow down! Which means-What's worse? Yes, for example, earlier versions of firefox do not support onload.

 

How to determine the completion of CSS file loading-five solutions

Aside from all complaints and dissatisfaction, how can we determine whether a file is loaded based on past experience? There are generally the following methods:

  1. Listen to link. load
  2. Listen to link. addEventListener ('load', loadHandler, false );
  3. Listen for link. onreadystatechange
  4. Listen to document. styleSheets changes
  5. Use setTimeout to regularly check whether the style of the tag you created has changed (the tag is assigned to the style declared only in the Dynamically Loaded CSS file)

The sample code is as follows:

// Solution 1 link. onload = function () {alert ('css onload! ');}
// Solution 2 link. addEventListener ('load', function () {alert ('addeventlistener loaded! ') ;}, False );
// Solution 3 link. onreadystatechange = function () {var readyState = this. readyState; if (readyState = 'complete' | readyState = 'loaded') {alert ('readystatechange loaded! ');}};
// Solution 4 var curCSSNum = document. styleSheets. length; var timer = setInterval (function () {if (document. styleSheets. length> curCSSNum) {// Note: When you load a large number of files at a time, you need to determine which file has been loaded with alert ('document. styleSheets loaded! '); ClearInterval (timer) ;}, 50 );
Var div = document. createElement ('div '); div. className = 'pre _ defined_class '; // The style var timer = setTimeout (function () {// assume the role of the getStyle method in the loaded CSS file: obtain the value of the Tag feature style if (getStyle (div, 'display') = 'None') {alert ('settimeout check style loaded! '); Return;} setTimeout (arguments. callee, 50); // Continue check}, 50 );
  Test results of the five solutions

What are the actual test results? As follows:

Browser Check onload (onload/addEventListener) Link. onreadystatechange Check document. styleSheets. length Check the style of a specific label
IE OK, but the onload will also be triggered in 404 and other situations.

Feasible, but readyState in 404 or other cases

It is also complete or loaded

The test results are inconsistent with those on the Internet.

Additional verification required

OK
Chrome

1. Old Version: not OK

2. New Version: OK (such as 24.0)

Not OK OK (length is changed only after the file is loaded) OK
Firefox

1. Old Version: not OK (3.X)

2. New Version: OK (such as 16.0)

Not OK Not OK (length changes when a node is inserted) OK
Safari

1. Old Version: not OK (?)

2. New Version: OK (such as 6.0)

Not OK OK (length is changed only after the file is loaded) OK
Opera OK Not OK Not OK (length changes when a node is inserted) OK

 

 

 

 

 

 

 

 

 

 

 

Solution 1 and solution 2 are essentially the same. If possible, stoyan recommends that solution 5 be avoided as much as possible for the following reasons:

1) performance overhead (solution 4 is not good enough)

2) You need to add additional useless styles and have sufficient control over CSS files (CSS files may not be maintained by your own team)

Well, we will temporarily exclude solution 5 (in fact, the best compatibility). As you can see from the table, the solutions available for various browsers are as follows:

Browser Available solutions
IE Solution 1, solution 2, and solution 3
Chrome Solution 4
Firefox None
Safari Solution 4
Opera Solution 1 and 2

 

 

 

 

 

Firefox... When the heart of time thousands of grass mud horse in the happy Pentium... For firefox, stoyan has also tried other methods, such:

1. vodafterpaint ~)

2. document. styleSheets [N].Css Rules, only when the CSS file is loaded, document. styleSheets [N].Css Rules will change. However, due to the security restrictions of ff 3.5, if the CSS file is cross-origin, JS accesses document. styleSheets [N].Css Rules errors

  How to determine whether CSS is loaded in earlier firefox versions?

Just as stoyan was about to despair, Zach Leatherman found a solution in firefox:

  1. You createstyleElement, notlink
  2. Add@import "URL"
  3. Poll for access to that style node'scssRulesCollection

This solution utilizes the second point mentioned above and solves the cross-origin problem. The Code is as follows (the code is referenced from the original ):

var style = document.createElement('style');style.textContent = '@import "' + url + '"'; var fi = setInterval(function() {  try {    style.sheet.cssRules; // <--- MAGIC: only populated when file is loaded    CSSDone('listening to @import-ed cssRules');    clearInterval(fi);  } catch (e){}}, 10);   head.appendChild(style);

According to stoyan and Zach ideas, Ryan Grove will implement it in LazyLoad. If you are interested, you can refer to the source code.

There are some minor issues with the Ryan Grove code, such:

1. The configuration of CSS files, such as a.css, B .css, and a.css.

2. Check errors when the CSS file is successfully recorded due to errors in some judgment statements (see the first while loop of the pollWebkit method)

Despite this, we still want to thank Ryan for his work (sprinkling flowers). LZ removes the code loaded by js in LazyLoad based on actual needs and fixes the two obvious bugs mentioned above, for the modified source code and demo, see the article CSS file dynamic loading.

 

How to determine whether a CSS file fails to be loaded

Until now, we finally solved the problem of how to check whether the CSS file is loaded. Next, we will face another severe problem: how can we determine whether a file fails to be loaded?

Don't forget the onerror kids shoes! What is onerror support? -- The actual test, the situation is not optimistic, directly reference the work crystallization of the ancestors, the original link is as follows: http://seajs.org/tests/research/load-js-css/test.html

Css: Chrome/Safari:-WebKit >=535.23 and later versions support onload/onerror-earlier versions without any event to trigger Firefox: -Firefox> = 9.0 supports onload/onerror-earlier versions without any event triggering Opera:-will trigger onload-but when css 404 does not trigger onerror IE6-8: -onload and onreadystatechange will be triggered when the download succeeds and fails, and no onerror IE9:-the same IE6-8-onreadystatechange will trigger the solution repeatedly:-Old WebKit and Old Firefox, with the poll method: load-css.html-other browsers with onload/onerror Insufficiency:-Opera if 404, no event is triggered, it is possible that the module dependent on this css remains in the waiting state-onerror-poll cannot be distinguished in the IE6-8

It can be seen that the previous solution does not perfectly solve the problem of "determining the failure of loading CSS files" (it is quite frustrating. If you have an idea, please leave a message to inform me of the TAT)

There are two ways to solve the problem:

1. Timeout failure determination: sets the tvalue. When the loading time exceeds t, determines that the loading fails (simple and crude, currently used)

2. After determining whether the file is loaded, use solution 5 (check the style) to determine whether the CSS file fails to be loaded. The premise is that the file is not considered as a "timeout failure"

After consulting from multiple parties, tom, a colleague from other departments, provided a good idea. The implementation scheme has been wired to the project as a practical support:JSONP

 

CSS loading failure judgment-different ideas JSONP

It is set to style.css (the file to be loaded) and style. js. In style. js, a callback method is CSSLoadedCallback, and CSSLoadedCallback is used to do two things.

1)mark, indicating that style.js is successful (the style string in style.css is obtained on the webpage)

2) create a link tag and write the style strings passed in CSSLoadedCallback to the link tag.

The code in style. js is roughly as follows:

// The first CSS is the name of the CSS file to be loaded.
// The second parameter is the style in style.css.
CSSLoadedCallback ("style.css", ". hide {display: 'none';}. title {font-size: 14px ;}");

Therefore, the original judgment on whether the CSS loading failed was converted to the judgment on whether the JS loading failed. For about whether the JS loading failed, the previous test is as follows. Click here for the original article link:

With regard to the inability of IE6-8 to differentiate onerror, it is not a problem here (it can be achieved by determining whether the variable exists), that is, JSONP is a reliable solution.

Js: Chrome/Firefox/Safari/Opera:-onload is triggered when the download is successful, onerror is triggered when the download fails, and 200,302,304 is triggered when the download is successful, you only need to download the file.-download failure means that the file is not downloaded, for example, empty in earlier versions of 404-Opera. js this empty file will not trigger onload, the new version has no problem IE6-8:-download Success and Failure will trigger onreadystatechange, no onload/onerror-Success and Failure meaning the same as IE9: -onload/onerror, and onreadystatechange solution:-In Firefox, Chrome, Safari, Opera, IE9, onload + onerror-in the IE6-8, onreadystatechange is insufficient: -onerror cannot be distinguished Under the IE6-8

 

Summary:

1. Check whether the CSS file is successfully loaded. (check the label style when the file is loaded by multiple methods)

2. You can roughly check whether the CSS file fails to be loaded (the premise is that the CSS file has been loaded and cannot be accurately determined in earlier versions of chrome and opera)

3. The JSONP method can be used to accurately determine whether the file is successfully loaded or failed.

Written below:

This article has referenced many posts on the external site technical blog. If you have referenced the external site content but have not stated it, please refer to it!

  If there are any mistakes or omissions in this example, please point out. If you think the article is useful to you, click "recommended"

Reference:

Http://www.phpied.com/when-is-a-stylesheet-really-loaded/

Https://github.com/seajs/seajs/blob/master/src/util-request.js

Https://github.com/rgrove/lazyload/commit/6caf58525532ee8046c78a1b026f066bad46d32d

Http://www.zachleat.com/web/load-css-dynamically/

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.