Transformer Tabs

Avatar of Chris Coyier
Chris Coyier am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Tabs sind ein einfaches Designmuster, bei dem eine Reihe von Links offensichtlich klickbare Navigation sind und beim Klicken auf einen Link neue Inhalte angezeigt werden. Natürlich gibt es viele Variationen, aber es ist eines der allgegenwärtigsten Navigationsdesignmuster. Wenn sie in einer horizontalen Reihe angeordnet sind, sind sie auch eines der am wenigsten bildschirmfreundlichen Designmuster.

Wir können es aber zum Laufen bringen.

Ohne etwas zu tun, um Tabs auf einem kleinen Bildschirm zu helfen, werden Sie auf irgendein Problem stoßen

  • Sie lassen die Seite "herauszoomen" und die Tabs sind winzige Berührungsziele
  • Sie lassen die Seite auf die Gerätebreite und...
    • Es ist kein Platz für die Tabs, also werden sie abgeschnitten.
    • Die Tabs brechen um, sehen komisch aus und nehmen zu viel Platz ein.

Grundsätzlich: Wir müssen hier etwas tun, um Tabs für kleine Bildschirme besser zu machen.

Das wurde schon einmal gemacht

Beliebte Lösungen sind

Ich möchte es mit einigen spezifischen Zielen wieder tun.

Ziele

Hier ist der Plan

  • Normaler „Tabs“-Look, wenn Platz vorhanden ist, Dropdown, wenn nicht.
  • „Aktiver“ Tab immer sichtbar und offensichtlich.
  • Funktioniert mit #hash-Tabs, bei denen der gesamte Inhalt auf der Seite ist und Inhaltspanels ausgeblendet/angezeigt werden.
  • Funktioniert mit verknüpften Tabs, bei denen die Tabs auf eine andere URL verweisen.
  • Das HTML ist semantisch.
  • Es gibt eine Version des HTML, die sich nicht ändert.
  • Es gibt eine Version des JavaScript, die sich nicht ändert.
  • Sie können auf einen bestimmten Tab verlinken.

Wir gehen also nicht nur das Design, sondern auch die Funktionalität an.

Muster wie der „Off Canvas“-Stil werden hier nicht funktionieren, da wir versuchen, den aktuellen Tab anzuzeigen und nicht zu verbergen. Die Konvertierung in ein <select>-Dropdown funktioniert nicht, da dies anderes HTML und anderes JavaScript ist.

Das HTML

Tabs sind Navigation, also <nav>. Die role sollte durch das Tag impliziert werden, aber man kann sich nicht immer darauf verlassen, daher fügen wir die role hinzu. Wir verwenden eine Klasse für das CSS am äußersten Element (dem <nav>). Die Navigationspunkte selbst sind in einer Liste weil das am besten ist. Jeder Link hat entweder ein #hash-Ziel oder eine gültige URL.

<nav role='navigation' class="transformer-tabs">
    <ul>
      <li><a href="#tab-1">Important Tab</a></li>
      <li><a href="#tab-2" class="active">Smurfvision</a></li>
      <li><a href="#tab-3">Monster Truck Rally</a></li>
      <li><a href="http://google.com">Go To Google &rarr;</a></li>
    </ul>
</nav>

Nichts Überflüssiges.

Das CSS für die Tab-Ansicht

Es gibt eine Reihe von spezifischen CSS für die Tabs in jedem „Zustand“ (Tabs oder Dropdown). Sie können „mobile first“ beginnen, indem Sie das Dropdown stylen, und dann eine Media Query mit min-width verwenden, um es als Tab umzugestalten, oder Sie können „desktop first“ beginnen, indem Sie zuerst die Tabs stylen und dann eine Media Query mit max-width verwenden, um es in ein Dropdown umzugestalten. Sie sind so unterschiedlich, dass ich keinen großen Vorteil in der einen oder anderen Richtung sehe, aber ich würde das an Ihre bereits auf der Website verwendeten Methoden anpassen.

Desktop-first und SCSS für diese Demo.

