Creazione di un componente Schede

Una panoramica di base sulla creazione di un componente delle schede simile a quelli presenti nelle app per iOS e Android.

In questo post vorrei condividere pensare alla creazione di un componente Schede per il web che sia reattivo, supporti più input da dispositivi e funzioni su tutti i browser. Prova la demo.

Demo

Se preferisci i video, ecco una versione di YouTube di questo post:

Panoramica

Le schede sono un componente comune dei sistemi di progettazione, ma possono assumere molte forme. Prima c'erano le schede desktop basate sull'elemento <frame>, mentre ora abbiamo componenti mobili pesanti che animano i contenuti in base alle proprietà fisiche. Cercano tutti di fare la stessa cosa: risparmiare spazio.

Oggi l'essenziale di un'esperienza utente nelle schede è un'area di navigazione con pulsanti, che attiva/disattiva la visibilità dei contenuti in un frame di visualizzazione. Molte aree di contenuti diverse condividono lo stesso spazio, ma sono presentate in modo condizionale in base al pulsante selezionato nella navigazione.

il collage è piuttosto caotico a causa dell&#39;enorme varietà di stili che il web ha applicato al concetto di componente.
Un collage di stili di web design dei componenti delle schede degli ultimi 10 anni

Tattiche web

Nel complesso, ho trovato questo componente piuttosto semplice da creare, grazie ad alcune funzionalità fondamentali della piattaforma web:

  • scroll-snap-points per interazioni eleganti con scorrimento e tastiera con posizioni di interruzione di scorrimento appropriate
  • Link diretti tramite hash URL per il supporto della condivisione e dell'ancoraggio di scorrimento in-page gestito dal browser
  • Supporto per screen reader con markup degli elementi <a> e id="#hash"
  • prefers-reduced-motion per abilitare le transizioni a dissolvenza incrociata e lo scorrimento istantaneo nella pagina.
  • La funzionalità web @scroll-timeline in versione bozza per sottolineare e cambiare il colore della scheda selezionata in modo dinamico

Il codice HTML

Essenzialmente, l'esperienza utente è: fare clic su un link, fare in modo che l'URL rappresenti lo stato della pagina nidificata e vedere l'aggiornamento dell'area dei contenuti mentre il browser scorre fino all'elemento corrispondente.

Ci sono alcuni membri del contenuto strutturale: link e :target. Abbiamo bisogno di un elenco di link, per i quali è ideale un <nav>, e di un elenco di elementi <article>, per cui un <section> è ideale. Ogni hash link corrisponderà a una sezione, consentendo al browser di scorrere gli elementi tramite l'ancoraggio.

Viene fatto clic su un pulsante Link, facendo scorrere i contenuti in evidenza

Ad esempio, se fai clic su un link, l'articolo :target viene impostato automaticamente in Chrome 89, senza necessità di JavaScript. L'utente può quindi scorrere il contenuto dell'articolo con il dispositivo di input, come sempre. Si tratta di contenuti complementari, come indicato nel markup.

Ho utilizzato il seguente markup per organizzare le schede:

<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>

Posso stabilire connessioni tra gli elementi <a> e <article> con le proprietà href e id in questo modo:

<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>

Poi ho riempito gli articoli con quantità miste di lorem e i link con una lunghezza mista e un insieme di immagini di titoli. Iniziamo il layout con i contenuti.

Layout di scorrimento

In questo componente sono disponibili tre diversi tipi di aree di scorrimento:

  • La barra di navigazione (rosa) può essere scorribile orizzontalmente
  • L'area dei contenuti (blu) è a scorrimento orizzontale
  • Ogni elemento dell'articolo (verde) può scorrere verticalmente.
3 caselle colorate con frecce direzionali corrispondenti a colori che delineano le aree di scorrimento e mostrano la direzione dello scorrimento.

Lo scorrimento include due diversi tipi di elementi:

  1. Una finestra
    Una casella con dimensioni definite che abbia lo stile della proprietà overflow.
  2. Una superficie di grandi dimensioni
    In questo layout, si tratta dei contenitori elenco: link di navigazione, articoli della sezione e contenuti degli articoli.

Layout <snap-tabs>

