App-tabbalk met glijdende markering New
Bottom tab bar for a mobile web app, here for a physiotherapy practice: an orange bar slides to the active tab, the icon hops up briefly and aria-current marks the page. A badge shows open appointments. Scroll down in the content and the bar slides away, scroll back up and it returns. Left and right arrows move through the tabs. In production you pin the bar with position:fixed and env(safe-area-inset-bottom).
Volgende afspraak
Dinsdag 14 oktober om 08:30 bij Ruben Smit, Fysio Oost in Leiden.
Neem je sportschoenen en een handdoek mee. Parkeren kan gratis achter de praktijk.
Verzetten kan tot 24 uur van tevoren, daarna rekenen we € 39 voor de gemiste afspraak.
Vragen over je oefeningen? Stuur Ruben een bericht, hij antwoordt op werkdagen binnen een dag.
Oefeningen deze week
Brug: 3 keer 12, twee keer per dag.
Kuitstretch tegen de muur: 3 keer 30 seconden per been.
Fietsen op lage weerstand: 15 minuten.
Afspraken
Di 14 okt, 08:30, behandeling knie.
Do 23 okt, 17:15, controle en nieuwe oefeningen.
Berichten
Ruben: Lukt de brug zonder pijn? Dan bouwen we volgende week op naar 15 herhalingen.
Profiel
Lotte Jansen, verzekerd bij Zilveren Kruis. Nog 6 behandelingen vergoed dit jaar.
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.
<!-- App-tabbalk met glijdende markering · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="atm">
<div class="atm__view" tabindex="0" aria-label="Inhoud">
<section class="atm__p is-on" data-p="0"><h3 class="atm__h">Volgende afspraak</h3><p class="atm__t">Dinsdag 14 oktober om 08:30 bij Ruben Smit, Fysio Oost in Leiden.</p><p class="atm__t">Neem je sportschoenen en een handdoek mee. Parkeren kan gratis achter de praktijk.</p><p class="atm__t">Verzetten kan tot 24 uur van tevoren, daarna rekenen we € 39 voor de gemiste afspraak.</p><p class="atm__t">Vragen over je oefeningen? Stuur Ruben een bericht, hij antwoordt op werkdagen binnen een dag.</p></section>
<section class="atm__p" data-p="1"><h3 class="atm__h">Oefeningen deze week</h3><p class="atm__t">Brug: 3 keer 12, twee keer per dag.</p><p class="atm__t">Kuitstretch tegen de muur: 3 keer 30 seconden per been.</p><p class="atm__t">Fietsen op lage weerstand: 15 minuten.</p></section>
<section class="atm__p" data-p="2"><h3 class="atm__h">Afspraken</h3><p class="atm__t">Di 14 okt, 08:30, behandeling knie.</p><p class="atm__t">Do 23 okt, 17:15, controle en nieuwe oefeningen.</p></section>
<section class="atm__p" data-p="3"><h3 class="atm__h">Berichten</h3><p class="atm__t">Ruben: Lukt de brug zonder pijn? Dan bouwen we volgende week op naar 15 herhalingen.</p></section>
<section class="atm__p" data-p="4"><h3 class="atm__h">Profiel</h3><p class="atm__t">Lotte Jansen, verzekerd bij Zilveren Kruis. Nog 6 behandelingen vergoed dit jaar.</p></section>
</div>
<nav class="atm__bar" aria-label="App">
<span class="atm__mark" aria-hidden="true"></span>
<a class="atm__tab" href="#atm-home" aria-current="page"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 11l8-6 8 6v8a1 1 0 0 1-1 1h-4v-6h-6v6H5a1 1 0 0 1-1-1z"/></svg><span>Home</span></a>
<a class="atm__tab" href="#atm-oefeningen"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 10v4M6 8v8M18 8v8M21 10v4M6 12h12"/></svg><span>Oefenen</span></a>
<a class="atm__tab" href="#atm-afspraken"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M4 10h16M9 3v4M15 3v4"/></svg><span>Afspraken</span><b class="atm__badge" aria-hidden="true">2</b><span class="atm__vh">, 2 gepland</span></a>
<a class="atm__tab" href="#atm-berichten"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 6h16v10H9l-5 4z"/></svg><span>Berichten</span></a>
<a class="atm__tab" href="#atm-profiel"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="8" r="4"/><path d="M4 21c1-4 4.5-6 8-6s7 2 8 6"/></svg><span>Profiel</span></a>
</nav>
</div>
</div>/* App-tabbalk met glijdende markering · NedDev · eigen werk. */
.atm{position:absolute;inset:0;background:#fff;color:#0a0a0a;font-family:'Switzer',sans-serif;text-align:left;overflow:hidden}
.atm *,.atm *::before,.atm *::after{box-sizing:border-box}
.atm__view{position:absolute;inset:0;overflow:auto;padding:16px 18px 76px;outline:none;scrollbar-width:thin}
.atm__view:focus-visible{box-shadow:inset 0 0 0 2px #F5480F}
.atm__p{display:none}
.atm__p.is-on{display:block;animation:atmIn .24s ease}
@keyframes atmIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.atm__h{margin:0 0 6px;font:600 18px/1.2 'Switzer',sans-serif;letter-spacing:-.01em}
.atm__t{margin:0 0 8px;font:400 14px/1.45 'Switzer',sans-serif;color:#3a3733;max-width:38em}
.atm__bar{position:absolute;left:0;right:0;bottom:0;display:flex;height:60px;background:#0a0a0a;transition:transform .28s cubic-bezier(.2,.7,.2,1)}
.atm.is-hidden .atm__bar{transform:translateY(100%)}
.atm__mark{position:absolute;top:0;left:0;width:28px;height:3px;border-radius:0 0 3px 3px;background:#F5480F;transform:translateX(var(--x,0));transition:transform .32s cubic-bezier(.3,.7,.2,1)}
.atm__tab{position:relative;flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;color:#b9b5ae;text-decoration:none;font:500 12px/1 'Switzer',sans-serif;outline:none;-webkit-tap-highlight-color:transparent}
.atm__tab svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.atm__tab span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.atm__tab:hover{color:#fff}
.atm__tab[aria-current="page"]{color:#fff;font-weight:600}
.atm__tab[aria-current="page"] svg{stroke:#F5480F}
.atm__tab.is-pop svg{animation:atmPop .34s cubic-bezier(.3,.7,.3,1.4)}
@keyframes atmPop{40%{transform:translateY(-4px) scale(1.08)}100%{transform:none}}
.atm__tab:focus-visible{box-shadow:inset 0 0 0 2px #F5480F}
.atm__vh{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.atm__badge{position:absolute;top:7px;left:calc(50% + 6px);min-width:18px;height:18px;padding:0 4px;border-radius:9px;background:#F5480F;color:#0a0a0a;font:700 12px/18px 'Switzer',sans-serif;text-align:center}
@media (max-width:420px){.atm__tab{font-size:12px}.atm__tab span{max-width:62px}}
@media (prefers-reduced-motion:reduce){.atm__bar,.atm__mark{transition:none}.atm__p.is-on,.atm__tab.is-pop svg{animation:none}}// App-tabbalk met glijdende markering · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.atm');if(!w)return;
var tabs=[].slice.call(w.querySelectorAll('.atm__tab')),ps=[].slice.call(w.querySelectorAll('.atm__p')),mark=w.querySelector('.atm__mark'),view=w.querySelector('.atm__view');
function place(){var t=w.querySelector('.atm__tab[aria-current="page"]');if(!t)return;mark.style.setProperty('--x',(t.offsetLeft+t.offsetWidth/2-14)+'px');}
function act(i,focus){tabs.forEach(function(t,k){if(k===i)t.setAttribute('aria-current','page');else t.removeAttribute('aria-current');});
ps.forEach(function(p,k){p.classList.toggle('is-on',k===i);});var t=tabs[i];t.classList.remove('is-pop');void t.offsetWidth;t.classList.add('is-pop');
view.scrollTop=0;w.classList.remove('is-hidden');place();if(focus)t.focus();}
tabs.forEach(function(t,i){t.addEventListener('click',function(e){e.preventDefault();act(i);});
t.addEventListener('keydown',function(e){var j=null;if(e.key==='ArrowRight')j=(i+1)%tabs.length;else if(e.key==='ArrowLeft')j=(i-1+tabs.length)%tabs.length;if(j!==null){e.preventDefault();tabs[j].focus();}});});
var last=0;view.addEventListener('scroll',function(){var y=view.scrollTop,max=view.scrollHeight-view.clientHeight;if(y>last+6&&y>24)w.classList.add('is-hidden');else if(y<last-6||y<=4||y>=max-2&&y<last)w.classList.remove('is-hidden');last=y;},{passive:true});
w.querySelector('.atm__bar').addEventListener('focusin',function(){w.classList.remove('is-hidden');});
if('ResizeObserver' in window)new ResizeObserver(place).observe(w);
place();
}
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 →