Blurred background late loader
A work in progress.
Blah CSS, blah vanilla JavaScript, blah small script.
Mark up
<div class="lateload-container">
<div class="lateload-img lateload-img-1" data-lateload-src="high-resolution.jpg">
<div></div>
</div>
<div class="lateload-copy">
Overlaid copy
</div>
</div>
Styles
Either the container or the content copy can define the height.
.lateload-container {
position: relative;
overflow: hidden;
min-height: 400px;
display: flex;
align-items: center;
justify-content: center;
}
.lateload-copy {
padding:4rem 1rem
}
Three superimposed image layers are used.
.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;
}
Both the top and middle image layers have a small, extremely low quality, dataURI encoded background-image defined in the style sheet.
The smaller the image, the better. Keeping below 2 KB is strongly suggested.
.lateload-img-1 div,
.lateload-img-1 div::before {
background-image: url(data:image/jpeg;base64,…);
}
To offset the low quality the top image layer has a blur filter applied.
.lateload-img div::before {
content: "";
filter: blur(10px);
}
The middle layer remains as is. It's purpose is to keep the container edges sharp.
The bottom layer, .hero-bg
is where the JavaScript adds the high resolution background-image.
Scripting
Requires the browser to support: addEventListener
, requestAnimationFrame
, getElementsByClassName
and let-for loop
which are not tested before use in the module.
var LateLoadDataSrcImages = (function() {
"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 but check.
obj.style.backgroundImage = "url(" + img.src + ")";
// Fade out the middle layer.
// It'll take the top (pseudo) 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 - don't needlessly clutter DOM or Events.
window.removeEventListener("load", _initialise);
let lateLoads = document.getElementsByClassName(lateloadClass);
for (let lateLoadObj of lateLoads) {
let dataAttr = lateLoadObj.getAttribute(lateloadDataAttr);
if (dataAttr) {
_requestImage(lateLoadObj, dataAttr);
}
}
};
// Test the required features are supported
// before initialising here:
window.addEventListener("load", _initialise, false);
}());
No scripting available?
Use CSS instead, not ideal but adequate under most circumstances.
Add the image to bottom layer after a small delay, to allow the image to fully download first.
.noJS .hero_bg {
background-image: url(high-resolution.jpg);
}
The use an animation to fade out the blur layers.
.noJS .hero_bg div {
animation: fadeOut 1s ease-out 3s forwards;
}
@keyframes fadeOut {
to {
opacity: 0
}
}
Google compiled
333 bytes gzipped (523 bytes uncompressed).
// The compiler transcoded the let-for loop
// Replace with standard for loop.
Social links and email client: