Balken groeien op scroll (CSS animation-timeline) New
A savings overview in which each bar grows as its row scrolls into view, entirely in CSS with animation-timeline: view() and animation-range; the header gains a shadow via scroll(nearest). Browsers without support get the same through a small IntersectionObserver, with reduced motion the bars are full at once. For worked examples, comparisons and annual reports.
Wat levert verduurzamen op?
Tussenwoning uit 1965 in Breda, besparing per jaar
- Spouwmuurisolatie€ 480
- Zonnepanelen, 8 stuks€ 620
- Dakisolatie€ 390
- HR++ glas€ 260
- Vloerisolatie€ 210
- Kierdichting€ 95
Samen € 2.055 per jaar. Bedragen bij de energieprijs van oktober 2026.
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.
<!-- Balken groeien op scroll (CSS animation-timeline) · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="stb">
<div class="stb__vp" tabindex="0" aria-label="Besparing per maatregel, scroll voor meer">
<div class="stb__kop"><h3 class="stb__t">Wat levert verduurzamen op?</h3><p class="stb__w">Tussenwoning uit 1965 in Breda, besparing per jaar</p></div>
<ul class="stb__lijst">
<li class="stb__r" style="--v:.77"><span class="stb__naam">Spouwmuurisolatie</span><span class="stb__bedrag">€ 480</span><span class="stb__balk"><i></i></span></li>
<li class="stb__r" style="--v:1"><span class="stb__naam">Zonnepanelen, 8 stuks</span><span class="stb__bedrag">€ 620</span><span class="stb__balk"><i></i></span></li>
<li class="stb__r" style="--v:.63"><span class="stb__naam">Dakisolatie</span><span class="stb__bedrag">€ 390</span><span class="stb__balk"><i></i></span></li>
<li class="stb__r" style="--v:.42"><span class="stb__naam">HR++ glas</span><span class="stb__bedrag">€ 260</span><span class="stb__balk"><i></i></span></li>
<li class="stb__r" style="--v:.34"><span class="stb__naam">Vloerisolatie</span><span class="stb__bedrag">€ 210</span><span class="stb__balk"><i></i></span></li>
<li class="stb__r" style="--v:.15"><span class="stb__naam">Kierdichting</span><span class="stb__bedrag">€ 95</span><span class="stb__balk"><i></i></span></li>
</ul>
<p class="stb__voet">Samen € 2.055 per jaar. Bedragen bij de energieprijs van oktober 2026.</p>
</div>
</div>
</div>/* Balken groeien op scroll (CSS animation-timeline) · NedDev · eigen werk. */
.stb{position:absolute;inset:0;padding:8px;font-family:'Switzer',system-ui,sans-serif;color:#0a0a0a;background:#f4f3f1;text-align:left}
.stb *{box-sizing:border-box}
.stb__vp{width:100%;height:100%;overflow-y:auto;overscroll-behavior:contain;background:#fff;border:1px solid rgba(10,10,10,.14);border-radius:8px;scrollbar-width:thin;scrollbar-color:#0a0a0a transparent}
.stb__vp:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.stb__kop{position:sticky;top:0;z-index:1;padding:10px 14px 8px;background:#fff;border-bottom:1px solid transparent}
.stb__t{margin:0;font-size:15px;font-weight:700;letter-spacing:-.01em}
.stb__w{margin:2px 0 0;font-size:12px;color:#4a4a4a}
.stb__lijst{list-style:none;margin:0;padding:4px 14px 0}
.stb__r{display:grid;grid-template-columns:1fr auto;gap:3px 10px;padding:9px 0}
.stb__naam{font-size:13px;font-weight:500}
.stb__bedrag{font-size:13px;font-weight:700;font-variant-numeric:tabular-nums}
.stb__balk{grid-column:1/-1;height:8px;background:#efedea;border-radius:4px;overflow:hidden}
.stb__balk i{display:block;height:100%;width:calc(var(--v) * 100%);background:#F5480F;border-radius:4px;transform-origin:0 50%}
.stb__voet{margin:6px 14px 14px;font-size:12px;line-height:1.4;color:#4a4a4a}
@supports (animation-timeline:view()){
.stb__balk i{animation:stbGroei linear both;animation-timeline:view();animation-range:entry 10% cover 42%}
.stb__bedrag{animation:stbToon linear both;animation-timeline:view();animation-range:entry 10% cover 42%}
.stb__kop{animation:stbSchaduw linear both;animation-timeline:scroll(nearest);animation-range:0 40px}
}
@keyframes stbGroei{from{transform:scaleX(0)}}
@keyframes stbToon{from{opacity:.25}}
@keyframes stbSchaduw{to{border-bottom-color:rgba(10,10,10,.14);box-shadow:0 8px 12px -10px rgba(10,10,10,.4)}}
.stb.is-terugval .stb__balk i{transform:scaleX(0);transition:transform .8s cubic-bezier(.2,.7,.2,1)}
.stb.is-terugval .stb__r.is-in .stb__balk i{transform:none}
.stb.is-terugval .stb__kop.is-schaduw{border-bottom-color:rgba(10,10,10,.14);box-shadow:0 8px 12px -10px rgba(10,10,10,.4)}
@media (prefers-reduced-motion:reduce){.stb__balk i,.stb__bedrag,.stb.is-terugval .stb__balk i{animation:none!important;transform:none!important;opacity:1;transition:none}}// Balken groeien op scroll (CSS animation-timeline) · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w = root.querySelector('.stb');
if (window.CSS && CSS.supports && CSS.supports('animation-timeline', 'view()')) return;
if (matchMedia('(prefers-reduced-motion: reduce)').matches || !('IntersectionObserver' in window)) return;
var vp = w.querySelector('.stb__vp'), kop = w.querySelector('.stb__kop');
w.classList.add('is-terugval');
var io = new IntersectionObserver(function (es) { es.forEach(function (e) { if (e.isIntersecting) { e.target.classList.add('is-in'); io.unobserve(e.target); } }); }, { root: vp, threshold: .6 });
[].forEach.call(w.querySelectorAll('.stb__r'), function (r) { io.observe(r); });
vp.addEventListener('scroll', function () { kop.classList.toggle('is-schaduw', vp.scrollTop > 4); }, { passive: true });
}
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 →