Afbeelding laadt met blur-up New
While a photo loads you see a blurred mini version (a 20 px LQIP, about 250 bytes as a data URI in the HTML); once the real image arrives it flows from blurry to sharp. loading="lazy" + decoding="async" + an onload class, works everywhere; if loading fails a clean error state with "Retry" appears. The demo slows loading on purpose so you can see the transition.

Foto niet geladen

Foto niet geladen

Foto niet geladen
How to use it
- Paste the HTML where the components should appear.
- Add the CSS to your stylesheet. All classes are prefixed, so nothing clashes with your own styles.
- Add the JavaScript and call init() with the element that contains the HTML.
<!-- Afbeelding laadt met blur-up · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="lbu">
<div class="lbu__grid">
<figure class="lbu__f" style="--lq:url(data:image/webp;base64,UklGRpwAAABXRUJQVlA4IJAAAAAQBACdASoUAAsAPpE4l0eloyIhMAgAsBIJZgCdACKykofffM4kLoKgTAD+6uX6y856gDSIOZ/NUYa0y+ZXklCHo1e/g4m/mRefSrbAgqOLg797I6J6pD6Ws2GpQ3s28+AW8loz5kj879cf3ISW7blIK4tZPMaA7pEebZiUMfzcbXuvR+K/DhtZNaLQWPwSAAA=)"><img alt="Duinpad naar het strand bij Zandvoort" width="900" height="491" decoding="async" loading="lazy" data-src="https://neddev.com/lab-media/lazy-blur-up-1.webp"><div class="lbu__err" role="alert" hidden><span>Foto niet geladen</span><button type="button" class="lbu__retry">Opnieuw</button></div><figcaption>Zandvoort</figcaption></figure>
<figure class="lbu__f" style="--lq:url(data:image/webp;base64,UklGRqwAAABXRUJQVlA4IKAAAABQBACdASoUAAsAPpE6l0eloyIhMAgAsBIJYwCdAYu47QcfjFaWX53Czac4AP7Ce50Au9PjO0hoSpALtQlT37DTfApovSyqNgx7y14vdXdj+rVQ59ER9U4kEJXWUm66v6TBDLGClx/neBH7Y99tKMKFmkFsXL/GCBbWizBPkSJCU4GbOsgFuey61YyuyXEhfIIMAlJ7tSBppB837hGsAAAA)"><img alt="Koffie en appeltaart op een terras" width="900" height="491" decoding="async" loading="lazy" data-src="https://neddev.com/lab-media/lazy-blur-up-2.webp"><div class="lbu__err" role="alert" hidden><span>Foto niet geladen</span><button type="button" class="lbu__retry">Opnieuw</button></div><figcaption>Delft</figcaption></figure>
<figure class="lbu__f" style="--lq:url(data:image/webp;base64,UklGRqgAAABXRUJQVlA4IJwAAACQAwCdASoUAAsAPpE6mEeloyKhMAgAsBIJZQATgABhCxOL53bwAP3D+0RO8JAjTOEbmNJNfsR6usbaNte9vtIYQK9L87/6V+7T5oR9TRF+mBLWb3/Tp6vu3l4k4PfUTfJnibMYsyM62R7M3CIMWOXx4s0f3zos3DUpGTrQNHRVLTgIGv7qpBU9B65QT+nCVTUQlqBz9wXrxDQAAAA=)"><img alt="Fietsers op een brede straat in Rotterdam" width="900" height="491" decoding="async" loading="lazy" data-src="https://neddev.com/lab-media/lazy-blur-up-3.webp"><div class="lbu__err" role="alert" hidden><span>Foto niet geladen</span><button type="button" class="lbu__retry">Opnieuw</button></div><figcaption>Rotterdam</figcaption></figure>
</div>
<div class="lbu__ctl"><button class="lbu__b" type="button" data-a="reload">Opnieuw laden</button><button class="lbu__b" type="button" data-a="err">Toon foutstaat</button><span class="lbu__st" aria-live="polite"></span></div>
</div>
</div>/* Afbeelding laadt met blur-up · NedDev · eigen werk. */
.lbu{position:absolute;inset:0;display:flex;flex-direction:column;gap:12px;padding:14px;background:#f4f3f1;font-family:'Switzer',system-ui,sans-serif;color:#0a0a0a}
.lbu__grid{flex:1;min-height:0;display:grid;grid-template-columns:1.3fr 1fr 1fr;gap:8px}
.lbu__f{position:relative;margin:0;min-height:0;border-radius:4px;overflow:hidden;background:#cfc9bf}
.lbu__f::before{content:'';position:absolute;inset:-12px;background:var(--lq) center/cover no-repeat;filter:blur(10px);transform:scale(1.05)}
.lbu__f img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;filter:blur(14px);transform:scale(1.06);transition:opacity .5s ease,filter .7s cubic-bezier(.2,.7,.2,1),transform .7s cubic-bezier(.2,.7,.2,1)}
.lbu__f.is-loaded img{opacity:1;filter:none;transform:none}
.lbu__f::after{content:'';position:absolute;left:8px;top:8px;width:12px;height:12px;border-radius:50%;border:2px solid rgba(255,255,255,.4);border-top-color:#fff;animation:lbu-rot .8s linear infinite;transition:opacity .2s}
.lbu__f.is-loaded::after,.lbu__f.is-err::after{opacity:0;animation:none}
.lbu__f figcaption{position:absolute;left:8px;bottom:7px;z-index:2;font:500 10px 'JetBrains Mono',monospace;letter-spacing:.06em;text-transform:uppercase;color:#fff;text-shadow:0 1px 3px rgba(0,0,0,.6)}
.lbu__err{position:absolute;inset:0;z-index:3;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;background:#e6e2da;font-size:11.5px;text-align:center;padding:8px}
.lbu__err[hidden]{display:none}
.lbu__retry,.lbu__b{appearance:none;border:1px solid #0a0a0a;background:#fff;color:#0a0a0a;font:600 11.5px 'Switzer',sans-serif;padding:6px 10px;border-radius:999px;cursor:pointer;transition:background-color .16s,color .16s}
.lbu__retry:hover,.lbu__b:hover{background:#0a0a0a;color:#fff}
.lbu__retry:focus-visible,.lbu__b:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.lbu__ctl{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.lbu__st{font:500 10px 'JetBrains Mono',monospace;color:#5f5a54;text-transform:uppercase;letter-spacing:.06em}
@keyframes lbu-rot{to{transform:rotate(1turn)}}
@media (prefers-reduced-motion:reduce){.lbu__f img{transition:opacity .2s}.lbu__f::after{animation-duration:2.4s}}
@media (max-width:420px){.lbu{gap:8px;padding:10px}.lbu__st{display:none}}// Afbeelding laadt met blur-up · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
root=root.querySelector('.lbu')||root;
var figs=[].slice.call(root.querySelectorAll('.lbu__f')),st=root.querySelector('.lbu__st'),run=0;
function load(f,delay,fail){var img=f.querySelector('img'),err=f.querySelector('.lbu__err');f.classList.remove('is-loaded','is-err');err.hidden=true;img.removeAttribute('src');var my=run;
setTimeout(function(){if(my!==run)return;
if(fail){f.classList.add('is-err');err.hidden=false;return;}
img.onload=function(){if(my!==run)return;(img.decode?img.decode():Promise.resolve()).catch(function(){}).then(function(){f.classList.add('is-loaded');if(root.querySelectorAll('.is-loaded').length===figs.length)st.textContent='Alle foto\'s geladen';});};
img.onerror=function(){f.classList.add('is-err');err.hidden=false;};
img.src=img.getAttribute('data-src');},delay);}
function all(failIdx){run++;st.textContent='Laden met trage verbinding';figs.forEach(function(f,i){load(f,700+i*550,i===failIdx);});}
root.querySelector('[data-a="reload"]').addEventListener('click',function(){all(-1);});
root.querySelector('[data-a="err"]').addEventListener('click',function(){all(1);});
figs.forEach(function(f){f.querySelector('.lbu__retry').addEventListener('click',function(){var r=++run;load(f,600,false);run=r;});});
if('IntersectionObserver' in window){var io=new IntersectionObserver(function(es){if(es[0].isIntersecting){io.disconnect();all(-1);}});io.observe(root);}else all(-1);
}
init(document.querySelector('.jouw-container'));
More components
Seen something you like?
Add it to your selection and send it over. We build your site around it, in your brand.
Get in touch →