.transformer-tabs {
  ul {
    list-style: none;
    padding: 0;
    margin: 0;
    border-bottom: 3px solid white;
  }
  li {
    display: inline-block;
    padding: 0;
    vertical-align: bottom;
  }
  a {
    display: inline-block;
    color: white;
    text-decoration: none;
    padding: 0.5rem;
    &.active {
      border-bottom: 3px solid black;
      position: relative;
      bottom: -3px;
    }
  }
}

Nur eine Reihe von Links mit einer Linie darunter. Der Ankerlink mit einer „aktiven“ Klasse erhält einen andersfarbigen Rand, der den Rand von Kante zu Kante überlappt. vertical-align hält sie alle auf derselben Grundlinie, wenn der aktive Link den Rand erhält, den die anderen nicht haben.

Das CSS für die Dropdown-Ansicht

Wir müssen eine Ansichtsbreite finden, bei der das Tab-Aussehen zusammenbricht, und dort eine Media-Query einfügen. 700px für diese Demo.

.transformer-tabs {
  ...
  @media (max-width: 700px) {
    ul {
      border-bottom: 0;
      overflow: hidden;
      position: relative;
      background: linear-gradient(#666, #222);
      &::after {
        content: "☰"; /* "Three Line Menu Navicon" shows up */
        position: absolute;
        top: 8px;
        right: 15px;
        z-index: 2;
        pointer-events: none;
      }
    }
    li {
      display: block; /* One link per "row" */
    }
    a {
      position: absolute; /* Stack links on top of each other */
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      &.active {
        border: 0;
        z-index: 1; /* Active tab is on top */
        background: linear-gradient(#666, #222);
      }
    }
  }
}

Wenn die Media-Query greift, gelangen wir hierher

Der aktive Tab ist immer noch offensichtlich (er ist der einzige angezeigte) und ein Drei-Linien-Menü-Navicon wird angezeigt, was universell als Symbol zum Aufrufen weiterer Navigation verstanden wird.

Die JavaScript-Struktur

Die benötigte Funktionalität

  • Wenn es ein #hash-Link ist, enthüllt die Auswahl des Links das Panel mit dieser ID und blendet das aktuell angezeigte aus.
  • Ändern Sie die URL, um diesen #hash anzuzeigen, aber ohne die Historie zu beeinflussen (keine Rückwärts-Button-Ärgernisse).
  • Visuelle Anzeige des nun aktiven Tabs (Togglen von Klassen entsprechend).
  • Wenn es sich um einen verknüpften Tab handelt, lassen Sie diesen Link funktionieren.
  • Wenn die Seite mit einem Hash geladen wird, der einem Tab entspricht, wechseln Sie zu diesem Tab.
  • Im Dropdown-Zustand für kleine Bildschirme erlauben Sie dem Dropdown, sich beim Auswählen zu öffnen/schließen.

Einige Struktur basierend auf diesen Anforderungen

var Tabs = {

  init: function() {
    this.bindUIfunctions();
    this.pageLoadCorrectTab();
  },

  bindUIfunctions: function() {
  },

  changeTab: function(hash) {
  },

  pageLoadCorrectTab: function() {
  },

  toggleMobileMenu: function(event, el) {
  }

}

Tabs.init();

Tabs beim Auswählen ändern

Die einzige Zeit, in der wir einen Tab beim Auswählen ändern müssen, ist, wenn der ausgewählte Tab ein #hash-Link ist. Andernfalls ist es ein verknüpfter Tab und er sollte einfach diesem Link folgen. (Und mit „Auswählen“ meine ich Klicken, Tippen, Tabben und Aktivieren oder was auch immer.) Daher kann unsere changeTab-Funktion einfach diesen Hash-Wert akzeptieren und verwenden.

  changeTab: function(hash) {
    
    // find the link based on that hash
    var anchor = $("[href=" + hash + "]");

    // find the related content panel
    var div = $(hash);

    // activate correct anchor (visually)
    anchor.addClass("active").parent().siblings().find("a").removeClass("active");

    // activate correct div (visually)
    div.addClass("active").siblings().removeClass("active");

    // update URL, no history addition
    window.history.replaceState("", "", hash);

    // Close menu, in case in dropdown state
    anchor.closest("ul").removeClass("open");

  },

Tab-Klicks behandeln

Wir verwenden Standard-Event-Delegation, nur um effizient zu sein. Jeder „Klick“ (der für Taps gut funktioniert), vorausgesetzt, es ist nicht der bereits aktive Tab und es ist ein #hash-Link, wird diesen Hash einfach an die changeTab-Funktion weitergeben.

    // Delegation
    $(document)
      .on("click", ".transformer-tabs a[href^='#']:not('.active')", function(event) {
        Tabs.changeTab(this.hash);
        event.preventDefault();
      })

... und preventDefault(), damit die Seite nicht ungeschickt nach unten springt.

Das Dropdown umschalten

Wenn die Media-Query aktiv ist und die Tabs somit in ihrem Dropdown-Zustand sind, können wir das Dropdown umschalten, wenn der .active Tab angeklickt wird. Aufgrund unseres Stylings wissen wir, dass der aktive Tab den gesamten klickbaren Bereich abdeckt.

    $(document)
      // ... first click handler, chaining for efficiency 
      .on("click", ".transformer-tabs a.active", function(event) {
        Tabs.toggleMobileMenu(event, this);
        event.preventDefault();
      });

Die Funktion toggleMobileMenu ist sehr einfach. Aber ich mag es trotzdem, dass wir sie in eine eigene Funktion abstrahiert haben, falls sie eines Tages mehr tun muss, damit wir nicht alles zerhacken.

  toggleMobileMenu: function(event, el) {
    $(el).closest("ul").toggleClass("open");
  }

Die .open-Klasse öffnet das Menü visuell durch einige CSS-Änderungen.

.transformer-tabs {
  ...
  @media (max-width: 700px) {
    ul {
      ...
      &.open {
        a {
          position: relative;
          display: block;
        }
      }
    }
  }
  ...
}

Das Entfernen der absoluten Positionierung dieser Tabs und das Umwandeln in Block-Elemente lässt das Menü nach unten aufklappen und den darunter liegenden Inhalt ebenfalls nach unten schieben. Dies ist das, was es zu einem Dropdown macht.

Lade den richtigen Tab, wenn die Seite mit einem #Hash geladen wird

Es stellt sich heraus, dass das sehr einfach ist. Schauen Sie einfach auf den Hash in der URL und übergeben Sie ihn an die changeTab-Funktion.

  pageLoadCorrectTab: function() {
    this.changeTab(document.location.hash);
  },

Deshalb abstrahieren wir Funktionalitäten in wiederverwendbare Funktionen statt in Spaghetti-Code.

Das ist nicht nur theoretisch

Ich schreibe das, nachdem ich die Tabs auf CodePen repariert habe, wo die Tabs bis dahin ziemlich schlecht waren. Wir haben sowohl #hash-Link-Tabs als auch echte verknüpfte Tabs auf CodePen, daher die Anforderungen.

Möchten Sie es besser machen?

Vielleicht eine Version, bei der das Menü den Inhalt darunter nicht nach unten schiebt, sondern das erweiterte Dropdown einfach über dem Inhalt liegt, wäre cool. Vielleicht eines, das eine Menge Links (mehr als für einen kleinen Bildschirm nötig) mit einer Art Scrolling oder Paginierung bewältigen könnte. Vielleicht eines mit Animationen/Übergängen.

Ein Problem mit der exakten Demo, die wir hier erstellt haben, ist, dass Sie das Dropdown nicht schließen können, es sei denn, Sie wählen einen Tab aus. Sie können den aktuellen Tab auswählen, um ihn zu schließen, ohne etwas zu tun, aber Sie können nicht einfach auf das Drei-Linien-Menü klicken, um es zu schließen. Das liegt daran, dass Sie (soweit ich weiß) keine Klick-Events an ein Pseudo-Element binden können. Auf CodePen habe ich für das Drei-Linien-Menü einfach ein <span> verwendet, damit Sie es auf diese Weise umschalten können, aber das bedeutet zusätzlichen Markup.

Demo

Hinweis: „Go To Google →“ ist ein verknüpfter Tab, nur um ihn zu testen. Er funktioniert hier auf CodePen wegen des sandboxed iFrames nicht. Er würde unter normalen Umständen funktionieren.

Sehen Sie den Pen Transformer Tabs von Chris Coyier (@chriscoyier) auf CodePen