Il layout di primo livello che ho scelto era Flex (Flexbox). Imposto la direzione su column, quindi l'intestazione e la sezione sono ordinate verticalmente. Questa è la nostra prima finestra di scorrimento e nasconde tutto con l'overflow nascosto. L'intestazione e la sezione utilizzeranno presto l'overscroll, come singole zone.

HTML
<snap-tabs>
  <header></header>
  <section></section>
</snap-tabs>
CSS
  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 against 
needing 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }

Ritorno al colorato diagramma a tre scorrimenti:

  • <header> ora è preparato per essere il container di scorrimento (rosa).
  • <section> è preparato per essere il contenitore di scorrimento (blu).

I frame che ho evidenziato di seguito con VisBug ci aiutano a vedere le finestre create dai container di scorrimento.

Gli elementi di intestazione e sezione presentano overlay rosa acceso, che delineano lo spazio occupato nel componente

Layout schede <header>

Il layout successivo è praticamente lo stesso: uso l'opzione flessibile per creare l'ordinamento verticale.

HTML
<snap-tabs>
  <header>
    <nav></nav>
    <span class="snap-indicator"></span>
  </header>
  <section></section>
</snap-tabs>
CSS
header {
  display: flex;
  flex-direction: column;
}

.snap-indicator deve spostarsi orizzontalmente con il gruppo di link e questo layout di intestazione consente di impostare questa fase. Non ci sono elementi posizionati in modo assoluto qui.

Gli elementi nav e span.indicator hanno overlay rosa acceso, che delineano lo spazio occupato nel componente

Poi, gli stili di scorrimento. Ho scoperto che possiamo condividere gli stili di scorrimento tra le nostre due aree di scorrimento orizzontali (intestazione e sezione), così ho creato una classe di utilità, .scroll-snap-x.

.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;
    }
  }
}

Ognuno di questi ha bisogno di overflow sull'asse x, di contenimento dello scorrimento per bloccare l'overscroll, delle barre di scorrimento nascoste per i dispositivi tattili e infine dello scorrimento per bloccare le aree di presentazione dei contenuti. L'ordine delle schede della tastiera è accessibile e qualsiasi guida all'interazione è naturale. Inoltre, i container Snap-Scorretta hanno una piacevole interazione in stile carousel dalla tastiera.

Layout dell'intestazione <nav> delle schede

I link di navigazione devono essere allineati, senza interruzioni di riga, centrati verticalmente e ogni elemento link deve agganciarsi al contenitore di scroll-snap. Dai il massimo per il CSS 2021!

HTML
<nav>
  <a></a>
  <a></a>
  <a></a>
  <a></a>
</nav>
CSS
  nav {
  display: flex;

  & a {
    scroll-snap-align: start;

    display: inline-flex;
    align-items: center;
    white-space: nowrap;
  }
}

Ogni link applica stili e dimensioni, quindi il layout di navigazione deve specificare solo direzione e flusso. Larghezze uniche negli elementi di navigazione rendono la transizione tra le schede divertente mentre l'indicatore regola la larghezza in base al nuovo target. A seconda di quanti elementi ci sono, il browser mostrerà o meno una barra di scorrimento.

Gli elementi di navigazione presentano overlay rosa acceso, che delineano lo spazio occupato nel componente e i punti in cui eccedono

Layout schede <section>

Questa sezione è un articolo flessibile e deve essere il consumatore principale di spazio. Deve inoltre creare colonne in cui inserire gli articoli. Ancora una volta, lavoriamoci per CSS 2021. L'elemento block-size: 100% estende questo elemento il più possibile per riempire l'elemento principale e, per un proprio layout, crea una serie di colonne che hanno 100% la larghezza dell'elemento principale. Le percentuali sono molto efficaci qui, perché abbiamo dei vincoli rigidi per l'elemento padre.

HTML
<section>
  <article></article>
  <article></article>
  <article></article>
  <article></article>
</section>
CSS
  section {
  block-size: 100%;

  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 100%;
}

