An Extendible Deferred Asset Responsive Framework
A cross browser platform for implementing and creating gracefully degrading Responsive techniques
- Full uncustomized R.js minified and gzipped weighs at 2.8kb
- This can be reduced with custom builds - e.g. just including picture and not srcset brings us down to 2.4kb
- Picture updated to new syntax according to [proposed spec]http://dvcs.w3.org/hg/html-proposals/raw-file/tip/responsive-images/responsive-images.html)
- API changes
- New plugin API for creating plugins of implementations
- New hack method: instead of
<noscript></noscript></style>Respondu now uses
- The closing
</noscript-->must have the two dashes for cross browser compatibility
- Warning Do not use
<!-- -->(comment tags) inside the
- This will break the functionality some browsers (ie, safari)
- If you wish to make comments within the noscript tags use
- The closing
- Behavioural changes
- Instead of putting all content in
<noscript>tags, only relevant content (such as a picture element) goes inside a noscript tag
- The call to Respondu isolates the following
<noscript></noscript-->tag, processes the code and reinserts it in the place where Respondu is called
- This leads to a more familiar, progressive loading experience
- It also means R.base has been trimmed down, there's no need for loadScripts, doclate, window.open hackarounds etc
- Infrastructure examples have been removed, since this functionality is no longer needful
- Any scripts should go outside the noscript tag, the contents of the noscript tags should only be for assets you wish to responsively select the source for
- Instead of putting all content in
- Stronger compatibility for source elements
- It turns out some browsers cough iOS Safari cough sometimes strip source tags unless they're in a video element, this is secured against
- Picture/srcset now check for a browser implementation before processing (i.e. Respondu can now be used as a polyfill)
- Includes matchMedia polyfill for use in plugin implementations (and could be used anywhere in a project)
- Needs retesting in browsers
- Improve picture further
- Get picture media attributes working with em's
- Standardisation of picture element has made hybrid solution inaccurate/reduntant so hybrid has been removed, picture will be updated in 0.0.4
- Now includes grunt.js file to automatically build R.js
- Customized builds available in the builds folder
- Future version will have a builder gui for fine grain control
- Now supports IE8 + IE7
- Intelligently triggers window.onload and $(window).load in IE7/8/9
- Improved code base
- Modularized code for great customisation
- R.base provides basic use
- R.srcset, R.picture, and R.hybrid can be combined with R.base to become a polyfill for the respective implementation
- Combine with doclate for seamless jQuery compatability
- Relatively Unintrustive
- Entirely client side
- DEFERS SRC LOADING TILL PROCESSING IS FINISHED!
- Gracefully Degrades for non-JS clients (e.g. search bots)
- Very gentle to the global scope
- Create your own responsive techniques (implementations)!
- Forward looking - simple feature detection (once we know how to detect) will cause it to become easily compatible with future browsers
- Now works seamlessly with jQuery's $(document).ready!
Examples can be found at http://respondu.davidmarkclements.com
The end dashes in
</noscript--> are essential for Respondu to operate in certain browsers (Safari, IE8)
and to block the img src's from loading prior to responsive processing.
The positioning of the Respondu call in the body, just before the noscript tag is also essential. See How It Works.
Basic usage will apply the default breakpoints
breakpoints:typical: 500 //typical will leave src unchangedmedium : 1000 //configurable properties, will be reflected in requested image e.g. name.medium.pnglarge : Infinity //largest size set to infinity
Break points can be set thusly
Respondu also provides an implementations system, it currently includes the picture and srcset implementations plus the new hybrid implementation which combines the best of both.
For picture we would do something like
For srcset we could do
We create an implementation by adding it to the Respondu prototype, the format for creating an implementation is:
Responduplugin'MyNewImplementation'// all your code heredone;;
doc parameter is a DOM object (but not the actual DOM)
done paremeter is called as a function when processing is complete
done callback function allows for any async stuff)
We could then use it with
Here's how we could implement picture (already included):
Responduplugin'picture'if 'srcset' in documentcreateElement'picture' //if picture is implemented then just pass throughif done done;return;var pictures = docgetElementsByTagName'picture' pic attrs sources src i cmedia sourceImg img sW = windowscreenwidth pixelRatiopr = windowdevicePixelRatio || 1;//set devices pixel ratio;fori = 0; i < pictureslength; i++pic = picturesi;attrs = picattributes;sources = picgetElementsByTagName'source';sourceCandidates = ;forc = 0; c < sourceslength; c++srcel = sourcesc;media = srcelgetAttribute'media';//!media means no media attribute, so will be used if no other source elements qualifyif !media || matchMediamediamatches sourceCandidatespushsrcel;var x = sourceCandidateslength closest = 0;if x > 1whilex--media = sourceCandidatesxgetAttribute'media';if !media && sourceCandidateslength > 1delete sourceCandidatesx;break;media = mediamatch/\(-width:\)/;if Mathabsmedia2 - sW <= Mathabsclosest - sWclosest = media2;sourceImg = sourceCandidatesx;elsesourceImg = sourceCandidates0;var srcset srcsetCounter srcsetToken imageSrc;if sourceImgsrcset = sourceImggetAttribute'srcset'split',';srcsetCounter = srcsetlength;while srcsetCounter--srcsetToken = srcsetsrcsetCounterreplace/^\s\s*/ ''replace/\s\s*$/ ''split' ';if srcsetToken1 === pr + 'x'imageSrc = srcsetToken0;if !srcsetToken1//no density supplied, assume defaultimageSrc = srcsetToken0;img = doccreateElement'img'; //create a new image element on the ghost DOMimgsetAttribute'src' imageSrc;forc = 0; c < attrslength; c++imgsetAttributeattrscnodeName attrscnodeValue;picparentNodereplaceChildimg pic; //replace picture element with created img elementdone; //finished.;
Wrapping content in
<noscript> tags stops it from being added to the DOM, whilst also providing complete content to non-js clients (such as
search engine bots, screen readers, text browsers).
On some browsers its possible to extract and process the content of the
<noscript> tags using normal methods (e.g. getElementById etc.)
So Respondu uses a hack to to ensure the content can be extracted from all browsers.
We do this by dynamically wrapping the
<noscript> tags in another context - there are several ways: comments, textareas, script tags, style tags...
After experimentation and thought, Respondu's chosen way is to use the
<noscript>#content#</noscript--> technique, once Respondu has been called
<--<noscript>#content#<noscript-->. The dashes in the closing noscript tag enables us to close a dynamically inserted comment opener.
Dynamically wrapping the noscript tags in a comment prevents browsers such as IE and Safari from stripping the contents out of noscript. Respondu reliest on being called just before the noscript tags, so that it
- Knows where to insert the opening
- Knows where in the document to insert the final processed code
As a result, we can't put HTML comments inside our noscript tags (which means conditional comments are out). If we really want to have
comments within our noscript HTML we can use
Once the noscript content has been extracted, Respondu loads it into a "ghost DOM". (see createHTMLDocument)
The ghost DOM doesn't load any src's. We can manipulate this ghost DOM as the
doc parameter when creating implementations (see Creating an Implementation)
When all changes have been made to our ghost document (e.g. when we've replaced img src's according to screen width), we load it into the real document
If we want to have scripts execute once the DOM has loaded, the best place for them (if possible) is usually just before the closing
If you're using Respondu, you want them to be just before the closing
</noscript--> tags, Respondu will then ensure they are loaded and executed
after all the content has loaded.
<body><script>Respondu();</script><noscript>content etc.<script src=myScriptWhichWillManipulateTheDocument.js></script></noscript--></body>
If you're using jQuery, and absolutely need to include scripts in the head but you're using
to defer execution until the DOM has loaded then Respondu can accomodate you.
Just include doclate.js after jQuery, but before R.js
<script src=//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js></script><script src='js/doclate.js'></script><script src='js/R.js'></script>
In production you'll probably want to merge (and minify) doclate.js and R.js to reduce the amount of HTTP connections on page load.
Any calls to any variations of jQuery's DOM ready (
$(document).bind('ready', fn) or simply
will be buffered by doclate and then executed (in order) by R.js after all the responsive processing has completed.
Whilst this makes things easier, it's not as efficient as simply including your scripts at the bottom of the body.
- IE 7
- IE 8
- IE 9
- iOS Safari
- Safari (win)
- explain the callback functionality
I warmly welcome all contributions, you can help by
- pull requests
- suggesting a name