<h1 id="id-layzrjs">Layzr.js</h1>
<p><a href="https://www.npmjs.com/package/layzr.js"><img src="https://img.shields.io/npm/v/layzr.js.svg?style=flat-square" alt="Layzr.js on NPM"></a></p>
<p>A modern lazy loading library for images.</p>
<ul>
<li><a href="http://callmecavs.github.io/layzr.js/">Demo Page</a></li>
</ul>
<h2 id="id-getting-started">Getting Started</h2>
<p>Follow these steps:</p>
<ol>
<li><a href="#install">Install</a></li>
<li><a href="#setup-images">Setup Images</a></li>
<li><a href="#instantiate">Instantiate</a></li>
<li><a href="#options">Review Options</a></li>
<li><a href="#events">Review Events</a></li>
<li><a href="#api">Review API</a></li>
<li><strong><a href="https://github.com/callmecavs/layzr.js/tree/master/examples">Review Example Code</a></strong></li>
</ol>
<ul>
<li>Examples progress like a coffee addiction: small -&gt; medium -&gt; large</li>
</ul>
<h2 id="id-install">Install</h2>
<p>Layzr was developed with a modern JavaScript workflow in mind. Though not required, it&#39;s convenient to have a build system in place that can transpile ES6, and bundle modules. For a minimal boilerplate that does so, try <a href="https://github.com/callmecavs/outset">outset</a>.</p>
<p>Choose an installation option based on your workflow:</p>
<ul>
<li><a href="#npm">npm</a></li>
<li><a href="#cdn">CDN</a></li>
<li><a href="#download">Download</a></li>
<li><a href="#framework-bridge">Framework Bridge</a></li>
</ul>
<p>Refer to the <a href="https://github.com/callmecavs/layzr.js/releases">releases</a> page for version specific information.</p>
<h3 id="id-npm">npm</h3>
<p>Install Layzr, and add it to your <code>package.json</code> dependencies.</p>
<pre><code>$ npm install layzr.js --save
</code></pre>
<p>Then <code>import</code> it into the file where you&#39;ll use it.</p>
<pre><code class="hljs language-es6">import Layzr from &#39;layzr.js&#39;
</code></pre>
<h3 id="id-cdn">CDN</h3>
<p>Copy and paste one of the following <code>&lt;script&gt;</code> tags. Note the version number in the <code>src</code> attributes.</p>
<h4 id="id-jsdelivr"><a href="http://www.jsdelivr.com/projects/layzr.js">jsDelivr</a></h4>
<pre><code class="hljs language-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;https://cdn.jsdelivr.net/layzr.js/2.0.2/layzr.min.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h4 id="id-cdnjs"><a href="https://cdnjs.com/libraries/layzr.js">cdnjs</a></h4>
<pre><code class="hljs language-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;https://cdnjs.cloudflare.com/ajax/libs/layzr.js/2.0.2/layzr.min.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h3 id="id-download">Download</h3>
<p><a href="https://github.com/callmecavs/layzr.js/archive/master.zip">Download</a> the latest version, and load the script in the <code>dist</code> folder.</p>
<pre><code class="hljs language-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;layzr.min.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h3 id="id-framework-bridge">Framework Bridge</h3>
<p>Thank you to the community members who created these framework bridges!</p>
<ul>
<li>Ruby on Rails: <a href="https://github.com/mohitjain/layzr-rails">layzr-rails</a> by <a href="https://github.com/mohitjain">Mohit Jain</a></li>
</ul>
<h2 id="id-setup-images">Setup Images</h2>
<p>Layzr intelligently chooses the best image source available <strong>based on an image&#39;s data attributes and browser feature detection</strong>.</p>
<ul>
<li>In browsers that <a href="http://caniuse.com/#search=srcset">support <code>srcset</code></a>, if available, it will be used to determine the source.</li>
<li>In browsers that don&#39;t, the normal or retina source will be chosen based on the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio">devicePixelRatio</a> and availability.</li>
</ul>
<p>Note that all attribute names are configurable via the <a href="#options">options</a> passed to Layzr. To indicate potential sources, add the following attributes to your images:</p>
<div class="table-responsive"><table class="table table-striped"><tr>
<th align="left">Name</th>
<th align="center">Required</th>
<th align="center">Optional</th>
</tr>
<tr>
<td align="left"><a href="#data-normal"><code>data-normal</code></a></td>
<td align="center">✓</td>
<td align="center"></td>
</tr>
<tr>
<td align="left"><a href="#data-retina"><code>data-retina</code></a></td>
<td align="center"></td>
<td align="center">✓</td>
</tr>
<tr>
<td align="left"><a href="#data-srcset"><code>data-srcset</code></a></td>
<td align="center"></td>
<td align="center">✓</td>
</tr>
</table></div><h3 id="id-data-normal">data-normal</h3>
<p>Put the <em>normal resolution</em> source in the <code>data-normal</code> attribute.</p>
<pre><code class="hljs language-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">data-normal</span>=<span class="hljs-string">&quot;normal.jpg&quot;</span>&gt;</span>
</code></pre>
<p>Note that Layzr <strong>selects elements using this attribute</strong>. Elements without it won&#39;t be tracked, and will never load.</p>
<h3 id="id-data-retina">data-retina</h3>
<p>Add the <em>retina/high resolution</em> source in the <code>data-retina</code> attribute.</p>
<pre><code class="hljs language-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">data-normal</span>=<span class="hljs-string">&quot;normal.jpg&quot;</span> <span class="hljs-attr">data-retina</span>=<span class="hljs-string">&quot;retina.jpg&quot;</span>&gt;</span>
</code></pre>
<h3 id="id-data-srcset">data-srcset</h3>
<p>Add the <em>source set</em> in the <code>data-srcset</code> attribute. For information on the proper syntax, read the official <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img">specification</a>.</p>
<pre><code class="hljs language-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">data-normal</span>=<span class="hljs-string">&quot;normal.jpg&quot;</span> <span class="hljs-attr">data-retina</span>=<span class="hljs-string">&quot;retina.jpg&quot;</span> <span class="hljs-attr">data-srcset</span>=<span class="hljs-string">&quot;small.jpg 320w, medium.jpg 768w, large.jpg 1024w&quot;</span>&gt;</span>
</code></pre>
<h2 id="id-instantiate">Instantiate</h2>
<p>Create an instance, optionally passing in your <a href="#options">options</a>.</p>
<p>Be sure to <strong>assign your Layzr instance to a variable</strong>. Using your instance, you can:</p>
<ul>
<li>start and stop the event listeners</li>
<li>add and remove event handlers</li>
<li>accommodate dynamically added elements</li>
</ul>
<pre><code class="hljs language-es6">// using the default options