È come se stessi dicendo "espandi il più possibile in verticale, in modo insistente" (ricorda l'intestazione che abbiamo impostato su flex-shrink: 0: è una difesa contro questo push di espansione), che imposta l'altezza della riga per un insieme di colonne a altezza intera. Lo stile auto-flow indica alla griglia di disporre sempre gli elementi secondari in una linea orizzontale, senza wrapping, esattamente ciò che vogliamo, per superare la finestra principale.

Gli elementi dell&#39;articolo presentano overlay rosa acceso, che delineano lo spazio che occupano nel componente e i punti in cui eccedono

A volte mi è capitato di avere qualcosa da dire! Questo elemento di sezione si adatta a un riquadro, ma ha anche creato un gruppo di riquadri. Spero che le immagini e le spiegazioni ti siano d'aiuto.

Layout schede <article>

L'utente dovrebbe essere in grado di scorrere il contenuto dell'articolo e le barre di scorrimento dovrebbero essere visualizzate solo in caso di overflow. Questi elementi dell'articolo sono in una posizione ordinata. Sono contemporaneamente un elemento principale a scorrimento e uno secondario. Il browser gestisce alcune interazioni difficili con il tocco, il mouse e la tastiera.

HTML
<article>
  <h2></h2>
  <p></p>
  <p></p>
  <h2></h2>
  <p></p>
  <p></p>
  ...
</article>
CSS
article {
  scroll-snap-align: start;

  overflow-y: auto;
  overscroll-behavior-y: contain;
}

Ho scelto di far scattare gli articoli all'interno del loro cursore principale. Mi piace molto il modo in cui gli elementi dei link di navigazione e degli articoli si agganciano all'inizio in linea dei rispettivi contenitori di scorrimento. Sembra una relazione armoniosa.

l&#39;elemento articolo e i relativi elementi secondari presentano overlay rosa acceso, che delineano lo spazio che occupano all&#39;interno del componente e la direzione di overflow

L'articolo è un elemento secondario della griglia e le sue dimensioni sono predeterminate in base all'area dell'area visibile a cui vogliamo fornire l'UX di scorrimento. Ciò significa che non ho bisogno di stili di altezza o larghezza, ma solo di definire l'overflow. Imposto overflow-y su auto e poi trappolesco le interazioni di scorrimento con la pratica proprietà overscroll-behavior.

Riepilogo delle 3 aree di scorrimento

Di seguito ho scelto l'opzione "Mostra sempre le barre di scorrimento" nelle impostazioni del sistema. Penso che sia due volte importante che il layout funzioni con questa impostazione attivata, dato che devo esaminare il layout e l'orchestrazione dello scorrimento.

Le tre barre di scorrimento sono impostate per essere visualizzate, e ora occupano spazio di layout e il nostro componente continua a funzionare correttamente.

Penso che vedere i canali di scorrimento della barra di scorrimento in questo componente aiuti a mostrare chiaramente dove si trovano le aree di scorrimento, la direzione che supportano e in che modo interagiscono tra loro. Considera come anche ciascuno di questi frame delle finestre di scorrimento sia l'elemento padre flessibile o griglia di un layout.

DevTools può aiutarci a visualizzarlo:

Le aree di scorrimento presentano overlay con gli strumenti griglia e flexbox, che delineano lo spazio che occupano nel componente e la direzione di overflow
Chromium Devtools, che mostra il layout degli elementi nav Flexbox pieno di elementi di ancoraggio, il layout della sezione griglia pieno di elementi articolo e gli elementi degli articoli pieni di paragrafi e un elemento heading.

I layout di scorrimento sono completi: agganciabili, collegabili tramite link diretti e accessibili dalla tastiera. Base solida per miglioramenti UX, stile e gioia.

Caratteristica principale

I riquadri secondari agganciati con scorrimento mantengono la loro posizione bloccata durante il ridimensionamento. Ciò significa che JavaScript non dovrà mostrare nulla durante la rotazione del dispositivo o il ridimensionamento del browser. Provala nella modalità del dispositivo di Chromium DevTools selezionando una modalità diversa da Adattabile, quindi ridimensiona il frame del dispositivo. Tieni presente che l'elemento rimane visibile e bloccato con i suoi contenuti. Questa funzionalità è disponibile da quando Chromium ha aggiornato l'implementazione per corrispondere alle specifiche. Ecco un post del blog in merito.

Animazione

L'obiettivo dell'animazione è collegare chiaramente le interazioni con il feedback dell'interfaccia utente. Ciò aiuta l'utente a guidare o assistere l'utente nella sua (si spera) scoperta fluida di tutti i contenuti. Aggiungo le azioni con uno scopo e in modo condizionale. Ora gli utenti possono specificare le loro preferenze di movimento nel sistema operativo e a me piace molto rispondere alle loro preferenze nelle interfacce.

Collego una sottolineatura di una scheda alla posizione di scorrimento dell'articolo. L'agganciamento non è solo un bell'allineamento, ma anche l'inizio e la fine di un'animazione. In questo modo, <nav>, che agisce come una mini-mappa, rimane collegato ai contenuti. Controlleremo la preferenza di movimento dell'utente sia da CSS che da JS. Ci sono alcuni ottimi posti in cui prestare attenzione.

Comportamento scorrimento

Hai la possibilità di migliorare il comportamento di movimento di :target e element.scrollIntoView(). Per impostazione predefinita, è istantanea. Il browser imposta solo la posizione di scorrimento. E se volessimo passare alla posizione di scorrimento anziché battere le ciglia?

@media (prefers-reduced-motion: no-preference) {
  .scroll-snap-x {
    scroll-behavior: smooth;
  }
}

Poiché in questo caso stiamo introducendo il movimento e il movimento che l'utente non controlla (come lo scorrimento), applichiamo questo stile solo se l'utente non ha preferenze nel suo sistema operativo riguardo alla riduzione del movimento. In questo modo, introduciamo un'azione di scorrimento solo per gli utenti che ne sono d'accordo.

Indicatore schede

Lo scopo di questa animazione è aiutare ad associare l'indicatore allo stato dei contenuti. Ho deciso di applicare una dissolvenza incrociata colorata negli stili border-bottom per gli utenti che preferiscono il movimento ridotto e un'animazione con scorrimento e dissolvenza colore collegata a scorrimento per gli utenti che preferiscono il movimento.

In Chromium DevTools posso attivare/disattivare la preferenza e mostrare i due diversi stili di transizione. Mi sono divertita tantissimo a costruirla.

@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;
  }
}

Nascondo .snap-indicator quando l'utente preferisce il movimento ridotto perché non mi serve più. Poi lo sostituisco con stili border-block-end e transition. Nell'interazione con le schede, nota che l'elemento di navigazione attivo non solo presenta una sottolineatura del brand, ma il colore del testo è anche più scuro. L'elemento attivo ha un contrasto di colore del testo più elevato e un accento molto luminoso in condizioni di luce scarsa.

Bastano poche righe di codice CSS in più per far sentire qualcuno (nel senso che rispettiamo attentamente le loro preferenze di movimento). Mi piace un sacco.

@scroll-timeline

Nella sezione precedente ho mostrato come gestisco gli stili di dissolvenza incrociata con movimento ridotto e in questa sezione ti mostrerò come ho collegato l'indicatore e un'area di scorrimento. Ecco alcune attività sperimentali divertenti dopo poco tempo. Spero che tu sia entusiasta quanto me.

const { matches:motionOK } = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
);

Innanzitutto controllo la preferenza di movimento dell'utente da JavaScript. Se il risultato è false, il che significa che l'utente preferisce il movimento ridotto, non eseguiremo nessuno degli effetti di movimento di scorrimento che collega.

if (motionOK) {
  // motion based animation code
}

Al momento della redazione del presente documento, il supporto dei browser per @scroll-timeline non è nessuno. Si tratta di una bozza di specifica con implementazioni solo sperimentali. Comunque ha un polyfill, che uso in questa demo.

ScrollTimeline

Anche se CSS e JavaScript possono creare sequenze temporali di scorrimento, ho attivato JavaScript per poter utilizzare le misurazioni degli elementi live nell'animazione.

const sectionScrollTimeline = new ScrollTimeline({
  scrollSource: tabsection,  // snap-tabs > section
  orientation: 'inline',     // scroll in the direction letters flow
  fill: 'both',              // bi-directional linking
});

Voglio che una cosa segua la posizione di scorrimento di un'altra e, creando un ScrollTimeline, definisco il driver del link di scorrimento, ovvero scrollSource. Normalmente un'animazione sul web viene eseguita in base a un segno di spunta del periodo di tempo globale, ma con un sectionScrollTimeline personalizzato in memoria, posso modificare tutto questo.

tabindicator.animate({
    transform: ...,
    width: ...,
  }, {
    duration: 1000,
    fill: 'both',
    timeline: sectionScrollTimeline,
  }
);

Prima di entrare nei fotogrammi chiave dell'animazione, penso che sia importante indicare che il follower dello scorrimento, tabindicator, verrà animato in base a una sequenza temporale personalizzata, ovvero il scorrimento della nostra sezione. Completa il collegamento, ma manca l'elemento finale, ovvero i punti stateful tra cui animarsi, noti anche come fotogrammi chiave.

Fotogrammi dinamici

Esiste un modo CSS dichiarativo davvero potente per animarsi con @scroll-timeline, ma l'animazione che ho scelto di realizzare era troppo dinamica. Non è possibile passare dalla larghezza di auto e non è possibile creare dinamicamente un numero di fotogrammi chiave in base alla lunghezza dei riquadri secondari.

Tuttavia, JavaScript sa come ottenere queste informazioni, quindi eseguiremo l'iterazione direttamente sui secondari e recuperare i valori calcolati in fase di runtime:

tabindicator.animate({
    transform: [...tabnavitems].map(({offsetLeft}) =>
      `translateX(${offsetLeft}px)`),
    width: [...tabnavitems].map(({offsetWidth}) =>
      `${offsetWidth}px`)
  }, {
    duration: 1000,
    fill: 'both',
    timeline: sectionScrollTimeline,
  }
);

Per ogni tabnavitem, destruttura la posizione offsetLeft e restituisci una stringa che la utilizza come valore translateX. Vengono creati quattro fotogrammi chiave di trasformazione per l'animazione. Lo stesso viene fatto per la larghezza: a ciascuno viene chiesto di qual è la sua larghezza dinamica e poi viene utilizzato come valore per i fotogrammi chiave.

Ecco un output di esempio, basato sui miei caratteri e preferenze del browser:

Fotogrammi chiave TraduttoreX:

[...tabnavitems].map(({offsetLeft}) =>
  `translateX(${offsetLeft}px)`)

// results in 4 array items, which represent 4 keyframe states
// ["translateX(0px)", "translateX(121px)", "translateX(238px)", "translateX(464px)"]

Larghezza fotogrammi chiave:

[...tabnavitems].map(({offsetWidth}) =>
  `${offsetWidth}px`)

// results in 4 array items, which represent 4 keyframe states
// ["121px", "117px", "226px", "67px"]

Per riepilogare la strategia, l'indicatore della scheda ora si anima in quattro fotogrammi chiave a seconda della posizione di agganciamento dello scorrimento della sezione. I punti di agganciamento creano una chiara delimitazione tra i nostri fotogrammi chiave e aggiungono un tocco di sincronizzazione all'animazione.

scheda attiva e scheda non attiva sono mostrate con gli overlay VisBug, che mostrano i punteggi di contrasto superiori per entrambi

L'utente guida l'animazione con l'interazione, vedendo che la larghezza e la posizione dell'indicatore cambiano da una sezione all'altra, seguendo perfettamente lo scorrimento.

Forse non lo avrai notato, ma sono molto orgoglioso della transizione di colore quando viene selezionato l'elemento di navigazione evidenziato.

Il grigio più chiaro deselezionato appare ancora più respirato quando l'elemento evidenziato ha un contrasto maggiore. È frequente eseguire la transizione del colore al testo, ad esempio al passaggio del mouse e quando viene selezionato, ma è di livello successivo eseguire la transizione di quel colore allo scorrimento, sincronizzato con l'indicatore di sottolineatura.

Ecco come ci sono riuscito:

tabnavitems.forEach(navitem => {
  navitem.animate({
      color: [...tabnavitems].map(item =>
        item === navitem
          ? `var(--text-active-color)`
          : `var(--text-color)`)
    }, {
      duration: 1000,
      fill: 'both',
      timeline: sectionScrollTimeline,
    }
  );
});

