Voordeur zwaait open, je stapt naar binnen New
A facade with a front door: scrolling swings the door open, you step through until the hallway fills the box, then a card slides in with address, floor area, asking price and a viewing button. For an estate agent listing, an open house or the hero of an interior builder. Own scroll box with keyboard support; with reduced motion the door fades and the hallway cross-fades in without zoom.
Lindelaan 42, Hilversum
Jaren 30 · 132 m² · 4 slaapkamers
Vraagprijs € 685.000 k.k.
How to use it
- Paste the HTML where the scroll effects 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.
<!-- Voordeur zwaait open, je stapt naar binnen · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie -->
<div class="jouw-container">
<div class="dr">
<div class="dr__vak" tabindex="0" role="region" aria-label="Woning Lindelaan 42 in Hilversum. Scroll in dit vak om naar binnen te gaan.">
<div class="dr__baan">
<div class="dr__beeld">
<div class="dr__wereld">
<div class="dr__raam dr__raam--l" aria-hidden="true"></div>
<div class="dr__raam dr__raam--r" aria-hidden="true"></div>
<div class="dr__opening">
<img class="dr__binnen" src="https://neddev.com/lab-media/r7scr-deur-1.webp" alt="Lichte gang met houten vloer en trap" width="896" height="1200">
<div class="dr__deur" aria-hidden="true"><i class="dr__glas"></i><i class="dr__bus"></i><i class="dr__knop"></i></div>
</div>
<p class="dr__nr" aria-hidden="true">42</p>
<i class="dr__stoep" aria-hidden="true"></i>
</div>
<img class="dr__vol" src="https://neddev.com/lab-media/r7scr-deur-1.webp" alt="" width="896" height="1200">
<div class="dr__kaart" inert>
<h3 class="dr__adres">Lindelaan 42, Hilversum</h3>
<p class="dr__p">Jaren 30 · 132 m² · 4 slaapkamers</p>
<p class="dr__prijs">Vraagprijs € 685.000 k.k.</p>
<button type="button" class="dr__actie">Plan een bezichtiging</button>
<p class="dr__status" aria-live="polite"></p>
</div>
</div>
</div>
</div>
<p class="dr__hint" aria-hidden="true">Scroll om binnen te stappen</p>
</div>
</div>/* Voordeur zwaait open, je stapt naar binnen · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie */
.dr{position:absolute;inset:0;container-type:size;font-family:'Switzer',system-ui,sans-serif;color:#0a0a0a;background:#9d4e36}
.dr__vak{position:absolute;inset:0;overflow-y:auto;scrollbar-width:none}
.dr__vak::-webkit-scrollbar{display:none}
.dr__vak:focus-visible{outline:2px solid #F5480F;outline-offset:-2px}
.dr__baan{height:500cqh}
.dr__beeld{position:sticky;top:0;height:100cqh;overflow:hidden}
.dr__wereld{position:absolute;inset:0;background-color:#9d4e36;background-image:repeating-linear-gradient(0deg,rgba(244,243,241,.28) 0 1px,transparent 1px 8px),repeating-linear-gradient(90deg,rgba(244,243,241,.18) 0 1px,transparent 1px 22px);will-change:transform}
.dr__opening{position:absolute;left:50%;bottom:10cqh;height:72cqh;aspect-ratio:.52;transform:translateX(-50%);perspective:520px;background:#0a0a0a;box-shadow:0 0 0 5px #fff;overflow:hidden}
.dr__binnen{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.dr__deur{position:absolute;inset:0;background:#F5480F;transform-origin:0 50%;box-shadow:inset 0 0 0 4px #c63a0c}
.dr__glas{position:absolute;left:18%;right:18%;top:8%;height:30%;background:linear-gradient(160deg,#e9eef0,#bfcad0);box-shadow:0 0 0 3px #fff;background-image:linear-gradient(90deg,transparent 48%,#fff 48% 52%,transparent 52%),linear-gradient(160deg,#e9eef0,#bfcad0)}
.dr__bus{position:absolute;left:30%;right:30%;top:56%;height:4%;background:#0a0a0a;border-radius:2px}
.dr__knop{position:absolute;right:12%;top:52%;width:7%;aspect-ratio:1;border-radius:50%;background:#0a0a0a}
.dr__raam{position:absolute;bottom:24cqh;width:20cqw;height:38cqh;background:linear-gradient(90deg,transparent 48%,#fff 48% 52%,transparent 52%),linear-gradient(200deg,#f0f3f4,#b9c4ca);box-shadow:0 0 0 4px #fff}
.dr__raam--l{left:6cqw}.dr__raam--r{right:6cqw}
.dr__nr{z-index:2;position:absolute;left:50%;top:calc(18cqh - 26px);transform:translateX(-50%);margin:0;background:#fff;font-size:13px;font-weight:700;padding:1px 7px;border-radius:4px}
.dr__stoep{position:absolute;left:0;right:0;bottom:0;height:10cqh;background:#6e6a64}
.dr__vol{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;display:block}
.dr__kaart{position:absolute;left:10px;bottom:10px;max-width:250px;background:#fff;border-radius:4px;padding:8px 10px;opacity:0}
.dr__adres{font-size:15px;font-weight:700;margin:0 0 2px;line-height:1.2}
.dr__p,.dr__prijs{font-size:12px;margin:0;line-height:1.4}
.dr__prijs{font-weight:600;margin-bottom:6px}
.dr__actie{font:600 12px 'Switzer',system-ui,sans-serif;min-height:28px;padding:5px 10px;border:0;border-radius:4px;background:#F5480F;color:#0a0a0a;cursor:pointer}
.dr__actie:hover{background:#0a0a0a;color:#fff}
.dr__actie:focus-visible{outline:2px solid #0a0a0a;outline-offset:2px}
.dr__status{font-size:12px;margin:4px 0 0}
.dr__status:empty{display:none}
.dr__hint{position:absolute;right:10px;top:8px;margin:0;font-size:12px;background:#fff;padding:3px 8px;border-radius:4px;pointer-events:none;transition:opacity .3s}
.dr.is-weg .dr__hint{opacity:0}// Voordeur zwaait open, je stapt naar binnen · © 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('.dr'); if (!w) return;
const vak = w.querySelector('.dr__vak'), wereld = w.querySelector('.dr__wereld'), opening = w.querySelector('.dr__opening'), deur = w.querySelector('.dr__deur');
const vol = w.querySelector('.dr__vol'), kaart = w.querySelector('.dr__kaart'), actie = w.querySelector('.dr__actie'), status = w.querySelector('.dr__status');
const rm = matchMedia('(prefers-reduced-motion: reduce)').matches;
const cl = v => v < 0 ? 0 : v > 1 ? 1 : v, ease = t => t < .5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
let raf = 0;
function teken() {
raf = 0; const m = vak.scrollHeight - vak.clientHeight, p = m > 0 ? vak.scrollTop / m : 0;
const a = ease(cl(p / .4)), b = ease(cl((p - .42) / .36)), c = cl((p - .8) / .12);
if (rm) { deur.style.opacity = 1 - a; vol.style.opacity = b; }
else {
deur.style.transform = 'rotateY(' + (a * 96).toFixed(1) + 'deg)';
const W = vak.clientWidth, H = vak.clientHeight, oW = opening.offsetWidth, oH = opening.offsetHeight;
const ox = W / 2, oy = H - H * .1 - oH / 2, sEind = Math.max(W / oW, H / oH) * 1.04, s = 1 + (sEind - 1) * b;
wereld.style.transformOrigin = ox + 'px ' + oy + 'px';
wereld.style.transform = 'translate(' + ((W / 2 - ox) * b).toFixed(1) + 'px,' + ((H / 2 - oy) * b).toFixed(1) + 'px) scale(' + s.toFixed(4) + ')';
}
kaart.style.opacity = c; kaart.style.transform = rm ? '' : 'translateY(' + ((1 - c) * 12).toFixed(1) + 'px)';
kaart.inert = c < .9;
w.classList.toggle('is-weg', vak.scrollTop > 8);
}
actie.addEventListener('click', () => { status.textContent = 'Dank je. We bellen je vandaag nog om een tijd af te spreken.'; actie.hidden = true; });
vak.addEventListener('scroll', () => { if (!raf) raf = requestAnimationFrame(teken); }, { passive: true });
if (window.ResizeObserver) new ResizeObserver(() => teken()).observe(vak);
teken();
}
init(document.querySelector('.jouw-container'));
More scroll effects
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 →