Bester Weg, um eine Web-Application programmatisch zu zoomen

Avatar of Michael Romanov
Michael Romanov am

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

Webseiten-Zugänglichkeit war schon immer wichtig, aber heutzutage, wo wir in den meisten Ländern klare Standards und Vorschriften von Regierungen haben, ist es noch entscheidender geworden, diese Standards zu unterstützen und unsere Projekte so zugänglich wie möglich zu gestalten.

Die W3C-Empfehlung sieht 3 Konformitätsstufen vor: A, AA und AAA. Um die Stufe AA zu erreichen, müssen wir unter anderem eine Möglichkeit bieten, die Schriftgröße der Website zu erhöhen.

1.4.4 Textgröße ändern: Mit Ausnahme von Bildunterschriften und Bildern von Text kann Text ohne Hilfstechnologie bis zu 200 Prozent skaliert werden, ohne dass Inhalt oder Funktionalität verloren gehen. (Stufe AA)

Betrachten wir Lösungen dafür und versuchen, die beste zu finden.

Update (25.09.17): Es stellt sich heraus, dass WCAG keine benutzerdefinierte Lösung zur Textskalierung zusätzlich zu dem, was Benutzeragenten anbieten, verlangt. Wir müssen nur sicherstellen, dass eine Website nach der Skalierung gut aussieht. Wenn wir dennoch Elemente aus irgendeinem Grund skalieren möchten, folgt hier eine gründliche Analyse verschiedener Methoden dafür.

Unvollständige Lösung: CSS zoom

Das erste Wort, das uns einfällt, wenn wir über Größenänderung sprechen, ist Zoom. CSS hat eine zoom-Eigenschaft und sie tut genau das, was wir wollen – sie vergrößert die Größe.

Schauen wir uns ein gängiges Designmuster an (das wir für den Rest dieses Artikels verwenden werden): eine horizontale Navigationsleiste, die sich an einem bestimmten Breakpoint in ein Menüsymbol verwandelt.

Das wollen wir erreichen. Kein Umbruch und das gesamte Menü verwandelt sich an einem bestimmten Breakpoint in ein Menüsymbol.

Das folgende GIF zeigt, was wir mit dem zoom-Ansatz auf das Menüelement erhalten. Ich habe einen Schalter erstellt, der die Auswahl verschiedener Größen ermöglicht und die entsprechende Zoomstufe anwendet.

Schauen Sie sich den Pen hier an, wenn Sie damit spielen möchten.

Das Menü ragt aus dem sichtbaren Bereich hinaus, da wir die Breite des Viewports mit Zoom nicht programmatisch erhöhen können und das Menü wegen der Anforderung auch nicht umbrechen können. Das Menüsymbol erscheint ebenfalls nicht, da sich die Bildschirmgröße tatsächlich nicht geändert hat, sie ist dieselbe wie vor dem Klicken auf den Schalter.

All diese Probleme, plus, zoom wird sowieso von Firefox überhaupt nicht unterstützt.

Falsche Lösung: Scale-Transformationen

Wir können mit transform: scale einen weitgehend ähnlichen Effekt erzielen wie mit zoom. Allerdings wird transform breiter von Browsern unterstützt. Dennoch erhalten wir die exakt gleichen Probleme wie bei zoom: Das Menü passt nicht in den sichtbaren Bereich und schlimmer noch, es ragt auch über den vertikalen sichtbaren Bereich hinaus, da das Seitenlayout basierend auf einer anfänglichen Skalierung von 1-Faktor berechnet wird.

Sehen Sie den Pen Font-switcher–wrong-scale von Mikhail Romanov (@romanovma) auf CodePen.

Eine weitere unvollständige Lösung: rem und html font-size

Anstatt zu zoomen oder zu skalieren, könnten wir rem als Größeneinheit für alle Elemente auf der Seite verwenden. Wir können dann ihre Größe ändern, indem wir die font-size-Eigenschaft des html-Elements ändern, denn per Definition entspricht 1rem dem font-size-Wert von html.

Das ist eine ziemlich gute Lösung, aber noch nicht ganz perfekt. Wie Sie in der folgenden Demo sehen können, hat sie die gleichen Probleme wie die vorherigen Beispiele: Sie passt irgendwann nicht mehr horizontal, weil der benötigte Platz zwar größer wird, die Breite des Viewports aber gleich bleibt.

Sehen Sie den Pen Font-switcher–wrong-rem von Mikhail Romanov (@romanovma) auf CodePen.

Das Problem ist sozusagen, dass sich die Media Queries nicht an die Größenänderung anpassen. Wenn wir die Größe erhöhen, sollten sich die Media Queries entsprechend anpassen, damit der Effekt an derselben Stelle vor der Größenänderung, relativ zum Inhalt, eintritt.

Funktionierende Lösung: Browser-Zoom mit Sass mixin emulieren

Lassen Sie uns zur Inspiration sehen, wie die native Browser-Zoomfunktion das Problem löst.

Wow! Chrome versteht, dass Zoomen tatsächlich den Viewport verändert. Je größer der Zoom, desto schmaler der Viewport. Das bedeutet, dass unsere Media Queries wie erwartet und benötigt greifen.

Eine Möglichkeit, dies zu erreichen (ohne sich auf den nativen Zoom zu verlassen, da wir keinen Zugriff darauf für unsere On-Page-Steuerelemente haben, wie von AA gefordert), besteht darin, die Media-Query-Werte jedes Mal zu aktualisieren, wenn wir die Schriftgröße ändern.

Nehmen wir zum Beispiel an, wir haben einen Media-Query-Breakpoint bei 1024px und führen einen 200%-Zoom durch. Wir sollten diesen Breakpoint auf 2048px aktualisieren, um die neue Größe auszugleichen.

Sollte das nicht einfach sein? Können wir die Media Queries nicht einfach mit rem-Einheiten einstellen, sodass sich die Media Queries automatisch anpassen, wenn wir die font-size erhöhen? Leider nein, dieser Ansatz funktioniert nicht. Versuchen Sie, die Media Queries in diesem Pen von px auf rem zu ändern und sehen Sie, dass sich nichts ändert. Das Layout wechselt nach der Größenänderung nicht die Breakpoints. Das liegt daran, dass gemäß den Standards sowohl rem- als auch em-Einheiten in Media Queries basierend auf dem Anfangswert der html-Element-font-size berechnet werden, der normalerweise 16px beträgt (und variieren kann).

Relative Einheiten in Media Queries basieren auf dem Anfangswert, was bedeutet, dass Einheiten niemals auf Ergebnissen von Deklarationen basieren. Zum Beispiel ist im HTML die em-Einheit relativ zum Anfangswert von 'font-size.

Wir können jedoch die Macht von Sass mixins nutzen, um dies zu umgehen! Hier ist, wie wir es machen werden.

  • Wir verwenden eine spezielle Klasse auf dem html-Element für jede Größe (font-size--s, font-size--m, font-size--l, font-size--xl, usw.)
  • Wir verwenden ein spezielles mixin, das für jede Kombination aus Breakpoint und Größe eine Media-Query-Regel erstellt und sowohl die Bildschirmbreite als auch die auf das html-Element angewendete Modifikator-Klasse berücksichtigt.
  • Wir werden den Code mit diesem mixin überall dort, wo wir eine Media-Query anwenden wollen, einwickeln.

So sieht dieses mixin aus.

$desktop: 640px;
$m: 1.5;
$l: 2;
$xl: 4;

// the main trick is here. We increase the min-width if we increase the font-size
@mixin media-desktop {
  html.font-size--s & {
    @media (min-width: $desktop) {
      @content;
    }
  }

  html.font-size--m & {
    @media (min-width: $desktop * $m) {
      @content;
    }
  }

  html.font-size--l & {
    @media (min-width: $desktop * $l) {
      @content;
    }
  }

  html.font-size--xl & {
    @media (min-width: $desktop * $xl) {
      @content;
    }
  }
}
.menu {
  @include media-desktop {
    &__mobile {
      display: none;
    }
  }
}

Und ein Beispiel für den CSS-Code, den es generiert.

@media (min-width: 640px) {
  html.font-size--s .menu__mobile {
    display: none;
  }
}
@media (min-width: 960px) {
  html.font-size--m .menu__mobile {
    display: none;
  }
}
@media (min-width: 1280px) {
  html.font-size--l .menu__mobile {
    display: none;
  }
}
@media (min-width: 2560px) {
  html.font-size--xl .menu__mobile {
    display: none;
  }
}

Wenn wir also n Breakpoints und m Größen haben, generieren wir n mal m Media-Query-Regeln, was alle möglichen Fälle abdeckt und uns die gewünschte Fähigkeit gibt, erhöhte Media-Queries zu verwenden, wenn die Schriftgröße erhöht wird.

Sehen Sie sich den Pen unten an, um zu sehen, wie es funktioniert.

Sehen Sie den Pen Font-switcher–right von Mikhail Romanov (@romanovma) auf CodePen.

Nachteile

Es gibt jedoch einige Nachteile. Sehen wir, wie wir damit umgehen können.

Erhöhte Spezifität von Media-Query-Selektoren.

Der gesamte Code innerhalb der Media Query erhält eine zusätzliche Spezifitätsebene, da er sich innerhalb des Selektors html.font-size — x befindet. Wenn wir also den Mobile-First-Ansatz verfolgen und beispielsweise den Modifikator .no-margin auf ein Element anwenden, kann der normale Desktop-Stil den Modifikator übertrumpfen und Desktop-Ränder werden angewendet.

Um dies zu vermeiden, können wir das gleiche mixin für mobile erstellen und nicht nur Desktop-, sondern auch mobile CSS-Code mit unseren mixins umschließen. Das wird die Spezifität ausgleichen.

Andere Wege sind, jeden Sonderfall mit einem individuellen Ansatz zu behandeln, indem die Spezifität künstlich erhöht wird, oder ein mixin mit der gewünschten Funktionalität (kein Rand in unserem Beispiel) zu erstellen und es nicht nur für mobile Geräte, sondern auch für jeden Breakpoint-Code einzufügen.

Erhöhte Menge an generiertem CSS.

Die Menge des generierten CSS wird höher sein, da wir für jede Größe den gleichen CSS-Code generieren.

Dies sollte kein Problem darstellen, wenn die Dateien mit gzip komprimiert sind (und das ist normalerweise der Fall), da es wiederholten Code sehr gut behandelt.

Einige Front-End-Frameworks wie Zurb Foundation verwenden integrierte Breakpoints in JavaScript-Utilities und CSS-Media-Queries.

Das ist schwierig. Persönlich versuche ich, die Funktionen eines Frameworks zu vermeiden, die von der Bildschirmbreite abhängen. Die wichtigste, die oft übersehen wird, ist ein Grid-System, aber mit dem Aufkommen von Flexbox und Grid sehe ich darin kein Problem mehr. Lesen Sie diesen großartigen Artikel für weitere Details, wie Sie Ihr eigenes Grid-System erstellen können: hier.

Aber wenn ein Projekt von einem solchen Framework abhängt oder wir uns nicht mit dem Spezifitätsproblem herumschlagen wollen, aber trotzdem AA erreichen wollen, dann würde ich in Erwägung ziehen, feste Höhenelemente abzuschaffen und rems zusammen mit der Änderung der html-Element-font-size zu verwenden, um das Layout und die Textabmessungen entsprechend zu aktualisieren.


Vielen Dank fürs Lesen! Lassen Sie mich bitte wissen, ob dies hilft und welche anderen Probleme Sie bei der Einhaltung der W3C-Barrierefreiheitsanforderung 1.4.4 Textgröße ändern hatten.