Zon komt op en gaat onder Nieuw
Scroll en de dag loopt voorbij boven zee: de zon komt op, klimt en gaat onder, de lucht kleurt van nacht via ochtendrood naar blauw en weer terug, en er verschijnen sterren en een maan. Een kaartje toont de klok en wat er op dat uur te doen is. Voor de hero of openingstijden van een strandpaviljoen, camping of hotel. Eigen scrollvak met toetsenbord; alleen kleur en positie, geen zware effecten.
05:00
Nog even stil Om 08:00 gaan we open.
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.
<!-- Zon komt op en gaat onder · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie -->
<div class="jouw-container">
<div class="zd">
<div class="zd__vak" tabindex="0" role="region" aria-label="Een dag bij Paviljoen Noordstrand in Zandvoort. Scroll in dit vak om de tijd te laten lopen.">
<div class="zd__baan">
<div class="zd__beeld">
<div class="zd__sterren" aria-hidden="true"></div>
<div class="zd__maan" aria-hidden="true"></div>
<div class="zd__zon" aria-hidden="true"></div>
<div class="zd__zee" aria-hidden="true"><i class="zd__glans"></i></div>
<svg class="zd__duin" viewBox="0 0 400 60" preserveAspectRatio="none" aria-hidden="true"><path d="M0 60V26C40 10 80 8 120 22S190 40 230 30 320 6 400 20V60Z"/></svg>
<div class="zd__kaart"><p class="zd__tijd">05:00</p><p class="zd__wat" aria-live="polite"><strong>Nog even stil</strong> <span>Om 08:00 gaan we open.</span></p></div>
</div>
</div>
</div>
<p class="zd__hint" aria-hidden="true">Scroll door de dag</p>
</div>
</div>/* Zon komt op en gaat onder · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie */
.zd{position:absolute;inset:0;container-type:size;font-family:'Switzer',system-ui,sans-serif;color:#0a0a0a;background:#0b0f16}
.zd__vak{position:absolute;inset:0;overflow-y:auto;scrollbar-width:none}
.zd__vak::-webkit-scrollbar{display:none}
.zd__vak:focus-visible{outline:2px solid #F5480F;outline-offset:-2px}
.zd__baan{height:600cqh}
.zd__beeld{position:sticky;top:0;height:100cqh;overflow:hidden;background:linear-gradient(#0b0f16,#1b2330)}
.zd__sterren{position:absolute;inset:0 0 40% 0;background:radial-gradient(circle,#fff 1px,transparent 1.4px) 0 0/37px 29px,radial-gradient(circle,#fff .8px,transparent 1.2px) 13px 9px/53px 41px}
.zd__zon,.zd__maan{position:absolute;left:0;top:0;width:14cqh;height:14cqh;margin:-7cqh 0 0 -7cqh;border-radius:50%}
.zd__zon{background:#ffd27a;box-shadow:0 0 0 6px rgba(255,210,122,.25)}
.zd__maan{background:#f1efe8;box-shadow:inset -5px -3px 0 #c9c5ba;left:22cqw;top:20cqh;width:9cqh;height:9cqh}
.zd__zee{position:absolute;left:0;right:0;top:66%;bottom:0;background:#1b2330;overflow:hidden}
.zd__glans{position:absolute;top:0;bottom:0;width:10cqh;margin-left:-5cqh;background:repeating-linear-gradient(#ffd27a 0 2px,transparent 2px 6px);opacity:0}
.zd__duin{position:absolute;left:0;bottom:0;width:100%;height:22%;fill:#1a1a1a}
.zd__kaart{position:absolute;left:12px;bottom:12px;max-width:62%;background:#fff;border-radius:4px;padding:7px 10px}
.zd__tijd{margin:0;font-size:clamp(18px,6cqw,24px);font-weight:700;font-variant-numeric:tabular-nums;line-height:1.1}
.zd__wat{margin:2px 0 0;font-size:12px;line-height:1.35}
.zd__wat strong{font-weight:600}
.zd__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}
.zd.is-weg .zd__hint{opacity:0}// Zon komt op en gaat onder · © 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('.zd'); if (!w) return;
const vak = w.querySelector('.zd__vak'), beeld = w.querySelector('.zd__beeld'), zon = w.querySelector('.zd__zon'), maan = w.querySelector('.zd__maan');
const sterren = w.querySelector('.zd__sterren'), zee = w.querySelector('.zd__zee'), glans = w.querySelector('.zd__glans'), duin = w.querySelector('.zd__duin');
const tijd = w.querySelector('.zd__tijd'), wat = w.querySelector('.zd__wat');
const K = [[5, '#0b0f16', '#1b2330'], [6.5, '#2b3550', '#f0a070'], [8, '#8fc3e6', '#e6f1f7'], [13, '#5aa9e0', '#cfe6f5'], [18, '#79b4dc', '#f6d7a8'], [20.5, '#2f3d5c', '#f5803f'], [21.6, '#141b29', '#5a3a2e'], [23.5, '#0a0d13', '#141a24']];
const P = [[0, 'Nog even stil', 'Om 08:00 gaan we open.'], [8, 'Ontbijt aan zee', 'vanaf € 8,50, met vers brood uit Haarlem.'], [11.5, 'Lunch op het terras', 'uitsmijter met drie eieren € 11,50.'], [16, 'Borrel met zicht op zee', 'bittergarnituur € 9,75.'], [19, 'Diner bij zonsondergang', 'de keuken is open tot 21:30.'], [21.5, 'We zijn dicht', 'morgen weer vanaf 08:00.']];
const hex = h => [1, 3, 5].map(i => parseInt(h.slice(i, i + 2), 16));
const mix = (a, b, t) => { const x = hex(a), y = hex(b); return 'rgb(' + x.map((v, i) => Math.round(v + (y[i] - v) * t)).join(',') + ')'; };
const cl = v => v < 0 ? 0 : v > 1 ? 1 : v;
let raf = 0, nu = -1;
function teken() {
raf = 0; const m = vak.scrollHeight - vak.clientHeight, p = m > 0 ? vak.scrollTop / m : 0;
const u = 5 + p * 18.5;
let k = 0; while (k < K.length - 2 && u > K[k + 1][0]) k++;
const f = cl((u - K[k][0]) / (K[k + 1][0] - K[k][0]));
const boven = mix(K[k][1], K[k + 1][1], f), onder = mix(K[k][2], K[k + 1][2], f);
beeld.style.background = 'linear-gradient(' + boven + ',' + onder + ' 66%)';
zee.style.background = 'linear-gradient(' + mix(K[k][1], K[k + 1][1], f) + ',#0a0a0a 220%)';
const op = 6.5, neer = 21.25, s = (u - op) / (neer - op);
const hoog = s > 0 && s < 1 ? Math.sin(Math.PI * s) : 0;
const licht = cl(hoog * 3);
const x = 8 + 84 * cl(s), y = 66 - hoog * 54;
zon.style.transform = 'translate(' + x + 'cqw,' + (s <= 0 || s >= 1 ? 76 : y) + 'cqh)';
zon.style.background = mix('#f5803f', '#ffe7a8', cl(hoog * 2));
glans.style.left = x + '%'; glans.style.opacity = (cl(hoog * 4) * .5).toFixed(2);
sterren.style.opacity = (1 - cl((u - 5.6) / 1.4) + cl((u - 21.3) / 1.2)).toFixed(2);
maan.style.opacity = (u > 21.6 ? cl((u - 21.6) / 1) : u < 6 ? 1 - cl((u - 5.2) / .8) : 0).toFixed(2);
duin.style.fill = mix('#1a1a1a', '#d9c8a2', licht);
const hh = Math.floor(u), mm = Math.floor((u - hh) * 4) * 15;
tijd.textContent = String(hh).padStart(2, '0') + ':' + String(mm).padStart(2, '0');
let i = 0; P.forEach((q, j) => { if (u >= q[0]) i = j; });
if (i !== nu) { nu = i; wat.innerHTML = '<strong>' + P[i][1] + '</strong> <span>' + P[i][2] + '</span>'; }
w.classList.toggle('is-weg', vak.scrollTop > 8);
}
vak.addEventListener('scroll', () => { if (!raf) raf = requestAnimationFrame(teken); }, { passive: true });
teken();
}
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 →