Foto opent door de letters New
The place name fills the frame with the photo only inside the letters; then the letters grow and the photo bursts open from the middle of the word until it fills the whole frame, and the heading and button appear. Built with an SVG mask, no library. Use it as the hero of a holiday park, hotel or regional brand where the place itself is the story. With reduced motion the end state shows at once.
Chalets achter de duinen van Texel
Veertig chalets bij De Koog, vanaf € 89 per nacht.
Bekijk de chaletsHow to use it
- Paste the HTML where the hero styles 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.
<!-- Foto opent door de letters · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie -->
<div class="jouw-container">
<div class="hlo">
<svg class="hlo__svg" viewBox="0 0 1000 625" preserveAspectRatio="xMidYMid slice" aria-hidden="true" focusable="false">
<defs><mask id="hlo-m" maskUnits="userSpaceOnUse" x="0" y="0" width="1000" height="625"><rect width="1000" height="625" fill="#000"/><g class="hlo__mg"><text class="hlo__word" x="500" y="408" text-anchor="middle">Texel</text></g><circle class="hlo__c" cx="500" cy="300" r="0" fill="#fff"/></mask></defs>
<rect width="1000" height="625" fill="#f4f3f1"/>
<image class="hlo__img" href="https://neddev.com/lab-media/hk-letters-openen-1.webp" width="1000" height="625" preserveAspectRatio="xMidYMid slice" mask="url(#hlo-m)"/>
</svg>
<div class="hlo__shade" aria-hidden="true"></div>
<div class="hlo__txt">
<h2 class="hlo__h">Chalets achter de duinen van Texel</h2>
<p class="hlo__p">Veertig chalets bij De Koog, vanaf € 89 per nacht.</p>
<a class="hlo__cta" href="#hk-letters-openen">Bekijk de chalets</a>
</div>
<button class="hlo__again" type="button">Nog eens</button>
</div>
</div>/* Foto opent door de letters · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie */
.hlo{position:absolute;inset:0;overflow:hidden;background:#f4f3f1;color:#fff;font-family:'Switzer',sans-serif;container-type:size;text-align:left}
.hlo *,.hlo *::before,.hlo *::after{box-sizing:border-box}
.hlo__svg{position:absolute;inset:0;width:100%;height:100%;display:block}
.hlo__word{font:700 300px/1 'Switzer',sans-serif;letter-spacing:-12px;fill:#fff}
.hlo__shade{position:absolute;inset:0;background:linear-gradient(0deg,rgba(10,10,10,.72),rgba(10,10,10,.12) 62%,rgba(10,10,10,0));opacity:0;transition:opacity .6s ease}
.hlo__txt{position:absolute;left:20px;right:20px;bottom:18px;display:flex;flex-direction:column;align-items:flex-start;gap:6px;opacity:0;transform:translateY(10px);transition:opacity .5s ease,transform .5s ease;pointer-events:none}
.hlo.is-open .hlo__shade{opacity:1}
.hlo.is-open .hlo__txt{opacity:1;transform:none;pointer-events:auto}
.hlo__h{margin:0;font:700 clamp(19px,6.6cqi,40px)/1.04 'Switzer',sans-serif;letter-spacing:-.02em;max-width:15em;text-wrap:balance}
.hlo__p{margin:0;font:400 clamp(12px,3cqi,16px)/1.4 'Switzer',sans-serif;color:#eceae6}
.hlo__cta{margin-top:4px;padding:9px 14px;background:#F5480F;color:#0a0a0a;border-radius:4px;font:600 13px/1 'Switzer',sans-serif;text-decoration:none;transition:background-color .16s}
.hlo__cta:hover{background:#ff6a36}
.hlo__cta:focus-visible,.hlo__again:focus-visible{outline:2px solid #fff;outline-offset:3px}
.hlo__again{position:absolute;top:12px;right:12px;min-height:30px;padding:0 10px;border:1px solid rgba(10,10,10,.25);border-radius:4px;background:#fff;color:#0a0a0a;font:500 12px/1 'Switzer',sans-serif;cursor:pointer;transition:background-color .16s}
.hlo__again:hover{background:#f4f3f1}// Foto opent door de letters · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie
// root = het element waarin de HTML staat
function init(root){
const w=root.querySelector('.hlo');if(!w)return;
const uid='hlo-m-'+Math.random().toString(36).slice(2,8);
const m=w.querySelector('mask'),img=w.querySelector('.hlo__img'),g=w.querySelector('.hlo__mg'),t=w.querySelector('.hlo__word'),btn=w.querySelector('.hlo__again');
m.id=uid;img.setAttribute('mask','url(#'+uid+')');
const rm=matchMedia('(prefers-reduced-motion: reduce)').matches;
let raf=0,tm=0;
const c=w.querySelector('.hlo__c');
function set(s,r){g.setAttribute('transform','translate(500 300) scale('+s+') translate(-500 -300)');c.setAttribute('r',r);}
function end(){set(14,1300);w.classList.add('is-open');}
function play(){cancelAnimationFrame(raf);clearTimeout(tm);w.classList.remove('is-open');set(1,0);
if(rm){end();return;}
tm=setTimeout(()=>{const t0=performance.now(),D=1600;
const step=n=>{const k=Math.min(1,(n-t0)/D),e=k<.5?4*k*k*k:1-Math.pow(-2*k+2,3)/2,e2=Math.max(0,(k-.18)/.82);
set(Math.pow(14,e),1300*e2*e2);
if(k<1)raf=requestAnimationFrame(step);else w.classList.add('is-open');};raf=requestAnimationFrame(step);},1100);}
btn.addEventListener('click',play);
const go=()=>{if(document.fonts&&document.fonts.ready)document.fonts.ready.then(play);else play();};
if('IntersectionObserver' in window){const io=new IntersectionObserver(es=>{if(es[0].isIntersecting){io.disconnect();go();}},{threshold:.4});io.observe(w);}else go();
}
init(document.querySelector('.jouw-container'));
More hero styles
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 →