Eine grundlegende Übersicht darüber, wie Sie eine Tab-Komponente erstellen, die denen in iOS- und Android-Apps ähnelt.
In diesem Beitrag möchte ich meine Überlegungen zur Entwicklung einer Tab-Komponente für das Web teilen, die responsiv ist, mehrere Geräteeingaben unterstützt und in allen Browsern funktioniert. Demo ansehen
Wenn du lieber ein Video ansehen möchtest, findest du hier eine YouTube-Version dieses Beitrags:
Übersicht
Tabs sind eine gängige Komponente von Designsystemen, können aber viele Formen annehmen. Zuerst gab es Desktop-Tabs, die auf dem <frame>
-Element basierten. Jetzt haben wir flüssige mobile Komponenten, die Inhalte basierend auf physikalischen Eigenschaften animieren.
Sie alle versuchen, Platz zu sparen.
Die Grundlagen der Nutzererfahrung mit Tabs sind heute ein Schaltflächen-Navigationsbereich, mit dem die Sichtbarkeit von Inhalten in einem Anzeigefeld umgeschaltet wird. Viele verschiedene Inhaltsbereiche teilen sich denselben Bereich, werden aber je nach der in der Navigation ausgewählten Schaltfläche bedingt präsentiert.

Web-Taktiken
Insgesamt war es dank einiger wichtiger Webplattformfunktionen recht einfach, diese Komponente zu erstellen:
scroll-snap-points
für elegante Wisch- und Tastaturinteraktionen mit geeigneten Scroll-Stopp-Positionen- Deeplinks über URL-Hashes für die Unterstützung von In-Page-Scrollankern und Freigabe im Browser
- Screenreader-Unterstützung mit
<a>
- undid="#hash"
-Element-Markup prefers-reduced-motion
zum Aktivieren von Überblendungseffekten und sofortigem Scrollen auf der Seite- Die
@scroll-timeline
-Webfunktion für dynamisches Unterstreichen und Ändern der Farbe des ausgewählten Tabs ist noch in der Entwicklung.
Der HTML-Code
Die UX ist im Grunde so: Sie klicken auf einen Link, die URL gibt den verschachtelten Seitenstatus an und der Inhaltsbereich wird aktualisiert, wenn der Browser zum entsprechenden Element scrollt.
Es gibt einige strukturelle Inhaltselemente: Links und :target
. Wir benötigen eine Liste mit Links, für die sich ein <nav>
anbietet, und eine Liste mit <article>
-Elementen, für die sich ein <section>
anbietet. Jeder Link-Hash entspricht einem Abschnitt, sodass der Browser über die Verankerung scrollen kann.
Wenn Sie beispielsweise in Chrome 89 auf einen Link klicken, wird der :target
-Artikel automatisch fokussiert. Dazu ist kein JS erforderlich. Der Nutzer kann dann wie gewohnt mit seinem Eingabegerät durch die Artikelinhalte scrollen. Es handelt sich um kostenlose Inhalte, wie im Markup angegeben.
Ich habe das folgende Markup verwendet, um die Tabs zu organisieren:
<snap-tabs>
<header>
<nav>
<a></a>
<a></a>
<a></a>
<a></a>
</nav>
</header>
<section>
<article></article>
<article></article>
<article></article>
<article></article>
</section>
</snap-tabs>
So kann ich Verbindungen zwischen den Elementen <a>
und <article>
mit den Attributen href
und id
herstellen:
<snap-tabs>
<header>
<nav>
<a href="#responsive"></a>
<a href="#accessible"></a>
<a href="#overscroll"></a>
<a href="#more"></a>
</nav>
</header>
<section>
<article id="responsive"></article>
<article id="accessible"></article>
<article id="overscroll"></article>
<article id="more"></article>
</section>
</snap-tabs>
Als Nächstes habe ich die Artikel mit unterschiedlich viel Blindtext und die Links mit unterschiedlich langen Titeln und Bildern gefüllt. Sobald wir Inhalte haben, können wir mit dem Layout beginnen.
Scrollbare Layouts
Diese Komponente enthält drei verschiedene Arten von Scrollbereichen:
- Die Navigation (rosa) ist horizontal scrollbar.
- Der Inhaltsbereich (blau) ist horizontal scrollbar.
- Jedes Artikelelement (grün) ist vertikal scrollbar.

