Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <header class=lateload-container>

  <div class="lateload-img lateload-img-1" data-lateload-src="https://websemantics.uk/articles/late-loaded-blurred-image-replacement/demo/digital-tunnel.jpg">
    <div></div>
  </div>

  <div class=lateload-copy>

    <h1><a target=_blank href="http://websemantics.uk/articles/late-loaded-blurred-image-replacement/">Blurred image late-load replacement</a></h1>
    <p><span>See full <a target=_blank href="http://websemantics.uk/articles/late-loaded-blurred-image-replacement/">article</a> for more details.</span></p>
    <p><span>Vanilla JavaScript, with CSS fallback.</span></p>
    <p style="font-size:larger"><span>A 3 second delay is applied to simulate poor network connectivity</span></p>

  </div>

</header>

<main>
  
  <h2><span>Improve perceived page-load times</span></h2>
  
  <p>Display  blurry, low resolution, image(s) immediately, without any extra HTTP requests.</p> 
<p>Once page has fully loaded, fetch the high resolution image(s), then cross-fade onto display.</p>
  
  <p style="color:#ff0">As used on the <a style="color:#ff0" href="https://websemantics.uk/portfolio/2016/finest-wine-bar/" target=_blank title="[new window]">Tesco finest wine bar</a> page.</p>

<p><a target=_blank href="http://websemantics.uk/articles/late-loaded-blurred-image-replacement/">Late-loaded blurred image replacement &ndash; article</a></p>
  
  <p>Digital Tunnel image from <a target=_blank href="http://www.linkedinbackground.com/abstract/digital-tunnel/">Linked In Backgrounds</a></p>

</main>

[[[https://codepen.io/2kool2/pen/mKeeGM]]]
              
            
!

CSS

              
                /* General styles */

body {
  margin: 0;
  color: #fff;
  background: #000;
  font-family: sans-serif;
  line-height: 1.5;
  text-align: center;
  text-shadow: 0 2px 4px #000;
  background-image: url("data:image/svg+xml;utf8,<svg style='opacity:.75' width='1200' height='256' viewBox='0 0 1200 256' xmlns='http://www.w3.org/2000/svg'><defs><filter id='noise'><feTurbulence type='fractalNoise' baseFrequency='.4'></feTurbulence></filter></defs><rect height='256' width='1200' filter='url(%23noise)' opacity='0.3'/></svg>");
}

h1 a,
h2 span,
p span {
  font-weight: 100;
  padding: .5rem 1rem;
  background-color: rgba(0, 0, 0, 0.25);
  text-decoration: none;
}

a {color: #fff;}



/* Blurred background-image lazy-load */


/* Container defines the size */

.lateload-container {
  position: relative;
  overflow: hidden;
  min-height: 400px;

  display: flex;
  align-items: center;
  justify-content: center;
}


/* The three image layers: */

.lateload-img,  /* bottom layer */
.lateload-img div,  /* middle layer */
.lateload-img div::before {  /* top layer */
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-position: center;
  background-size: cover;
  z-index: -1;
}


/* 2 KB images are applied to both top & middle layers */

.lateload-img-1 div::before,
.lateload-img-1 div {
  /* digital-tunnel.small.jpg - Less than 2kb strongly suggested */
  background-image: url(data:image/jpeg;base64,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);
}


/* Top-most layer has the blur applied */

.lateload-img div::before {
  content: "";
  filter: blur(10px);
}


/*
  Middle layer: No blur, required to keep the container edges sharp.

  Bottom layer: .hero-bg has background-image added via script (when available).
                Upon image load, script fades out the top two layers.
*/


/* When no scripting is available use CSS instead. */


/* No JS: Add image to bottom layer */

.noJS .lateload-img {
  background-image: url(http://websemantics.uk/articles/late-loaded-blurred-image-replacement/demo/digital-tunnel.jpg);
}


/* No JS: Fade out blur layers */

.noJS .lateload-img div {
  animation: fadeOut 1s ease-out 3s forwards;
}

@keyframes fadeOut {
  to {
    opacity: 0
  }
}
              
            
!

JS

              
                // Uncomment the next line to test the no-script variant
// document.documentElement.classList.add("noJS");

var LateLoadDataSrcImages = (function() {

  // Browser support required for:
  //    addEventListener,
  //    requestAnimationFrame,
  //    getElementsByClassName

  "use strict";

  var lateloadClass = "lateload-img",
      lateloadDataAttr = "data-lateload-src";

  var _fadeOut = function(el) {

    el.style.opacity = 1;

    (function _fade() {

      if ((el.style.opacity -= 0.05) < 0) {

        // tidy up and remove from DOM
        el.parentNode.removeChild(el);
      } else {
        window.requestAnimationFrame(_fade);
      }

    })();

  };

  var _displayImage = function(img) {

    var obj = img.divObj;

    window.requestAnimationFrame(function() {

      var childDivs = obj.getElementsByTagName("div");

      // Add image to the bottom layer
      // It's unseen, behind the top & middle layer, hopefully no paint or reflow occurs (check it!).
      obj.style.backgroundImage = "url(" + img.src + ")";

      // fade out the middle layer, it'll take the top layer with it.
      if (childDivs) {

        // small delay to emulate a poor connection - Remove in production
        setTimeout(function(){
          _fadeOut(childDivs[0]);
        }, 1500);

      }

    });
  };

  var _requestImage = function (obj, src) {

    var img = new Image();

    img.divObj = obj;
    img.addEventListener("load", function() {
      _displayImage(img);
    }, false);
    img.src = src;

  };

  var _initialise = function () {

    // tidy up
    window.removeEventListener("load", _initialise);
    
    var lateLoads = document.getElementsByClassName(lateloadClass);
    var len = lateLoads.length;
    var dataAttr
    if (len) {
      for (var i = 0; i < len; i++) {
        dataAttr = lateLoads[i].getAttribute(lateloadDataAttr);
        if (dataAttr) {
          _requestImage(lateLoads[i], dataAttr);
        }
      }
    }
    
/* Replaced with the rubbish for-loop (above) for Chrome, cotton socks, bless:
    let lateLoads = document.getElementsByClassName(lateloadClass);
    for (let lateLoadObj of lateLoads) {
      let dataAttr = lateLoadObj.getAttribute(lateloadDataAttr);
      if (dataAttr) {
        _requestImage(lateLoadObj, dataAttr);
      }
    }
*/
    
  };

  // test required features are supported here before initialising
  var featuresSupported = true;
  if (featuresSupported) {
    window.addEventListener("load", _initialise, false);
  }
  

}());
              
            
!
999px

Console