Vorige / volgende met richting New
Step through a case with previous/next (or arrow keys): forward slides content left, back slides it right, the counter rolls along. Uses View Transition types (:active-view-transition-type), without types a plain fade, without View Transitions an instant swap. Multi-page: @view-transition { navigation: auto; types: forward; } or set the type in the pageswap/pagereveal event based on the URL.
Case · woonboerderij Staphorst
pijltjes werken ook
How to use it
- Paste the HTML where the navigation & menus 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.
<!-- Vorige / volgende met richting · NedDev · eigen werk. -->
<div class="jouw-container">
<!-- Echte multi-page site (bv. /case/stap-2 naar /case/stap-3):
1. CSS op elke pagina: @view-transition { navigation: auto; }
2. Zet de richting in pagereveal: addEventListener('pagereveal', e => { if (!e.viewTransition) return; const terug = ...; e.viewTransition.types.add(terug ? 'vtr-terug' : 'vtr-vooruit'); });
(bepaal 'terug' door het stapnummer van navigation.activation.from en .entry te vergelijken)
3. Zelfde view-transition-name (vtr-panel, vtr-count) op beide pagina's en de :active-view-transition-type regels uit de CSS
4. Reduced motion: @media (prefers-reduced-motion: reduce) { ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; } } -->
<div class="vtr" tabindex="-1">
<div class="vtr__top">
<span class="vtr__kick">Case · woonboerderij Staphorst</span>
<span class="vtr__count" aria-hidden="true"><b class="vtr__n">01</b> / 05</span>
</div>
<ol class="vtr__bar" aria-hidden="true"><li></li><li></li><li></li><li></li><li></li></ol>
<div class="vtr__panel">
<span class="vtr__step"></span>
<h3 class="vtr__h"></h3>
<p class="vtr__p"></p>
</div>
<div class="vtr__nav">
<button class="vtr__btn vtr__prev" type="button"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M10 3L5 8l5 5"/></svg>Vorige</button>
<span class="vtr__hint">pijltjes werken ook</span>
<button class="vtr__btn vtr__next" type="button">Volgende<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M6 3l5 5-5 5"/></svg></button>
</div>
<span class="vtr__sr" aria-live="polite"></span>
</div>
</div>/* Vorige / volgende met richting · NedDev · eigen werk. */
.vtr{position:absolute;inset:0;display:flex;flex-direction:column;padding:14px 16px 12px;background:#fff;color:#0a0a0a;font-family:'Switzer',system-ui,sans-serif;overflow:hidden}
.vtr:focus{outline:none}
.vtr__top{display:flex;justify-content:space-between;align-items:baseline;gap:10px}
.vtr__kick{font:500 10px 'JetBrains Mono',monospace;letter-spacing:.12em;text-transform:uppercase;color:rgba(10,10,10,.6)}
.vtr__count{font:500 11px 'JetBrains Mono',monospace;color:rgba(10,10,10,.45);font-variant-numeric:tabular-nums;white-space:nowrap}
.vtr__n{display:inline-block;color:#0a0a0a;font-weight:700}
.vtr__bar{list-style:none;margin:10px 0 0;padding:0;display:grid;grid-template-columns:repeat(5,1fr);gap:4px}
.vtr__bar li{height:3px;background:rgba(10,10,10,.12);border-radius:2px;transition:background-color .3s}
.vtr__bar li.is-on{background:#F5480F}
.vtr__panel{flex:1;min-height:0;padding-top:14px}
.vtr__step{display:block;font:500 10.5px 'JetBrains Mono',monospace;color:#F5480F;margin-bottom:5px}
.vtr__h{margin:0 0 7px;font-size:20px;line-height:1.15;font-weight:700;letter-spacing:-.01em}
.vtr__p{margin:0;font-size:13px;line-height:1.5;color:rgba(10,10,10,.72);max-width:32em}
.vtr__nav{display:flex;align-items:center;justify-content:space-between;gap:8px;border-top:1px solid rgba(10,10,10,.1);padding-top:10px}
.vtr__hint{font:500 9.5px 'JetBrains Mono',monospace;color:rgba(10,10,10,.4);letter-spacing:.06em}
.vtr__btn{all:unset;box-sizing:border-box;display:inline-flex;align-items:center;gap:5px;font-size:12.5px;font-weight:600;padding:7px 11px;border-radius:4px;cursor:pointer;transition:background-color .15s,color .15s,border-color .15s}
.vtr__btn svg{width:13px;height:13px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.vtr__prev{border:1px solid rgba(10,10,10,.2);color:#0a0a0a}
.vtr__prev:hover{border-color:#0a0a0a}
.vtr__next{background:#0a0a0a;color:#fff;border:1px solid #0a0a0a}
.vtr__next:hover{background:#F5480F;border-color:#F5480F}
.vtr__btn:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.vtr__btn:active{transform:translateY(1px)}
.vtr__btn:disabled,.vtr__btn[aria-disabled="true"]{opacity:.38;cursor:not-allowed;transform:none}
.vtr__prev[aria-disabled="true"]:hover{border-color:rgba(10,10,10,.2)}
.vtr__next[aria-disabled="true"]:hover{background:#0a0a0a;border-color:#0a0a0a}
.vtr__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
@media (max-width:420px){.vtr{padding:12px 13px 10px}.vtr__h{font-size:17px}.vtr__p{font-size:12px}.vtr__hint{display:none}.vtr__panel{padding-top:10px}}
/* richting via View Transition types */
::view-transition-group(vtr-panel),::view-transition-group(vtr-count){overflow:clip}
:active-view-transition-type(vtr-vooruit)::view-transition-old(vtr-panel){animation:vtr-uitl .18s cubic-bezier(.4,0,1,1) both}
:active-view-transition-type(vtr-vooruit)::view-transition-new(vtr-panel){animation:vtr-inr .34s cubic-bezier(.2,.7,.2,1) .12s both}
:active-view-transition-type(vtr-terug)::view-transition-old(vtr-panel){animation:vtr-uitr .18s cubic-bezier(.4,0,1,1) both}
:active-view-transition-type(vtr-terug)::view-transition-new(vtr-panel){animation:vtr-inl .34s cubic-bezier(.2,.7,.2,1) .12s both}
:active-view-transition-type(vtr-vooruit)::view-transition-old(vtr-count){animation:vtr-uito .24s ease-in both}
:active-view-transition-type(vtr-vooruit)::view-transition-new(vtr-count){animation:vtr-inb .3s cubic-bezier(.2,.7,.2,1) both}
:active-view-transition-type(vtr-terug)::view-transition-old(vtr-count){animation:vtr-uitb .24s ease-in both}
:active-view-transition-type(vtr-terug)::view-transition-new(vtr-count){animation:vtr-ino .3s cubic-bezier(.2,.7,.2,1) both}
@keyframes vtr-uitl{to{opacity:0;transform:translateX(-18%)}}
@keyframes vtr-inr{from{opacity:0;transform:translateX(18%)}}
@keyframes vtr-uitr{to{opacity:0;transform:translateX(18%)}}
@keyframes vtr-inl{from{opacity:0;transform:translateX(-18%)}}
@keyframes vtr-uito{to{opacity:0;transform:translateY(-100%)}}
@keyframes vtr-inb{from{opacity:0;transform:translateY(100%)}}
@keyframes vtr-uitb{to{opacity:0;transform:translateY(100%)}}
@keyframes vtr-ino{from{opacity:0;transform:translateY(-100%)}}
@media (prefers-reduced-motion:reduce){::view-transition-old(vtr-panel),::view-transition-new(vtr-panel),::view-transition-old(vtr-count),::view-transition-new(vtr-count){animation:none!important}}// Vorige / volgende met richting · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.vtr');if(!w)return;
var S=[['Intake','di 3 feb','Rondgang met de bewoners. Wensen, planning en budget van € 185.000 vastgelegd in één A4.'],
['Ontwerp','di 3 mrt','Drie varianten getekend. De keuze viel op een open deel met vide en de oude spanten in het zicht.'],
['Vergunning','do 16 apr','Omgevingsvergunning aangevraagd via het Omgevingsloket, na zes weken verleend zonder aanvullende eisen.'],
['Uitvoering','ma 1 jun','Fundering hersteld, nieuwe kap en vloerverwarming. Veertien weken op de bouwplaats, twee weken voor op schema.'],
['Oplevering','vr 11 sep','Opgeleverd zonder restpunten. Energielabel van F naar A, gasaansluiting eraf.']];
var panel=w.querySelector('.vtr__panel'),cnt=w.querySelector('.vtr__n'),bar=[].slice.call(w.querySelectorAll('.vtr__bar li')),prev=w.querySelector('.vtr__prev'),next=w.querySelector('.vtr__next'),sr=w.querySelector('.vtr__sr');
var rm=matchMedia('(prefers-reduced-motion: reduce)');var i=0,busy=false;
var hasTypes=typeof ViewTransition!=='undefined'&&'types' in ViewTransition.prototype;
function render(){var s=S[i];panel.querySelector('.vtr__step').textContent='Stap '+(i+1)+' · '+s[1];panel.querySelector('.vtr__h').textContent=s[0];panel.querySelector('.vtr__p').textContent=s[2];cnt.textContent='0'+(i+1);
bar.forEach(function(b,k){b.classList.toggle('is-on',k<=i);});prev.setAttribute('aria-disabled',i===0?'true':'false');next.setAttribute('aria-disabled',i===S.length-1?'true':'false');}
function go(d){var n=i+d;if(busy||n<0||n>=S.length)return;var upd=function(){i=n;render();sr.textContent='Stap '+(i+1)+' van '+S.length+': '+S[i][0];};
if(!document.startViewTransition||rm.matches){upd();return;}busy=true;panel.style.viewTransitionName='vtr-panel';cnt.style.viewTransitionName='vtr-count';
var t=hasTypes?document.startViewTransition({update:upd,types:[d>0?'vtr-vooruit':'vtr-terug']}):document.startViewTransition(upd);
t.finished.finally(function(){panel.style.viewTransitionName='';cnt.style.viewTransitionName='';busy=false;});}
prev.addEventListener('click',function(){go(-1);});next.addEventListener('click',function(){go(1);});
w.addEventListener('keydown',function(e){if(e.key==='ArrowRight'){e.preventDefault();go(1);}else if(e.key==='ArrowLeft'){e.preventDefault();go(-1);}});
render();
}
init(document.querySelector('.jouw-container'));
More navigation & menus
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 →