Skip to content
This repository has been archived by the owner on Sep 6, 2022. It is now read-only.

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

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Binary file modified 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.
Binary file added 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.
Binary file modified 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.
Binary file added 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.
Binary file modified 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.
Binary file added 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.
Binary file modified 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.
Binary file added 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.
55 changes: 42 additions & 13 deletions index.html
Expand Up @@ -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>
83 changes: 71 additions & 12 deletions picturefill.js
Expand Up @@ -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;
Expand All @@ -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.
Expand All @@ -36,34 +41,89 @@
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
if( !media || ( w.matchMedia && w.matchMedia( media ).matches ) ){
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 );
Expand All @@ -77,5 +137,4 @@
else if( w.attachEvent ){
w.attachEvent( "onload", w.picturefill );
}

})( this );