Ogni link di navigazione delle schede richiede questa nuova animazione a colori, che monitora la stessa sequenza temporale di scorrimento dell'indicatore di sottolineatura. Uso la stessa sequenza temporale di prima: il suo ruolo è l'emissione di un segno di spunta durante lo scorrimento, pertanto possiamo utilizzarlo in qualsiasi tipo di animazione. Come ho fatto prima, creo 4 fotogrammi chiave nel loop e restituisco i colori.

[...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)",
]

Il fotogramma chiave con il colore var(--text-active-color) evidenzia il link, altrimenti è un colore di testo standard. Il loop nidificato lo rende relativamente semplice, poiché il loop esterno è ogni elemento di navigazione e il loop interno è i fotogrammi chiave personali di ogni elemento di navigazione. Controlliamo se l'elemento del loop esterno è uguale a quello del loop interno e lo uso per sapere quando è selezionato.

Mi è divertito a scrivere questo articolo. Tantissimo.

Ancora più miglioramenti di JavaScript

Vale la pena ricordare che ciò che mostro qui funziona senza JavaScript. Detto questo, vediamo come possiamo migliorarla quando è disponibile JS.

Link diretti Il browser in-page raggiungerà l'ID che corrisponde all'hash dell'URL. Ho trovato che questo gestore onload ha apportato l'effetto su tutte le piattaforme.

window.onload = () => {
  if (location.hash) {
    tabsection.scrollLeft = document
      .querySelector(location.hash)
      .offsetLeft;
  }
}

Scorri e termina sincronizzazione

I nostri utenti non sempre fanno clic o usano una tastiera, a volte sono solo liberi di scorrere, come dovrebbero. Quando la barra di scorrimento della sezione smette di scorrere, dove arriva la barra di navigazione in alto.

Ecco come attendo la fine dello scorrimento: js tabsection.addEventListener('scroll', () => { clearTimeout(tabsection.scrollEndTimer); tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100); });

Ogni volta che fai scorrere le sezioni, cancella il timeout della sezione, se presente, e creane una nuova. Quando le sezioni smettono di scorrere, non cancellare il timeout e attivare 100 ms dopo il riposo. Quando si attiva, chiama la funzione che cerca di capire dove l'utente si è fermato.

const determineActiveTabSection = () => {
  const i = tabsection.scrollLeft / tabsection.clientWidth;
  const matchingNavItem = tabnavitems[i];

  matchingNavItem && setActiveTab(matchingNavItem);
};

Supponendo che lo scorrimento sia agganciato, dividendo la posizione di scorrimento corrente dalla larghezza dell'area di scorrimento dovrebbe essere generato un numero intero e non un decimale. Quindi provo a recuperare un navitem dalla cache tramite questo indice calcolato e, se trova qualcosa, invio la corrispondenza in modo che sia impostato come attivo.

const setActiveTab = tabbtn => {
  tabnav
    .querySelector(':scope a[active]')
    .removeAttribute('active');

  tabbtn.setAttribute('active', '');
  tabbtn.scrollIntoView();
};

L'impostazione della scheda attiva inizia cancellando qualsiasi scheda attualmente attiva, quindi assegnando all'elemento di navigazione in entrata l'attributo stato attivo. La chiamata a scrollIntoView() include un'interazione divertente con il CSS, di cui vale la pena.

.scroll-snap-x {
  overflow: auto hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;

  @media (prefers-reduced-motion: no-preference) {
    scroll-behavior: smooth;
  }
}

Nel CSS dell'utilità di scorrimento orizzontale abbiamo nidificato una query supporti che applica lo scorrimento smooth se l'utente è tollerante al movimento. JavaScript può effettuare liberamente chiamate per visualizzare gli elementi tramite scorrimento e il CSS può gestire l'UX in modo dichiarativo. Un abbinamento davvero delizioso a volte.

Conclusione

Ora che sai come ci sono riuscito, come faresti?! Questo rende l'architettura dei componenti divertente. Chi realizzerà la prima versione con slot nel framework preferito? 🙂

Diversifica i nostri approcci e scopriamo tutti i modi per creare sul web. Crea un Glitch, inviaci un tweet della tua versione e la aggiungerò alla sezione Remix della community di seguito.

Remix della community