Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Adds support for -based resolution switching on source elements. #18

Closed
wants to merge 6 commits into from

3 participants

@Wilto
Collaborator

Adds srcset-based resolution switching on source elements, per the markup pattern proposed here: http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2012-May/036160.html

@scottjehl
Owner
@Wilto
Collaborator

Thanks, dude! A branch probably makes the most sense, but we can sort it out later.

@digerata

Does anyone know the status on this pull request? It seems supremely useful...

@scottjehl
Owner

This branch should either be updated to the new source or dropped for a while, since it's mostly syntactic sugar on top of something already possible (I think?). Thoughts, @Wilto ? Closing the PR at least for now.

@scottjehl scottjehl closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
BIN  external/imgs/extralarge.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  external/imgs/extralarge2x.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  external/imgs/large.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  external/imgs/large2x.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  external/imgs/medium.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  external/imgs/medium2x.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  external/imgs/small.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  external/imgs/small2x.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
55 index.html
@@ -16,19 +16,48 @@
<h1>Picturefill: A &lt;picture&gt; element polyfill</h1>
<p>For more info: <a href="http://github.com/scottjehl/picturefill">see project home.</a></p>
-
- <picture alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia">
- <!-- <source src="external/imgs/small.jpg"> -->
- <source src="external/imgs/small.jpg">
- <!-- <source src="external/imgs/medium.jpg" media="(min-width: 400px)"> -->
- <source src="external/imgs/medium.jpg" media="(min-width: 400px)">
- <!-- <source src="external/imgs/large.jpg" media="(min-width: 800px)"> -->
- <source src="external/imgs/large.jpg" media="(min-width: 800px)">
- <!-- <source src="external/imgs/extralarge.jpg" media="(min-width: 1000px)"> -->
- <source src="external/imgs/extralarge.jpg" media="(min-width: 1000px)">
- <!-- Fallback content for non-JS browsers. Same img src as the initial, unqualified source element. -->
- <noscript><img src="external/imgs/small.jpg" alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia"></noscript>
- </picture>
+ <section>
+ <h1><code>source</code> elements using both <code>media</code> and <code>srcset</code> attributes</h1>
+ <p>This markup pattern is further detailed in the <a href="http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2012-May/036160.html">original proposal</a> by Florian Rivoal.</p>
+ <p>This syntax combines the resolution switching of <code>srcset</code> with <code>picture</code>’s ability to tailor sources to the viewport. This has a couple of major benefits over the originally-propsed <code>picture</code> element:</p>
+ <ul>
+ <li>Less verbose and more readable syntax, especially considering the vendor prefixing that comes along with <code>min-device-pixel-ratio</code>. Determining viewport-appropriate sources is handled through <code>media</code> attributes as expected, while serving that viewport-appropriate source at the correct <em>resolution</em> is done with <code>srcset</code>.</li>
+ <li>A native implementation would allow us to apply the original intrinsic dimensions of the <code>1x</code> source to the higher-resolution sources rather than simply delivering an image twice the size. This polyfill simply divides the image’s intrinsic width against the screen resolution (1x, 2x, etc.), though I’m sure this can be handled more intelligently in a native implementation.</li>
+ <li>By sandboxing the resolution in this new attribute, we allow the browser to intervene without compromising the effectiveness of media queries. The decision to serve higher-resolution images based on available bandwidth is a decision best left in the hands of the browser. <code>srcset</code> allows us to define a set of <em>suggested</em> sources based on resolution, while a user setting or automated bandwidth detection in the browser could still intervene. This approach prevents us from breaking the intended “absolute” terms of media queries.</li>
+ </ul>
+ <picture alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia">
+ <!-- <source srcset="external/imgs/small.jpg 1x, external/imgs/small2x.jpg 2x"> -->
+ <source srcset="external/imgs/small.jpg 1x, external/imgs/small2x.jpg 2x">
+ <!-- <source media="(min-width: 400px)" srcset="external/imgs/medium.jpg 1x, external/imgs/medium2x.jpg 2x"> -->
+ <source media="(min-width: 400px)" srcset="external/imgs/medium.jpg 1x, external/imgs/medium2x.jpg 2x">
+ <!-- <source media="(min-width: 800px)" srcset="external/imgs/large.jpg 1x, external/imgs/large2x.jpg 2x"> -->
+ <source media="(min-width: 800px)" srcset="external/imgs/large.jpg 1x, external/imgs/large2x.jpg 2x">
+ <!-- <source media="(min-width: 1000px)" srcset="external/imgs/extralarge.jpg 1x, external/imgs/extralarge2x.jpg 2x"> -->
+ <source media="(min-width: 1000px)" srcset="external/imgs/extralarge.jpg 1x, external/imgs/extralarge2x.jpg 2x">
+
+ <!-- Fallback content for non-JS browsers. Same img src as the initial, unqualified source element. -->
+ <noscript><img src="external/imgs/small.jpg" alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia"></noscript>
+ </picture>
+ </section>
+
+ <section>
+ <h1><code>source</code> elements using <code>media</code> attributes only</h1>
+ <p>Does not perform any resolution switching.</p>
+ <picture alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia">
+ <!-- <source src="external/imgs/small.jpg"> -->
+ <source src="external/imgs/small.jpg">
+ <!-- <source src="external/imgs/medium.jpg" media="(min-width: 400px)"> -->
+ <source src="external/imgs/medium.jpg" media="(min-width: 400px)">
+ <!-- <source src="external/imgs/large.jpg" media="(min-width: 800px)"> -->
+ <source src="external/imgs/large.jpg" media="(min-width: 800px)">
+ <!-- <source src="external/imgs/extralarge.jpg" media="(min-width: 1000px)"> -->
+ <source src="external/imgs/extralarge.jpg" media="(min-width: 1000px)">
+
+ <!-- Fallback content for non-JS browsers. Same img src as the initial, unqualified source element. -->
+ <noscript><img src="external/imgs/small.jpg" alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia"></noscript>
+ </picture>
+ </section>
+
</body>
</html>
View
83 picturefill.js
@@ -12,6 +12,10 @@
// Enable strict mode
"use strict";
+ // User preference for HD content when available
+ var prefHD = false || w.localStorage && w.localStorage[ "picturefill-prefHD" ] === "true",
+ hasHD;
+
// Test if `<picture>` is supported natively, if so, exit - no polyfill needed.
if ( !!( w.document.createElement( "picture" ) && w.document.createElement( "source" ) && w.HTMLPictureElement ) ){
return;
@@ -23,6 +27,7 @@
// Loop the pictures
for( var i = 0, il = ps.length; i < il; i++ ){
var sources = ps[ i ].getElementsByTagName( "source" ),
+ picImg = null,
matches = [];
// If no sources are found, they're likely erased from the DOM. Try finding them inside comments.
@@ -36,7 +41,7 @@
sources = frag.getElementsByTagName( "div" );
}
- // See if which sources match
+ // See which sources match
for( var j = 0, jl = sources.length; j < jl; j++ ){
var media = sources[ j ].getAttribute( "media" );
// if there's no media specified, OR w.matchMedia is supported
@@ -44,26 +49,81 @@
matches.push( sources[ j ] );
}
}
-
+
// Find any existing img element in the picture element
- var picImg = ps[ i ].getElementsByTagName( "img" )[ 0 ];
-
+ picImg = ps[ i ].getElementsByTagName( "img" )[ 0 ];
+
if( matches.length ){
-
+ // Grab the most appropriate (last) match.
+ var match = matches.pop(),
+ srcset = match.getAttribute( "srcset" );
+
if( !picImg ){
picImg = w.document.createElement( "img" );
picImg.alt = ps[ i ].getAttribute( "alt" );
ps[ i ].appendChild( picImg );
}
-
- picImg.src = matches.pop().getAttribute( "src" );
- }
- else if( picImg ) {
- ps[ i ].removeChild( picImg );
+
+ if( srcset ) {
+ var screenRes = ( prefHD && w.devicePixelRatio ) || 1, // Is it worth looping through reasonable matchMedia values here?
+ sources = srcset.split(","); // Split comma-separated `srcset` sources into an array.
+
+ hasHD = w.devicePixelRatio > 1;
+
+ for( var res = sources.length, r = res - 1; r >= 0; r-- ) { // Loop through each source/resolution in `srcset`.
+ var source = sources[ r ].replace(/^\s*/, '').replace(/\s*$/, '').split(" "), // Remove any leading whitespace, then split on spaces.
+ resMatch = parseFloat( source[1], 10 ); // Parse out the resolution for each source in `srcset`.
+
+ if( screenRes >= resMatch ) {
+ if( picImg.getAttribute( "src" ) !== source[0] ) {
+ var newImg = document.createElement("img");
+
+ newImg.src = source[0];
+ // When the image is loaded, set a width equal to that of the original’s intrinsic width divided by the screen resolution:
+ newImg.onload = function() {
+ // Clone the original image into memory so the width is unaffected by page styles:
+ this.width = ( this.cloneNode( true ).width / resMatch );
+ }
+ picImg.parentNode.replaceChild( newImg, picImg );
+ }
+ break; // We’ve matched, so bail out of the loop here.
+ }
+ }
+ } else {
+ // No `srcset` in play, so just use the `src` value:
+ picImg.src = match.getAttribute( "src" );
+ }
}
}
+ /*
+// Manual resolution switching, to simulate UA interference.
+ if( hasHD ){
+ var body = w.document.getElementsByTagName("body")[0],
+ prevSwitch = w.document.getElementById( "#toggle-res" ),
+ picSwitch = w.document.createElement( "a" );
+
+ if( prevSwitch ){
+ body.removeChild( prevSwitch );
+ }
+
+ picSwitch.id = "toggle-res";
+ picSwitch.href = "#";
+ picSwitch.innerHTML = ( prefHD ? "S" : "H" ) + "D only";
+ picSwitch.title = "Switch images to " + ( prefHD ? "Standard" : "High" ) + "Definition";
+ picSwitch.className = "pf-pref pf-pref-" + ( prefHD ? "standard" : "high" );
+
+ body.insertBefore( picSwitch, body.children[0] );
+
+ picSwitch.onclick = function(){
+ prefHD = !prefHD;
+ if( w.localStorage ){
+ w.localStorage[ "picturefill-prefHD" ] = prefHD;
+ }
+ return false;
+ };
+ }*/
};
-
+
// Run on resize and domready (w.load as a fallback)
if( w.addEventListener ){
w.addEventListener( "resize", w.picturefill, false );
@@ -77,5 +137,4 @@
else if( w.attachEvent ){
w.attachEvent( "onload", w.picturefill );
}
-
})( this );
Something went wrong with that request. Please try again.