Kader opent tot volle breedte Nieuw
Een foto staat eerst in een kader met witte rand en gaat bij het scrollen open tot de volle breedte, via clip-path: inset() en een lichte terugzoom. Gebruikt een scroll-driven animation (scroll-timeline op de eigen scrollcontainer, @property voor de voortgang); zonder ondersteuning neemt een klein scroll-script het over. Bij minder beweging staat het beeld direct open.
Wonen aan de Vecht
Een villa van baksteen en glas in Maarssen, ontworpen door Studio Kade.

Villa Zuilen, 240 m², opgeleverd in juni 2026
Daarna loopt de pagina door met plattegronden, materialen en de bouwtijd.
Zo gebruik je het
- Plak de HTML op de plek waar het onderdeel moet komen.
- Zet de CSS in je stylesheet. Alle klassen hebben een eigen voorvoegsel, dus niets botst met je eigen opmaak.
- Voeg de JavaScript toe en roep init() aan met het element waar de HTML in staat.
<!-- Kader opent tot volle breedte · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="vpk">
<div class="vpk__sc" tabindex="0" aria-label="Voorbeeld: villa aan de Vecht, scroll om het kader te openen">
<div class="vpk__track"><div class="vpk__pin">
<div class="vpk__intro"><h3 class="vpk__h">Wonen aan de Vecht</h3><p class="vpk__p">Een villa van baksteen en glas in Maarssen, ontworpen door Studio Kade.</p></div>
<div class="vpk__frame"><img class="vpk__img" src="https://neddev.com/lab-media/viewport-kader-1.webp" alt="Bakstenen villa met grote ramen aan het water" loading="lazy"></div>
<p class="vpk__cap">Villa Zuilen, 240 m², opgeleverd in juni 2026</p>
</div></div>
<div class="vpk__na"><p>Daarna loopt de pagina door met plattegronden, materialen en de bouwtijd.</p></div>
</div>
</div>
</div>/* Kader opent tot volle breedte · NedDev · eigen werk. */
@property --vpk-p{syntax:'<number>';inherits:true;initial-value:0}
.vpk{position:absolute;inset:0;background:#fff;color:#0a0a0a;font-family:'Switzer',sans-serif;container-type:size;text-align:left}
.vpk__sc{position:absolute;inset:0;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin;scroll-timeline:--vpk-tl y}
.vpk__sc:focus-visible{outline:2px solid #F5480F;outline-offset:-2px}
.vpk__track{height:260cqh;position:relative}
.vpk__pin{position:sticky;top:0;height:100cqh;overflow:hidden;--vpk-p:0}
@supports (animation-timeline: scroll()){.vpk__pin{animation:vpk-open linear both;animation-timeline:--vpk-tl;animation-range:0% 60%}}
@keyframes vpk-open{to{--vpk-p:1}}
.vpk__intro{position:absolute;left:16px;right:16px;top:12px;opacity:calc(1 - var(--vpk-p)*2.4)}
.vpk__h{margin:0;font:700 clamp(17px,5.6cqi,34px)/1.05 'Switzer',sans-serif;letter-spacing:-.025em}
.vpk__p{margin:4px 0 0;font:400 clamp(11px,3cqi,15px)/1.4 'Switzer',sans-serif;color:#4a4845;max-width:34em}
.vpk__frame{position:absolute;inset:0;overflow:hidden;clip-path:inset(calc((1 - var(--vpk-p))*40%) calc((1 - var(--vpk-p))*16px) calc((1 - var(--vpk-p))*16px) round calc((1 - var(--vpk-p))*4px))}
.vpk__img{display:block;width:100%;height:100%;object-fit:cover;transform:scale(calc(1.14 - .14*var(--vpk-p)))}
.vpk__cap{position:absolute;left:16px;bottom:14px;margin:0;color:#fff;font:600 clamp(13px,3.6cqi,18px)/1.2 'Switzer',sans-serif;text-shadow:0 1px 10px rgba(0,0,0,.6);opacity:calc((var(--vpk-p) - .75)*4)}
.vpk__na{padding:18px 16px 28px;font:400 14px/1.5 'Switzer',sans-serif;color:#4a4845}
.vpk__na p{margin:0}
@media (prefers-reduced-motion:reduce){.vpk__pin{animation:none!important;--vpk-p:1}.vpk__track{height:auto}.vpk__pin{position:relative}.vpk__intro{display:none}}// Kader opent tot volle breedte · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.vpk');if(!w)return;
var sc=w.querySelector('.vpk__sc'),pin=w.querySelector('.vpk__pin'),tr=w.querySelector('.vpk__track');
var rm=matchMedia('(prefers-reduced-motion: reduce)').matches;if(rm)return;
if(!(window.CSS&&CSS.supports&&CSS.supports('animation-timeline: scroll()'))){var tick=false;
function upd(){tick=false;var max=sc.scrollHeight-sc.clientHeight;var p=max>0?Math.min(1,sc.scrollTop/(max*.6)):0;pin.style.setProperty('--vpk-p',p.toFixed(4));}
sc.addEventListener('scroll',function(){if(!tick){tick=true;requestAnimationFrame(upd);}},{passive:true});upd();}
var on=true,t0=0;['wheel','touchstart','pointerdown','keydown','focusin'].forEach(function(ev){w.addEventListener(ev,function(){on=false;},{passive:true});});
function drift(now){if(!on)return;if(!t0)t0=now;var m=tr.offsetHeight-sc.clientHeight;sc.scrollTop=m*(.5-.5*Math.cos((now-t0)/1000*.4));requestAnimationFrame(drift);}
setTimeout(function(){if(on)requestAnimationFrame(drift);},900);
}
init(document.querySelector('.jouw-container'));
Meer uit scroll-effecten
Iets gezien dat je mooi vindt?
Zet het in je selectie en stuur hem op. Dan bouwen we je site eromheen, in jouw huisstijl.
Neem contact op →