const instance = Layzr()

// using custom options

const instance = Layzr({
  // ...
})
</code></pre>
<p>Options are explained in the following section.</p>
<h2 id="id-options">Options</h2>
<p>Default options are shown below, and an explanation of each follows:</p>
<pre><code class="hljs language-es6">const instance = Layzr({
  normal: &#39;data-normal&#39;,
  retina: &#39;data-retina&#39;,
  srcset: &#39;data-srcset&#39;,
  threshold: 0
})
</code></pre>
<h3 id="id-normal">normal</h3>
<p>Customize the attribute the normal resolution source is taken from.</p>
<pre><code class="hljs language-es6">const instance = Layzr({
  normal: &#39;data-normal&#39;
})
</code></pre>
<h3 id="id-retina">retina</h3>
<p>Customize the attribute the retina/high resolution source is taken from.</p>
<pre><code class="hljs language-es6">const instance = Layzr({
  retina: &#39;data-retina&#39;
})
</code></pre>
<h3 id="id-srcset">srcset</h3>
<p>Customize the attribute the source set is taken from.</p>
<pre><code class="hljs language-es6">const instance = Layzr({
  srcset: &#39;data-srcset&#39;
})
</code></pre>
<h3 id="id-threshold">threshold</h3>
<p>Adjust when images load, relative to the viewport. <em>Positive values make images load sooner, negative values make images load later</em>.</p>
<p>Threshold is a percentage of the viewport height, identical to the CSS <code>vh</code> unit.</p>
<pre><code class="hljs language-es6">const instance = Layzr({
  threshold: 0
})
</code></pre>
<h2 id="id-events">Events</h2>
<p>Layzr instances are extended with <a href="https://github.com/callmecavs/knot.js">Knot.js</a>, a browser-based event emitter. Use the event emitter syntax to add and remove handlers. Review the emitter syntax <a href="https://github.com/callmecavs/knot.js#api">here</a>.</p>
<p>Layzr emits the following events:</p>
<ul>
<li><a href="#srcbefore">src:before</a></li>
<li><a href="#srcafter">src:after</a></li>
</ul>
<h3 id="id-srcbefore">src:before</h3>
<p>This event is emitted immediately <em>before an image source is set</em>. The image node is passed to the event handler.</p>
<pre><code class="hljs language-es6">instance.on(&#39;src:before&#39;, (element) =&gt; {
  // &#39;this&#39; is your Layzr instance
  // &#39;element&#39; is the image node
  // ...
})
</code></pre>
<p>Load event handlers should be attached using this event. See the <a href="https://github.com/callmecavs/layzr.js/blob/master/examples/large.js">example</a>, and note the <a href="https://api.jquery.com/load-event/">caveats</a> associated with image load events before proceeding.</p>
<h3 id="id-srcafter">src:after</h3>
<p>This event is emitted immediately <em>after an image source is set</em>. The image node is passed to the event handler.</p>
<pre><code class="hljs language-es6">instance.on(&#39;src:after&#39;, (element) =&gt; {
  // &#39;this&#39; is your Layzr instance
  // &#39;element&#39; is the image node
  // ...
})
</code></pre>
<p>Note that the image is not necessarily done loading when this event fires.</p>
<h2 id="id-api">API</h2>
<p>All API methods are <strong>chainable</strong>, including those from the emitter.</p>
<h3 id="id-handlersflag">.handlers(flag)</h3>
<p>Add or remove the <code>scroll</code> and <code>resize</code> event handlers.</p>
<pre><code class="hljs language-es6">instance
  .handlers(true)       // &#39;true&#39; adds them
  .handlers(false)      // &#39;false&#39; removes them
