fg-loadcss
Advanced tools
Comparing version 1.3.1 to 2.0.0-2
{ | ||
"name": "fg-loadcss", | ||
"version": "1.3.1", | ||
"version": "2.0.0-2", | ||
"description": "A function for loading CSS asynchronously", | ||
@@ -22,3 +22,3 @@ "main": "src/loadCSS.js", | ||
"grunt-contrib-qunit": "~1.0.1", | ||
"grunt-contrib-uglify": "^0.10.0", | ||
"grunt-contrib-uglify": "^3.0.1", | ||
"grunt-contrib-concat": "^0.5.1" | ||
@@ -25,0 +25,0 @@ }, |
@@ -9,3 +9,3 @@ # loadCSS | ||
Referencing CSS stylesheets with `link[rel=stylesheet]` or `@import` causes browsers to delay page rendering while a stylesheet loads. When loading stylesheets that are not critical to the initial rendering of a page, this blocking behavior is undesirable. The new `<link rel="preload">` standard enables us to load stylesheets asynchronously, without blocking rendering, and loadCSS provides a JavaScript polyfill for that feature to allow it to work across browsers, as well as providing its own JavaScript method for loading stylesheets. | ||
Referencing CSS stylesheets with `link[rel=stylesheet]` or `@import` causes browsers to delay page rendering while a stylesheet loads. When loading stylesheets that are not critical to the initial rendering of a page, this blocking behavior is undesirable. The new `<link rel="preload">` standard enables us to load stylesheets asynchronously, without blocking rendering, and loadCSS provides a JavaScript polyfill for that feature to allow it to work across browsers. Additionally, loadCSS offers a separate (and optional) JavaScript function for loading stylesheets dynamically. | ||
@@ -15,7 +15,7 @@ * Latest release: https://github.com/filamentgroup/loadCSS/releases | ||
## Recommended loadCSS Usage | ||
## How To Use loadCSS (Recommended example) | ||
LoadCSS is designed for loading CSS that is **not critical** to the initial rendering of the page, and desirable to load in an asynchronous manner. (_For the critical CSS rules, we recommend either inlining that CSS in a `style` element, or referencing it externally and server-pushing it using http/2. [Read more here](https://www.filamentgroup.com/lab/modernizing-delivery.html)_) | ||
loadCSS is designed to help load CSS files that are **not critical** to the initial rendering of the page, and instead desirable to load in an asynchronous manner. (_For including critical CSS in a page without blocking rendering, we recommend either inlining that CSS in a `style` element, or referencing it externally and server-pushing it using http/2. [Read more here](https://www.filamentgroup.com/lab/modernizing-delivery.html)_) | ||
The standard markup pattern for loading files asynchronously is: `<link rel="preload">` ([W3C Spec](https://www.w3.org/TR/2015/WD-preload-20150721/)). We recommend using this markup pattern to reference your non-critical CSS files. `loadCSS` and its rel=preload polyfill are designed to enable this markup to work in browsers that don't yet support this feature. | ||
The standard markup pattern for loading files asynchronously is: `<link rel="preload">` ([W3C Spec](https://www.w3.org/TR/2015/WD-preload-20150721/)). We recommend using this markup pattern to reference your non-critical CSS files. `loadCSS`'s rel=preload polyfill is designed to enable this markup to work in browsers that don't yet support this feature ([view link rel="preload" support status](http://caniuse.com/#feat=link-rel-preload)). | ||
@@ -28,3 +28,3 @@ For each CSS file you'd like to load asynchronously, use a `link` element like this: | ||
In browsers that support it, the `rel=preload` attribute will cause the browser to fetch the stylesheet, but it will not **apply** the CSS once it is loaded (it merely fetches it). To address this, we recommend using an `onload` attribute on the `link` that will do that for us as soon as the CSS finishes loading. | ||
In browsers that support it, the `rel=preload` attribute will cause the browser to fetch the stylesheet, but it will not **apply** the CSS once it is loaded (it merely fetches it). To address this, we recommend using an `onload` attribute on the `link` that will apply the CSS when it finishes loading. | ||
@@ -42,11 +42,16 @@ ```html | ||
After linking to your asynchronous stylesheet(s) this way, include the [loadCSS script](https://github.com/filamentgroup/loadCSS/blob/master/src/loadCSS.js), as well as the [loadCSS rel=preload polyfill script](https://github.com/filamentgroup/loadCSS/blob/master/src/cssrelpreload.js) in your page. These can be inlined or linked and http/2-pushed if possible. | ||
We also recommend `null`ing the onload handler once it is used, since some browsers will occasionally re-call the handler upon switching the rel attribute to `stylesheet`: | ||
```html | ||
<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.onload=null;this.rel='stylesheet'"> | ||
<noscript><link rel="stylesheet" href="path/to/mystylesheet.css"></noscript> | ||
``` | ||
After linking to your asynchronous stylesheet(s) this way, include the the [loadCSS rel=preload polyfill script](src/cssrelpreload.js) in your page. This file should be inlined or linked with http/2 server-push (a simple external script ). | ||
Here's how they would look inlined in the page: | ||
```html | ||
<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'"> | ||
<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.onload=null;this.rel='stylesheet'"> | ||
<noscript><link rel="stylesheet" href="path/to/mystylesheet.css"></noscript> | ||
<script> | ||
/*! loadCSS. [c]2017 Filament Group, Inc. MIT License */ | ||
(function(){ ... }()); | ||
/*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */ | ||
@@ -56,6 +61,8 @@ (function(){ ... }()); | ||
``` | ||
These scripts will automatically detect if a browser supports `rel=preload`. In browsers that natively support `rel=preload`, these scripts will do nothing, allowing the browser to load and apply the asynchronous CSS (note the `onload` attribute above, which is there to set the `link`'s `rel` attribute to stylesheet once it finishes loading in browsers that support `rel=preload`). In browsers that do not support `rel=preload`, they will find CSS files referenced this way in the DOM and load and apply them asynchronously using the loadCSS function. | ||
By including this script (_which became standalone and no longer dependent on loadCSS.js as of version 2.0_) will automatically detect if a browser supports `rel=preload`. In browsers that natively support `rel=preload`, the script will do nothing, allowing the browser to load and apply the asynchronous CSS (note the `onload` attribute above, which is there to set the `link`'s `rel` attribute to stylesheet once it finishes loading). | ||
Note: regardless of whether the browser supports `rel=preload` or not, a CSS file will be referenced from the same location in the source order as your original `link` element. Keep this in mind, as you may want to place the `link` in a particular location in your `head` element so that the CSS loads with an expected cascade order. Also, any `media` attribute value on the original link element will be retained when the polyfill is in play. | ||
In browsers that do not support `rel=preload`, the script will apply a workaround (by temporarily manipulating the media attribute) to ensure that the file loads and applies asynchronously. It will also continue at a short interval to look for link elements in the DOM that need to be polyfilled. This means that the script will work from any location in the DOM (before or after the preload link(s)), but we do recommend placing the script **immediately after** all preload links for best performance. | ||
Note: regardless of whether the browser supports `rel=preload` or not, the original link element in the source will be used to fetch and apply the stylesheet. Keep this in mind, as you may want to place the `link` in a particular location in your `head` element so that the CSS loads with an expected cascade order. As you'd expect, any `media` attribute present on the original link element will be retained when the polyfill is in play. When the polyfill has a | ||
You can view a demo of this `rel=preload` pattern here: https://master-origin-loadcss.fgview.com/test/preload.html | ||
@@ -66,5 +73,5 @@ | ||
The [loadCSS.js](https://github.com/filamentgroup/loadCSS/blob/master/src/loadCSS.js) file exposes a global `loadCSS` function that you can call to load CSS files programmatically, when needed. | ||
The [loadCSS.js](https://github.com/filamentgroup/loadCSS/blob/master/src/loadCSS.js) file exposes a global `loadCSS` function that you can call to load CSS files programmatically, if needed. This file is no longer part of the loadCSS primary recommended workflow (which is purely a rel=preload polyfill), but it's handy for cases where you need to dynamically load CSS from script. | ||
```css | ||
``` javascript | ||
loadCSS( "path/to/mystylesheet.css" ); | ||
@@ -77,6 +84,6 @@ ``` | ||
If you're calling loadCSS manually (without the `rel=preload` pattern, the function has 3 optional arguments. | ||
If you're including and calling the loadCSS function (without the `rel=preload` pattern, the function has 3 optional arguments. | ||
- `before`: By default, loadCSS attempts to inject the stylesheet link *after* all CSS and JS in the page. However, if you desire a more specific location in your document, such as before a particular stylesheet link, you can use the `before` argument to specify a particular element to use as an insertion point. Your stylesheet will be inserted *before* the element you specify. For example, here's how that can be done by simply applying an `id` attribute to your `script`. | ||
``` html | ||
```html | ||
<head> | ||
@@ -98,3 +105,3 @@ ... | ||
``` javascript | ||
```javascript | ||
var stylesheet = loadCSS( "path/to/mystylesheet.css" ); | ||
@@ -101,0 +108,0 @@ onloadCSS( stylesheet, function() { |
@@ -1,44 +0,79 @@ | ||
/*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */ | ||
/*! loadCSS. [c]2017 Filament Group, Inc. MIT License */ | ||
/* This file is meant as a standalone workflow for | ||
- testing support for link[rel=preload] | ||
- enabling async CSS loading in browsers that do not support rel=preload | ||
- applying rel preload css once loaded, whether supported or not. | ||
*/ | ||
(function( w ){ | ||
// rel=preload support test | ||
if( !w.loadCSS ){ | ||
return; | ||
} | ||
var rp = loadCSS.relpreload = {}; | ||
rp.support = function(){ | ||
try { | ||
return w.document.createElement( "link" ).relList.supports( "preload" ); | ||
} catch (e) { | ||
return false; | ||
} | ||
}; | ||
"use strict"; | ||
// rel=preload support test | ||
if( !w.loadCSS ){ | ||
w.loadCSS = function(){}; | ||
} | ||
// define on the loadCSS obj | ||
var rp = loadCSS.relpreload = {}; | ||
// rel=preload feature support test | ||
rp.support = function(){ | ||
try { | ||
return w.document.createElement( "link" ).relList.supports( "preload" ); | ||
} catch (e) { | ||
return false; | ||
} | ||
}; | ||
// loop preload links and fetch using loadCSS | ||
rp.poly = function(){ | ||
var links = w.document.getElementsByTagName( "link" ); | ||
for( var i = 0; i < links.length; i++ ){ | ||
var link = links[ i ]; | ||
if( link.rel === "preload" && link.getAttribute( "as" ) === "style" ){ | ||
w.loadCSS( link.href, link, link.getAttribute( "media" ) ); | ||
link.rel = null; | ||
} | ||
} | ||
}; | ||
// if link[rel=preload] is not supported, we must fetch the CSS manually using loadCSS | ||
if( !rp.support() ){ | ||
rp.poly(); | ||
var run = w.setInterval( rp.poly, 300 ); | ||
if( w.addEventListener ){ | ||
w.addEventListener( "load", function(){ | ||
rp.poly(); | ||
w.clearInterval( run ); | ||
} ); | ||
} | ||
if( w.attachEvent ){ | ||
w.attachEvent( "onload", function(){ | ||
w.clearInterval( run ); | ||
} ) | ||
} | ||
} | ||
}( this )); | ||
// loop through link elements in DOM | ||
rp.poly = function(){ | ||
if( rp.support() ){ | ||
return; | ||
} | ||
var links = w.document.getElementsByTagName( "link" ); | ||
for( var i = 0; i < links.length; i++ ){ | ||
var link = links[ i ]; | ||
// qualify links to those with rel=preload and as=style attrs | ||
if( link.rel === "preload" && link.getAttribute( "as" ) === "style" && !link.getAttribute( "data-loadcss" ) ){ | ||
// remember existing media attr for ultimate state, or default to 'all' | ||
var finalMedia = link.media || "all"; | ||
// if preload isn't supported, get an asynchronous load by using a non-matching media attribute | ||
// then change that media back to its intended value on load | ||
var enableStylesheet = function(){ | ||
link.media = finalMedia; | ||
} | ||
if( link.addEventListener ){ | ||
link.addEventListener( "load", enableStylesheet ); | ||
} else if( link.attachEvent ){ | ||
link.attachEvent( "onload", enableStylesheet ); | ||
} | ||
// if preload is not supported, kick off an asynchronous request by using a non-matching media query and rel=stylesheet | ||
link.media = "x"; | ||
link.rel = "stylesheet"; | ||
// set rel=preload to stylesheet after 3 seconds, | ||
// which will catch very old browsers (android 2.x, old firefox) that don't support onload on link | ||
setTimeout( enableStylesheet, 3000 ); | ||
// prevent rerunning on link | ||
link.setAttribute( "data-loadcss", true ); | ||
} | ||
} | ||
// rerun poly on an interval until onload | ||
var run = w.setInterval( rp.poly, 300 ); | ||
if( w.addEventListener ){ | ||
w.addEventListener( "load", function(){ | ||
rp.poly(); | ||
w.clearInterval( run ); | ||
} ); | ||
} else if( w.attachEvent ){ | ||
w.attachEvent( "onload", function(){ | ||
rp.poly(); | ||
w.clearInterval( run ); | ||
} ); | ||
} | ||
}; | ||
// run once at least | ||
rp.poly(); | ||
// commonjs | ||
if( typeof exports !== "undefined" ){ | ||
exports.loadCSS = loadCSS; | ||
} | ||
else { | ||
w.loadCSS = loadCSS; | ||
} | ||
}( typeof global !== "undefined" ? global : this ) ); |
@@ -9,3 +9,3 @@ /*! loadCSS. [c]2017 Filament Group, Inc. MIT License */ | ||
// `before` [OPTIONAL] is the element the script should use as a reference for injecting our stylesheet <link> before | ||
// By default, loadCSS attempts to inject the link after the last stylesheet or script in the DOM. However, you might desire a more specific location in your document. | ||
// By default, loadCSS attempts to inject the link after the last stylesheet or script in the DOM. However, you might desire a more specific location in your document. | ||
// `media` [OPTIONAL] is the media type or query of the stylesheet. By default it will be 'all' | ||
@@ -12,0 +12,0 @@ var doc = w.document; |
@@ -102,24 +102,6 @@ /*global window:true*/ | ||
asyncTest( 'rel=preload stylesheet loads via polyfill', function(){ | ||
expect(1); | ||
var preloadElem = document.getElementById("preloadtest"); | ||
var preloadHref = preloadElem.getAttribute("href"); | ||
function loaded(){ | ||
return document.querySelector( 'link[href="'+ preloadHref +'"][rel="stylesheet"]' ) || document.querySelector( 'link[href="'+ preloadElem.href +'"][rel="stylesheet"]' ); | ||
} | ||
window.setTimeout(function(){ | ||
if( window.loadCSS.relpreload.support() ){ | ||
ok( loaded(), "stylesheet is in dom and applied without a polyfill" ); | ||
} | ||
else { | ||
ok( loaded(), "stylesheet is in dom and applied with a polyfill" ); | ||
} | ||
start(); | ||
},3000); | ||
}); | ||
}(window)); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
34
2391
113
95852
1
1