Es gibt zwei verschiedene Arten von Elementen, die beim Scrollen eine Rolle spielen:
- Fenster
Ein Feld mit definierten Abmessungen, das den Stil der Eigenschaftoverflow
hat. - Übergroße Oberfläche
In diesem Layout sind es die Listencontainer: Navigationslinks, Abschnittsartikel und Artikelinhalte.
Layout: <snap-tabs>
Als Layout der obersten Ebene habe ich „flex“ (Flexbox) ausgewählt. Ich habe die Richtung auf column
festgelegt, damit die Überschrift und der Abschnitt vertikal angeordnet werden. Das ist unser erstes Scrollfenster. Alles, was über den Rand hinausgeht, wird ausgeblendet. Die Kopfzeile und der Abschnitt werden bald als einzelne Zonen mit Overscroll-Funktion angezeigt.
<snap-tabs> <header></header> <section></section> </snap-tabs>
snap-tabs { display: flex; flex-direction: column; /* establish primary containing box */ overflow: hidden; position: relative; & > section { /* be pushy about consuming all space */ block-size: 100%; } & > header { /* defend againstneeding 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }
Zurück zum farbenfrohen Diagramm mit drei Scrollbereichen:
<header>
ist jetzt als (pink)-Scrollcontainer vorbereitet.<section>
ist als blauer Scrollcontainer vorgesehen.
Die Frames, die ich unten mit VisBug hervorgehoben habe, zeigen die Fenster, die durch die Scrollcontainer erstellt wurden.

Layout mit Tabs <header>
Das nächste Layout ist fast identisch: Ich verwende „flex“, um eine vertikale Anordnung zu erstellen.
<snap-tabs> <header> <nav></nav> <span class="snap-indicator"></span> </header> <section></section> </snap-tabs>
header { display: flex; flex-direction: column; }
Der .snap-indicator
sollte horizontal mit der Linkgruppe mitwandern. Dieses Header-Layout hilft dabei. Hier sind keine absolut positionierten Elemente vorhanden.

Als Nächstes die Scrollstile. Es hat sich herausgestellt, dass wir die Scrollstile für die beiden horizontalen Scrollbereiche (Header und Abschnitt) gemeinsam nutzen können. Deshalb habe ich die Utility-Klasse .scroll-snap-x
erstellt.
.scroll-snap-x {
/* browser decide if x is ok to scroll and show bars on, y hidden */
overflow: auto hidden;
/* prevent scroll chaining on x scroll */
overscroll-behavior-x: contain;
/* scrolling should snap children on x */
scroll-snap-type: x mandatory;
@media (hover: none) {
scrollbar-width: none;
&::-webkit-scrollbar {
width: 0;
height: 0;
}
}
}
Jedes benötigt einen Überlauf auf der X-Achse, Scroll-Containment, um Overscroll zu verhindern, ausgeblendete Scrollbars für Touchgeräte und schließlich Scroll-Snap, um Inhaltsbereiche zu fixieren. Die Reihenfolge der Tastaturtabulatoren ist zugänglich und alle Interaktionen führen den Fokus auf natürliche Weise. Scroll-Snap-Container erhalten außerdem eine ansprechende Karussell-Interaktion über die Tastatur.
Layout der Tab-Überschrift <nav>
Die Navigationslinks müssen in einer Zeile ohne Zeilenumbrüche angeordnet sein, vertikal zentriert und jedes Linkelement muss am Scroll-Snap-Container einrasten. Swift-Arbeit für CSS 2021!
<nav> <a></a> <a></a> <a></a> <a></a> </nav>
nav { display: flex; & a { scroll-snap-align: start; display: inline-flex; align-items: center; white-space: nowrap; } }
Jeder Link wird automatisch formatiert und in der richtigen Größe dargestellt. Im Navigationslayout müssen also nur Richtung und Fluss angegeben werden. Durch die unterschiedlichen Breiten der Navigationselemente wird der Übergang zwischen Tabs interessanter, da die Breite des Indikators an das neue Ziel angepasst wird. Je nachdem, wie viele Elemente sich darin befinden, rendert der Browser eine Scrollleiste oder nicht.

Layout mit Tabs <section>
Dieser Abschnitt ist ein Flex-Element und muss den größten Teil des verfügbaren Platzes einnehmen. Außerdem müssen Spalten für die Artikel erstellt werden. Auch hier gilt: Vielen Dank für die schnelle Arbeit für CSS 2021! Mit block-size: 100%
wird dieses Element so gestreckt, dass es den übergeordneten Container so weit wie möglich ausfüllt. Für das eigene Layout werden dann eine Reihe von Spalten erstellt, die 100%
der Breite des übergeordneten Containers entsprechen. Prozentsätze sind hier ideal, da wir starke Einschränkungen für das übergeordnete Element festgelegt haben.
<section> <article></article> <article></article> <article></article> <article></article> </section>
section { block-size: 100%; display: grid; grid-auto-flow: column; grid-auto-columns: 100%; }
Es ist, als würden wir sagen: „Vertikal so weit wie möglich erweitern, aufdringlich“ (denken Sie an den Header, den wir auf flex-shrink: 0
festgelegt haben: Er ist eine Abwehr gegen diese Erweiterung), wodurch die Zeilenhöhe für eine Reihe von Spalten mit voller Höhe festgelegt wird. Der Stil auto-flow
weist das Raster an, untergeordnete Elemente immer horizontal anzuordnen, ohne Umbruch. Das ist genau das, was wir möchten: das übergeordnete Fenster überlaufen.

Manchmal ist es schwierig, das zu verstehen. Dieses Abschnittselement passt in ein Feld, hat aber auch eine Reihe von Feldern erstellt. Wir hoffen, dass die Visualisierungen und Erklärungen hilfreich sind.
Layout mit Tabs <article>
Der Nutzer sollte den Artikelinhalt scrollen können und die Scrollleisten sollten nur bei Überlauf angezeigt werden. Diese Artikelelemente sind an einer übersichtlichen Position. Sie sind gleichzeitig ein Scroll-Parent und ein Scroll-Child. Der Browser übernimmt hier einige schwierige Touch-, Maus- und Tastaturinteraktionen für uns.
<article> <h2></h2> <p></p> <p></p> <h2></h2> <p></p> <p></p> ... </article>
article { scroll-snap-align: start; overflow-y: auto; overscroll-behavior-y: contain; }
Ich habe mich dafür entschieden, dass die Artikel im übergeordneten Scroller einrasten. Mir gefällt, wie die Navigationslinkelemente und die Artikelelemente am Inline-Start ihrer jeweiligen Scroll-Container einrasten. Es sieht aus und fühlt sich an wie eine harmonische Beziehung.

Der Artikel ist ein untergeordnetes Element des Grids und seine Größe ist auf den Viewportbereich festgelegt, für den wir die Scroll-UX bereitstellen möchten. Das bedeutet, dass ich hier keine Stilangaben für Höhe oder Breite benötige. Ich muss nur definieren, wie der Inhalt überläuft. Ich habe „overflow-y“ auf „auto“ gesetzt und dann die Scrollinteraktionen mit der praktischen Eigenschaft „overscroll-behavior“ abgefangen.
3 Scrollbereiche – Zusammenfassung
Unten habe ich in meinen Systemeinstellungen „Scrollleisten immer anzeigen“ ausgewählt. Ich denke, es ist doppelt wichtig, dass das Layout mit dieser Einstellung funktioniert, da ich das Layout und die Scroll-Orchestrierung überprüfen muss.

Ich denke, dass die Scrollleiste in dieser Komponente deutlich zeigt, wo sich die Scrollbereiche befinden, in welche Richtung sie unterstützt werden und wie sie miteinander interagieren. Berücksichtigen Sie, dass jeder dieser Scrollfenster-Frames auch ein Flex- oder Grid-Übergeordnetes Element für ein Layout ist.
Mit den Entwicklertools lässt sich das visualisieren:

Die Scroll-Layouts sind vollständig: Sie lassen sich einrasten, sind deeplinkfähig und können über die Tastatur aufgerufen werden. Solide Grundlage für UX-Verbesserungen, Stil und Freude.
Funktionshighlight
Angepasste untergeordnete Elemente behalten ihre gesperrte Position während der Größenänderung bei. Das bedeutet, dass JavaScript beim Drehen des Geräts oder Ändern der Browsergröße nichts in den sichtbaren Bereich bringen muss. Probieren Sie es in den Chromium-Entwicklertools im Gerätemodus aus, indem Sie einen anderen Modus als Responsiv auswählen und dann die Größe des Geräte-Frames ändern. Das Element bleibt im Blickfeld und ist mit seinem Inhalt verknüpft. Diese Funktion ist verfügbar, seit Chromium die Implementierung an die Spezifikation angepasst hat. Hier finden Sie einen Blogpost dazu.
Animation
Ziel der Animationen ist es, Interaktionen mit UI-Feedback zu verknüpfen. So können Nutzer alle Inhalte (hoffentlich) nahtlos entdecken. Ich werde Bewegungen gezielt und bedingt hinzufügen. Nutzer können jetzt ihre Einstellungen für Bewegungen in ihrem Betriebssystem festlegen. Ich freue mich sehr, wenn ich in meinen Benutzeroberflächen auf diese Einstellungen reagieren kann.
Ich verknüpfe eine Tab-Unterstreichung mit der Scrollposition des Artikels. Durch das Einrasten wird nicht nur eine gute Ausrichtung erreicht, sondern auch der Start und das Ende einer Animation werden verankert.
So bleibt die <nav>
, die wie eine Mini-Karte funktioniert, mit dem Inhalt verbunden.
Wir prüfen die Bewegungseinstellung des Nutzers sowohl über CSS als auch über JS. Es gibt einige Orte, an denen Sie besonders aufmerksam sein sollten.
Scrollverhalten
Es besteht die Möglichkeit, das Bewegungsverhalten von :target
und element.scrollIntoView()
zu verbessern. Standardmäßig erfolgt die Aktualisierung sofort. Der Browser legt nur die Scrollposition fest. Was aber, wenn wir zu dieser Scrollposition wechseln möchten, anstatt dort zu blinken?
@media (prefers-reduced-motion: no-preference) {
.scroll-snap-x {
scroll-behavior: smooth;
}
}
Da wir hier Bewegung einführen, die der Nutzer nicht steuert (z. B. Scrollen), wenden wir diesen Stil nur an, wenn der Nutzer in seinem Betriebssystem keine Präferenz für reduzierte Bewegung hat. So wird die Scrollbewegung nur für Nutzer eingeführt, die damit einverstanden sind.
Tab-Anzeige
Mit dieser Animation soll der Indikator mit dem Status der Inhalte in Verbindung gebracht werden. Ich habe mich für ein Farb-Crossfade für border-bottom
-Stile für Nutzer entschieden, die eine reduzierte Bewegung bevorzugen, und für eine Animation mit Scroll-Linked-Sliding und Farbüberblendung für Nutzer, die mit Bewegung einverstanden sind.
In den Chromium-Entwicklertools kann ich die Einstellung umschalten und die beiden verschiedenen Übergangsstile demonstrieren. Es hat mir viel Spaß gemacht, das zu entwickeln.
@media (prefers-reduced-motion: reduce) {
snap-tabs > header a {
border-block-end: var(--indicator-size) solid hsl(var(--accent) / 0%);
transition: color .7s ease, border-color .5s ease;
&:is(:target,:active,[active]) {
color: var(--text-active-color);
border-block-end-color: hsl(var(--accent));
}
}
snap-tabs .snap-indicator {
visibility: hidden;
}
}
Ich blende die .snap-indicator
aus, wenn der Nutzer reduzierte Bewegungen bevorzugt, da ich sie nicht mehr benötige. Dann ersetze ich es durch border-block-end
-Stile und ein transition
. Beachten Sie auch, dass das aktive Navigationselement nicht nur eine Markenunterstreichung hat, sondern auch die Textfarbe dunkler ist. Das aktive Element hat einen höheren Textfarbkontrast und einen hellen Unterlichtakzent.
Mit nur wenigen zusätzlichen Zeilen CSS können Sie dafür sorgen, dass sich Nutzer wahrgenommen fühlen, da Sie ihre Einstellungen für Bewegungen berücksichtigen. Ich liebe das.
@scroll-timeline
Im vorherigen Abschnitt habe ich gezeigt, wie ich die Crossfade-Stile für reduzierte Bewegung verarbeite. In diesem Abschnitt zeige ich, wie ich den Indikator und einen Scrollbereich verknüpft habe. Als Nächstes folgen einige experimentelle Funktionen. Ich hoffe, du bist genauso gespannt wie ich.
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
);
Zuerst prüfe ich die Bewegungseinstellung des Nutzers über JavaScript. Wenn das Ergebnis false
ist, d. h. der Nutzer bevorzugt reduzierte Bewegungen, werden keine der Scroll-Linking-Bewegungseffekte ausgeführt.
if (motionOK) {
// motion based animation code
}
Zum Zeitpunkt der Erstellung dieses Dokuments wird @scroll-timeline
von keinem Browser unterstützt. Es handelt sich um eine Entwurfsspezifikation mit experimentellen Implementierungen. Es gibt jedoch ein Polyfill, das ich in dieser Demo verwende.
ScrollTimeline
Sowohl mit CSS als auch mit JavaScript lassen sich Scroll-Zeitachsen erstellen. Ich habe mich für JavaScript entschieden, damit ich Live-Elementmessungen in der Animation verwenden kann.
const sectionScrollTimeline = new ScrollTimeline({
scrollSource: tabsection, // snap-tabs > section
orientation: 'inline', // scroll in the direction letters flow
fill: 'both', // bi-directional linking
});
Ich möchte, dass ein Element der Scrollposition eines anderen folgt. Mit ScrollTimeline
definiere ich den Treiber des Scroll-Links, also scrollSource
.
Normalerweise wird eine Animation im Web mit einem globalen Zeitrahmen-Tick ausgeführt. Mit einem benutzerdefinierten sectionScrollTimeline
im Speicher kann ich das jedoch ändern.
tabindicator.animate({
transform: ...,
width: ...,
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
Bevor ich auf die Keyframes der Animation eingehe, möchte ich darauf hinweisen, dass der Follower des Scrollens (tabindicator
) basierend auf einer benutzerdefinierten Zeitachse, dem Scrollen unseres Abschnitts, animiert wird. Damit ist die Verknüpfung abgeschlossen, aber es fehlt noch die letzte Zutat: statusbezogene Punkte, zwischen denen animiert werden soll, auch bekannt als Keyframes.
Dynamische Keyframes
Es gibt eine sehr leistungsstarke rein deklarative CSS-Methode zum Animieren mit @scroll-timeline
, aber die Animation, die ich gewählt habe, war zu dynamisch. Es gibt keine Möglichkeit, zwischen auto
-Breiten zu wechseln, und es gibt keine Möglichkeit, dynamisch eine Anzahl von Keyframes basierend auf der Länge der untergeordneten Elemente zu erstellen.
JavaScript weiß jedoch, wie diese Informationen abgerufen werden können. Wir iterieren also selbst über die untergeordneten Elemente und rufen die berechneten Werte zur Laufzeit ab:
tabindicator.animate({
transform: [...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`),
width: [...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
Für jede tabnavitem
-Variable wird die offsetLeft
-Position zerlegt und ein String zurückgegeben, der sie als translateX
-Wert verwendet. Dadurch werden vier Keyframes für die Transformation für die Animation erstellt. Das Gleiche geschieht mit der Breite. Für jede wird gefragt, wie ihre dynamische Breite ist, und dann wird sie als Keyframe-Wert verwendet.
Hier sehen Sie ein Beispiel für die Ausgabe basierend auf meinen Schriftarten und Browsereinstellungen:
TranslateX-Keyframes:
[...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`)
// results in 4 array items, which represent 4 keyframe states
// ["translateX(0px)", "translateX(121px)", "translateX(238px)", "translateX(464px)"]
Keyframes für die Breite:
[...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
// results in 4 array items, which represent 4 keyframe states
// ["121px", "117px", "226px", "67px"]
Zusammenfassend lässt sich sagen, dass der Tab-Indikator jetzt je nach Scroll-Snap-Position des Abschnitt-Scrollers über vier Keyframes animiert wird. Die Einrastpunkte sorgen für eine klare Abgrenzung zwischen unseren Keyframes und tragen wirklich zum synchronisierten Gefühl der Animation bei.

Der Nutzer steuert die Animation durch seine Interaktion. Die Breite und Position des Indikators ändern sich von einem Abschnitt zum nächsten und passen sich perfekt an das Scrollen an.
Vielleicht ist es Ihnen nicht aufgefallen, aber ich bin sehr stolz auf den Farbwechsel, wenn das hervorgehobene Navigationselement ausgewählt wird.
Das nicht ausgewählte helle Grau wirkt noch weiter in den Hintergrund gedrängt, wenn das hervorgehobene Element einen höheren Kontrast hat. Es ist üblich, die Farbe für Text zu ändern, z. B. beim Hovern und bei der Auswahl. Es ist jedoch eine Stufe höher, die Farbe beim Scrollen zu ändern, synchronisiert mit dem Unterstreichungsindikator.
So bin ich vorgegangen:
tabnavitems.forEach(navitem => {
navitem.animate({
color: [...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
});
Jeder Tab-Navigationslink benötigt diese neue Farbanimation, die denselben Scroll-Zeitachsen wie der Unterstrich-Indikator folgt. Ich verwende denselben Zeitachsentyp wie zuvor, da er bei jedem Scrollen ein Tick-Ereignis ausgibt. Dieses Tick-Ereignis kann für jede beliebige Art von Animation verwendet werden. Wie zuvor erstelle ich vier Keyframes in der Schleife und gebe Farben zurück.
[...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
// results in 4 array items, which represent 4 keyframe states
// [
"var(--text-active-color)",
"var(--text-color)",
"var(--text-color)",
"var(--text-color)",
]
Der Keyframe mit der Farbe var(--text-active-color)
hebt den Link hervor. Ansonsten wird eine Standardtextfarbe verwendet. Die verschachtelte Schleife macht es relativ einfach, da die äußere Schleife jedes Navigationselement und die innere Schleife die persönlichen Keyframes jedes Navigationselements ist. Ich prüfe, ob das Element der äußeren Schleife mit dem der inneren Schleife übereinstimmt, und verwende das, um zu ermitteln, wann es ausgewählt ist.
Mir hat es viel Spaß gemacht, diesen Beitrag zu schreiben. Sehr.
Noch mehr JavaScript-Verbesserungen
Es ist wichtig zu wissen, dass das, was ich Ihnen hier zeige, ohne JavaScript funktioniert. Sehen wir uns an, wie wir die Funktion verbessern können, wenn JavaScript verfügbar ist.
Deeplinks
Deeplinks sind eher ein Begriff für Mobilgeräte, aber ich denke, dass die Intention des Deeplinks hier mit Tabs erfüllt wird, da Sie eine URL direkt für den Inhalt eines Tabs freigeben können. Der Browser navigiert auf der Seite zur ID, die im URL-Hash übereinstimmt. Ich habe festgestellt, dass der onload
-Handler den Effekt plattformübergreifend erzielt.
window.onload = () => {
if (location.hash) {
tabsection.scrollLeft = document
.querySelector(location.hash)
.offsetLeft;
}
}
Synchronisierung des Scroll-Endes
Unsere Nutzer klicken oder verwenden nicht immer eine Tastatur. Manchmal scrollen sie einfach kostenlos, was sie auch tun sollten. Wenn der Abschnittsscroller aufhört zu scrollen, muss die Stelle, an der er landet, mit der oberen Navigationsleiste übereinstimmen.
So warte ich auf das Ende des Scrollens:
js
tabsection.addEventListener('scroll', () => {
clearTimeout(tabsection.scrollEndTimer);
tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100);
});
Wenn in den Abschnitten gescrollt wird, löschen Sie das Zeitlimit für den Abschnitt, falls vorhanden, und starten Sie ein neues. Wenn nicht mehr gescrollt wird, darf das Zeitlimit nicht gelöscht werden. Das Ereignis muss 100 ms nach dem Ende des Scrollens ausgelöst werden. Wenn das Ereignis ausgelöst wird, rufen Sie die Funktion auf, die ermittelt, wo der Nutzer aufgehört hat.
const determineActiveTabSection = () => {
const i = tabsection.scrollLeft / tabsection.clientWidth;
const matchingNavItem = tabnavitems[i];
matchingNavItem && setActiveTab(matchingNavItem);
};
Wenn der Scrollvorgang eingerastet ist, sollte die Division der aktuellen Scrollposition durch die Breite des Scrollbereichs eine Ganzzahl und keine Dezimalzahl ergeben. Ich versuche dann, über diesen berechneten Index ein Navitem aus unserem Cache abzurufen. Wenn etwas gefunden wird, sende ich die Übereinstimmung, um sie als aktiv festzulegen.
const setActiveTab = tabbtn => {
tabnav
.querySelector(':scope a[active]')
.removeAttribute('active');
tabbtn.setAttribute('active', '');
tabbtn.scrollIntoView();
};
Wenn Sie den aktiven Tab festlegen, wird zuerst der aktuell aktive Tab deaktiviert und dann dem eingehenden Navigationsmenüpunkt das Attribut für den aktiven Status zugewiesen. Der Aufruf von scrollIntoView()
hat eine interessante Interaktion mit CSS, die es wert ist, erwähnt zu werden.
.scroll-snap-x {
overflow: auto hidden;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
@media (prefers-reduced-motion: no-preference) {
scroll-behavior: smooth;
}
}
Im CSS für das horizontale Scroll-Snap-Utility haben wir eine Medienabfrage eingebettet, die smooth
-Scrolling anwendet, wenn der Nutzer bewegungstolerant ist. Mit JavaScript können Elemente beliebig in den sichtbaren Bereich gescrollt werden, während CSS die Nutzerfreundlichkeit deklarativ verwalten kann.
Manchmal sind sie ein wirklich tolles Team.
Fazit
Jetzt wissen Sie, wie ich es gemacht habe. Wie würden Sie es machen? Das ist eine interessante Komponentenarchitektur. Wer erstellt die erste Version mit Slots in seinem bevorzugten Framework? 🙂
Wir möchten unsere Ansätze diversifizieren und alle Möglichkeiten kennenlernen, die das Web bietet. Erstelle einen Glitch, schreib mir auf Twitter deine Version und ich füge sie unten im Bereich Community-Remixe hinzu.
Community-Remixe
- @devnook, @rob_dodson und @DasSurma mit Web Components: Artikel.
- @jhvanderschee mit Schaltflächen: Codepen.