</code></pre>
<h3 id="id-check">.check()</h3>
<p>Manually check if elements are in the viewport.</p>
<p>This method is called while the <code>window</code> is scrolled or resized.</p>
<pre><code class="hljs language-es6">instance.check()
</code></pre>
<h3 id="id-update">.update()</h3>
<p>Update the elements Layzr is checking.</p>
<pre><code class="hljs language-es6">instance.update()
</code></pre>
<p><strong>Dynamically added elements</strong> should be handled using this method. See the <a href="https://github.com/callmecavs/layzr.js/blob/master/examples/large.js">example</a>.</p>
<h2 id="id-browser-support">Browser Support</h2>
<p>Layzr depends on the following browser APIs:</p>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/classList">classList</a></li>
<li>ES5 array methods: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach">forEach</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice">slice</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame</a></li>
</ul>
<p>It supports the following natively:</p>
<ul>
<li>Chrome 24+</li>
<li>Firefox 23+</li>
<li>Safari 6.1+</li>
<li>Opera 15+</li>
<li>Edge 12+</li>
<li>IE 10+</li>
<li>iOS Safari 7.1+</li>
<li>Android Browser 4.4+</li>
</ul>
<p>To support older browsers, consider including <a href="https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills">polyfills/shims</a> for the APIs listed above. There are <strong>no plans to include any in the library</strong>, in the interest of file size.</p>
<h2 id="id-colophon">Colophon</h2>
<ul>
<li>Site Design: <a href="https://dribbble.com/cp_allen">Chris Allen</a></li>
<li>Stock Photos: <a href="https://unsplash.com/">Unsplash</a></li>
</ul>
<h2 id="id-license">License</h2>
<p><a href="https://opensource.org/licenses/MIT">MIT</a>. © 2016 Michael Cavalea</p>
<p><a href="http://forthebadge.com"><img src="http://forthebadge.com/images/badges/built-with-love.svg" alt="Built With Love"></a></p>