Weniger Code ist immer besser

Weniger Code ist immer besser (Foto von Etienne Girardet auf Unsplash)

Jetzt, wo der Support mit Sicherheitsupdates für den Internet Explorer 11 offiziell beendet ist und nur noch in Langzeit-Support-Umgebungen für Unternehmen eine Rolle spielt, ist der IE für den normalen Endnutzer endgültig tot. Alle übrigen Browser mit einem nennenswerten Marktanteil erhalten regelmäßig automatische Updates. Sogar Apple führt nun im Laufe des Jahres durch kleinere Safari-Updates die Unterstützung für neue Webfunktionen ein und stellt größere Safari-Updates auch für einige ältere macOS-Versionen zur Verfügung.

Für Webentwickler:innen heißt das, dass sie nur die letzten beiden Hauptversionen aller Browser unterstützen müssen und trotzdem sicher sein können, dass die große Mehrheit ihrer User abgedeckt ist. Natürlich ist es ratsam, die Browsernutzung Ihrer Nutzer:innen in Ihrem Analytics-Tool selbst zu überprüfen, bevor Sie die unternehmensrelevante Entscheidung treffen, den Support für bestimmte Browser einzustellen.

Mit neuen Versions-Updates unterstützen Browser regelmäßig neue Web-Funktionen, was oft zu Gedanken wie “Schön, das in fünf Jahren benutzen zu können, wenn es von allen Browsern unterstützt wird” führt. Der Zeitpunkt, an dem der übergreifende Browser-Support dann tatsächlich da ist, bleibt jedoch in der alltäglichen Menge von WebDev-News und neuen JavaScript-Frameworks oft unbemerkt. Wenn Sie also nicht regelmäßig die Changelogs aller relevanten Browser durchgehen, ist die Wahrscheinlichkeit groß, dass Sie Funktionen verpasst haben, die inzwischen problemlos verwendet werden können und sich dadurch das Leben schwerer machen, als es sein müsste.

Als ich kürzlich caniuse.com durchstöberte, war ich angenehm überrascht, welche Funktionen bereits durchgängig unterstützt werden, denn viele von ihnen können uns eine Menge Arbeit ersparen und maßgeschneiderte Lösungen für häufige Probleme, die bislang eine Menge Hacks, Workarounds oder Libraries erforderten, mit einem Einzeiler ersetzen. Cool! Schauen wir uns einige davon an.


Webfonts

Font-Formate

Erinnern Sie sich noch an Artikel wie die bulletproof font-face syntax? In den frühen 2010er Jahren waren bis zu fünf verschiedene Dateiformate nötig, um eigene Webfonts in allen gängigen Browsern anzuzeigen, und damit eine komplizierten Kette von Schriftdatei-URLs, die sich niemand merken konnte, so dass wir Tools nutzen mussten, um sie für uns zu erstellen. Irgendwann wurde dann einfach Google Fonts verwendet, das neben den Schriftdateien selbst auch das passende CSS für die Schriftart zur Verfügung stellt, je nachdem von welchem Browser der Request kommt.

Es gibt jedoch legitime Gründe, Ihre Web-Fonts selbst zu hosten, was zum Glück jetzt viel einfacher ist, da WOFF2, das wohl leistungsfähigste Web-Font-Format, jetzt von allen wichtigen Browsern unterstützt wird.

Browser Support-Tabelle für das WOFF 2.0 Format

Möglicherweise brauchen Sie auch nicht mehr unterschiedliche WOFF2-Dateien für verschiedene Schriftschnitte oder -stile, denn es gibt jetzt Variable Fonts, und sie werden auch von allen Browsern unterstützt.

Browser Support-Tabelle für Variable Fonts

Wenn Sie also bislang einen Webfont in drei Schnitten oder Varianten mit jeweils fünf Dateiformaten hatten, waren also 15 Font-Dateien plus CSS erforderlich, um diese korrekt zu laden. Jetzt brauchen Sie nur noch eine.

Laden von Webfonts

Selbst wenn wir uns nur um eine Font-Datei kümmern müssen, ist das immer noch eine zusätzliche Ressource, die vom Browser heruntergeladen werden muss. Vor ein paar Jahren war es noch nicht ohne Weiteres möglich zu kontrollieren, was beim Laden von Schriftarten passiert. Es war nicht ungewöhnlich, dass auf einer Webseite überhaupt kein Text zu sehen war, bis die Webfonts fertig heruntergeladen wurden (auch FOIT = Flash of Invisible Text genannt). Dies ist eine suboptimale User Experience und führt dazu, dass sich das Laden der Webseite insgesamt langsamer anfühlt als es tatsächlich ist.

ein Zeitstrahl, der den Flash of Invisible Text beim Laden von medium.com zeigt

FOIT auf medium.com (erstellt mit webpagetest.org)

Den Nutzer:innen fiel das negativ auf, und so entstanden mehrere Skripte von Drittanbietern, mit denen man das Ladeverhalten von Schriften steuern konnte. Dies bedeutete jedoch eine Menge blocking JavaScript-Code, den Sie in Ihre Seite einbetten mussten, was wiederum die Ladezeit Ihrer Seite erhöhte. Heute ist das alles nicht mehr nötig. Wir haben jetzt die font-display-Regel, die dem Browser mitteilt, wie er sich verhalten soll, bis ein Webfont geladen ist. Eine sinnvolle Voreinstellung ist font-display: swap, die sofort die Fallback-Schriftart anzeigt und dann zum Webfont wechselt, sobald dieser geladen wurde. Auf diese Weise kann man den Text auf der Seite so schnell wie möglich lesen.

Browser Support-Tabelle für die font-display-Regel

Verschiedene Schriftfamilien haben unterschiedliche Buchstabenbreiten, so dass es zu einer Verschiebung des Inhalts kommen kann, wenn die Schriftart gewechselt wird. Um dies zu verhindern, können wir die Fallback-Schriftgröße mit CSS so genau wie möglich an unseren Webfont anpassen. Font Style Matcher ist eine sehr nützliche Webseite, mit der man Schriftarten schnell und einfach visuell aufeinander abstimmen kann.

Nun müssen wir aber wissen, wann das Laden unseres Webfonts abgeschlossen ist, um die Größenanpassung für den Fallback-Font zu entfernen. Es gibt jetzt eine native Font Loading API, die uns mitteilt, wann ein Font fertig geladen ist. Auf diese Weise können wir ein nutzerfreundliches Verhalten beim Laden von Schriftarten mit nur wenigen Codezeilen implementieren:

// in Ihrem JavaScript:
await document.fonts.ready;
document.body.classList.add('font-loaded');
// in Ihrem CSS:

@font-face {
  font-family: 'MyFont';
  src: url('fonts/my-font.woff2') format('woff2-variations');
  font-weight: 400 700;
  font-display: 'swap';
}

body {
  font-family: 'MyFont', Arial, sans-serif;
}

body:not(.font-loaded) {
  /* passt die Schriftart Arial an, um eine Textblockgröße ähnlich der
      von "MyFont" zu erhalten, um Sprünge im Layout zu vermeiden, wenn
     "MyFont" fertig geladen wurde */
  letter-spacing: -0.05em;
  word-spacing: 0.02em;
}

Browser Support-Tabelle für die FontFaceSet API


Laden und Anzeigen von Bildern

Bilder sind meist die Ressourcen, die den größten Teil des Traffics zur Anzeige einer Webseite ausmachen. Je nach Bildgröße und Geschwindigkeit der Internetverbindung kann es einige Zeit dauern, bis alle Bilder vollständig heruntergeladen sind.

Eine unschöne Eigenschaft von Bildern im Web ist, dass der Browser die Größe eines Bilds erst dann kennt, wenn die Header des Bilds heruntergeladen wurden. Wenn Sie die Bildgröße nicht manuell per CSS angeben, hat das Bild eine Höhe von Null bis seine Abmessungen bekannt sind, was dazu führen kann, dass Teile der Seite plötzlich nach unten springen, wenn die darüber liegenden Bilder geladen werden. Dieser so genannte “Cumulative Layout Shift” sorgt für eine schlechte User Experience und kann sogar dazu führen, dass User auf etwas ganz anderes klicken, als sie eigentlich wollten, wenn sich zwischen dem Drücken und Loslassen der Maustaste Teile der Seite verschoben haben (Nicken Sie jetzt im Geiste, falls Sie sich schon einmal darüber geärgert haben).

Beim Laden von Bildern müssen wir im Allgemeinen vier Dinge beachten:

  1. Es sollten nur Bilder geladen werden, die im Viewport sind oder bald sichtbar werden, um keinen Traffic zu verschwenden (sogenanntes Lazy Loading)
  2. Die Bilder sollten nur in der Größe heruntergeladen werden, in der sie angezeigt werden
  3. Das Bild wird in der richtigen Größe für den aktuellen Viewport angezeigt
  4. Beim Herunterladen eines Bilds sollte es keine Sprünge auf der Seite geben

Für das Lazy-Loading von Bildern fügten Webentwickler:innen früher eigenen JavaScript-Code ein, der regelmäßig prüfte, wann ein Bild im Viewport sichtbar wurde, um erst dann die URL der Bildquelle festzulegen, so dass die Browser mit dem Herunterladen des eigentlichen Bildes begannen.

Heutzutage fügt man einfach das Attribut loading="lazy" zum Image-Tag hinzu. Es ist kein JavaScript mehr erforderlich.

Browser Support-Tabelle für das "loading"-Attribut

Der Partial Support bezieht sich auf die fehlende Unterstützung für das Lazy-Loading von Iframes; das Lazy-Loading von Bildern wird auch in Firefox und Safari unterstützt.

Um ein Springen der Seite beim Herunterladen eines Bilds zu vermeiden, kann seine Größe vorab manuell festgelegt werden, vorausgesetzt sie ist bekannt. In responsiven Designs wollen wir die Größe von Bildern oft basierend auf der Größe des Viewports festlegen, z.B. auf 100% der Breite des Content-Bereichs unter Beibehaltung des Seitenverhältnisses. Eine Skalierung unter Berücksichtigung des Seitenverhältnisses war bis vor kurzem nicht so einfach zu erreichen.

Mit CSS konnte dies mit einem Hack erreicht werden, der die Tatsache ausnutzt, dass sich ein prozentualer Padding-Wert immer auf die Breite eines Elements bezieht, auch wenn das Padding auf der vertikalen Achse angewendet wird. Dadurch konnte man die Größe eines Bildes wie folgt festlegen, sodass das Verhältnis 16 zu 9 erhalten bleibt:

width: 100%;
height: 0;
padding-top: 56.25%; /* 9 / 16 * 100 */

Die Höhe von Null und das Padding konnten jedoch in Kombination mit anderen Stilen Probleme verursachen, so dass dies nie eine wirklich gute Lösung war.

Heute können wir einfach die Eigenschaft aspect-ratio verwenden:

width: 100%;
aspect-ratio: 16 / 9;

Das ist deutlich einfacher zu lesen und zu verstehen und hat auch noch weniger Begleiterscheinungen. Super!

Browser Support-Tabelle für die Eigenschaft "aspect-ratio"

Aspect-Ratio wird in Safari seit v15 unterstützt, die Caniuse-Tabelle scheint hier nicht aktuell zu sein.

Bei manchen responsiven Layouts wollen wir ein Bild vielleicht in einem anderen als seinem ursprünglichen Seitenverhältnis anzeigen. Das war lange Zeit mit <img>-Tags nicht möglich, da das Bild sonst gestreckt oder verzerrt dargestellt wurde. Entwickler:innen nutzten stattdessen einfach Divs und setzten das Bild als Hintergrund, dessen Darstellung mit den Attributen background-size und background-position gesteuert werden konnte. Hinsichtlich der Semantik und Barrierefreiheit ist dies jedoch keine gute Lösung für Bilder, die Content der Seite und nicht nur Dekoration sind.

Heute können wir für Bilder einfach die Eigenschaften object-fit und object-position setzen, um das gleiche Verhalten zu erreichen.

Browser Support-Tabelle für die Eigenschaft "object-fit"

Auch bei den Bildformaten hat es einige Fortschritte gegeben. Während das <picture>-Element schon seit langem unterstützt wird, um das am besten geeignete Bildformat für den Browser zu laden, gibt es zwei Bereiche, in denen fast altertümliche Bildformate im heutigen Web immer noch weit verbreitet sind: Favicons und animierte Bilder.

Das favicon.ico ist ein Relikt, das wir anscheinend kaum loswerden können. Nicht nur ist das ICO-Format in seinen Möglichkeiten sehr begrenzt (begrenzte Farbpalette, keine Alpha-Transparenz), auch die Komprimierung ist sehr schwach. Viele Favicon-Generatoren erzeugen .ico-Dateien, die alle Größenvarianten des Favicons zusammen enthalten: 16x16px, 32x32px und 48x48px. Das kann manchmal eine Datei von bis zu 100 KB Größe erzeugen, nur um ein winziges Icon darzustellen. Welche Favicon-Formate heutzutage wirklich noch benötigt werden, wird unter Entwickler:innen ziemlich regelmäßig diskutiert, oft mit unterschiedlichen Ergebnissen.

Ein kurzer Test meinerseits mit allen aktuellen Browsern hat gezeigt, dass alle ein 32x32px großes PNG-Favicon einwandfrei anzeigen. Das sollte alles sein, was wir brauchen, wenn wir keine exotischen Clients unterstützen müssen. Dadurch haben wir eine viel kleinere Datei mit besserer Bildqualität als die gute alte ICO-Datei und wir müssen uns nicht auf Drittanbieter-Webseiten verlassen, um mehrere Favicon-Dateien für uns zu generieren.

Browser Support-Tabelle für PNG Favicons

Wenn Sie großen Wert auf die Bildqualität legen, können auch SVG-Favicons sehr nützlich sein, da sie sich durch ein wenig CSS in der SVG-Datei adaptiv an einen Dark Mode anpassen können. Leider werden sie von Safari erst ab Version 16 unterstützt, die noch nicht sehr weit verbreitet ist.

Browser Support-Tabelle für SVG Favicons

Für animierte Bilder gibt es seit langem das GIF-Format (oder wird es JIF ausgesprochen? 😜), aber wie ICO ist das Format in vielerlei Hinsicht stark limitiert: es hat eine geringe Farbtiefe, keine Alpha-Transparenz und eine begrenzte Dauer und Framerate.

Sowohl APNG als auch WebP sind deutlich bessere Alternativen, die beide von allen Browsern unterstützt werden. Sogar Giphy (trotz seines Namens) liefert jetzt standardmäßig WebP-Dateien in allen wichtigen Browsern aus. Die Tools zur Erzeugung dieser modernen Bildformate sind seltener als zur GIF-Erstellung, aber sie existieren.

Browser Support-Tabelle für das APNG-Format

Browser Support-Tabelle für das WebP-Format

Sofern Sie nicht gerade Video-Footage in animierte Bilder umwandeln wollen, könnten auch SVG-Animationen eine gute Option mit einer potentiell viel kleineren Dateigröße sein.


Scroll-Effekte

Irgendwann in den 2010er-Jahren wurden Scroll-Effekte auf vielen Webseiten en vogue, vor allem auf Marketing-Websites wie Agentur-Websites oder Produktseiten, welche jeweils eine Menge Teaser anzeigten, die den Viewport ausfüllten, während sie das native Scroll-Verhalten außer Kraft setzten und es den Nutzer:innen nur erlaubten, den vorherigen oder nächsten Teaser in den Viewport zu scrollen. Ähnlich, aber weniger nervig waren Content-Slider auf vielen Websites, die jeweils nur einen einzelnen Inhalt anzeigten und durch die man (oft horizontal) navigieren konnte, um neue Inhalte herein- und die vorherigen Inhalte wegzuschieben.

Da es nie eine Standardimplementierung für beide Patterns gab, entstanden viele verschiedene, oft fehlerbehaftete oder schwerfällige Implementierungen, die jede Menge eigenen JavaScript-Code oder aufgeblähte Libraries verwendeten.

Grundsätzlich sollten Sie es unterlassen, das native Scrollverhalten zu überschreiben und den Usern die Möglichkeit zu nehmen, frei zu scrollen, aber wenn sie es tun müssen, können Sie jetzt die CSS Scroll Snap-Attribute dafür nutzen, mit denen Sie festlegen können, zu welchem Teil eines Elements gescrollt werden soll und ob die Scrollposition immer auf dem Element einrasten soll oder nur dann, wenn der Benutzer in die unmittelbare Nähe des Elements gescrollt hat.

Browser Support-Tabelle für das CSS Scroll Snap-Feature

Auch Content-Slider lassen sich mit dieser Technologie einfacher realisieren.

Eine weitere Funktion, die man regelmäßig braucht, ist das animierten Scrollen zu einem bestimmten Punkt der Website nach einer Nutzerinteraktion, z.B. nach dem Drücken eines “zurück zum Seitenanfang”-Buttons. Dies kann nun leicht mit einer Zeile Code mit Element.scrollIntoView() erreicht werden:

document.body.scrollIntoView({ block: 'start', behavior: 'smooth' });

Beachten Sie, dass Smooth Scrolling in Safari erst ab Version 16 unterstützt wird. In früheren Versionen wird auch zum Ziel gescrollt, es wird aber nicht animiert.

Browser Support-Tabelle für die Methode "scrollIntoView"


Seitenlayout

Gaps in Flex Layouts

Glücklicherweise müssen wir uns seit Flex- und Grid-Layouts keine Gedanken mehr darüber machen, wie man die Elemente einfach zentriert, aber einige Dinge waren bisher weiterhin ziemlich schwierig.

Einheitliche Abstände zwischen Elementen in einem Flex-Layout konnten sich als nervig erweisen, insbesondere in responsiven Layouts, in denen Elemente in manchen Viewports umbrechen können. Eine recht flexible Möglichkeit bestand darin, einheitliche Margins in alle Richtungen auf die Flex-Elemente anzuwenden. Dies würde jedoch auch einen Abstand zum Rand des Containers erzeugen, was oft unerwünscht ist, so dass negative Margins auf den Container angewandt werden mussten, um die Margins der Flex-Elemente visuell auszugleichen. Dies wiederum könnte jedoch zu Problemen mit dem Parent-Element des Flex-Containers führen.

Im CSS Grid Layout wurde später die Eigenschaft gap eingeführt, die dieses Problem löste, da sie Abstände nur zwischen den Grid-Elementen, nicht aber am Anfang und Ende der Grid-Achsen hinzufügte. Manchmal ist die Verwendung von Grids für einfache Layouts ein wenig übertrieben, zum Glück hat die Eigenschaft gap inzwischen aber auch im Flexbox-Layout browserübergreifend Einzug gehalten.

Browser Support-Tabelle für die gap Eigenschaft in FlexBox-Layouts

Intrinsische Elementgrößen

Eine weitere Verbesserung, die mit dem CSS Grid Layout eingeführt wurde und nun auch außerhalb davon verfügbar ist, sind Intrinsische Elementgrößen. Dieser etwas komplizierte Begriff bedeutet, dass Sie jetzt die Abmessungen eines Elements auf die Größe einstellen können, die sein Inhalt einnimmt. Schauen wir uns das anhand der width-Eigenschaft an:

  • width: max-content ist die Breite, die der Inhalt einnehmen würde, ohne in mehrere Zeilen umzubrechen
  • width: min-content ist die Mindestbreite, die der Inhalt inklusive Umbrüchen einnehmen kann, was in der Regel der Breite des längsten Worts entspricht (wenn die Silbentrennung deaktiviert ist)
  • width: fit-content verwendet die jeweils kleinere Breite aus “max-content” und der Breite des Containers

Dies ist besonders nützlich, wenn Sie wiederverwendbare Komponenten mit variablem Inhalt erstellen, dessen Länge Sie im Voraus nicht kennen können.

Browser Support-Tabelle für CSS Intrinsic Sizing

min/max/fit-content werden auch in Firefox und Safari unterstützt, Limited Support bezieht sich auf andere Werte

Richtungsabhängige Größen und Abstände

Wenn Sie schon einmal an einem internationalisierten Produkt gearbeitet haben, das Sprachen mit unterschiedlichen Textrichtungen unterstützen muss, wissen Sie, dass CSS-Layouts dadurch viel komplizierter werden. Angenommen, Sie haben einen Button mit einem Textlabel und einem optionalen Icon vor dem Label und möchten einen kleinen Abstand zwischen Icon und Textlabel einfügen.

Wenn Sie nicht die gap-Eigenschaft in Grid- oder Flex-Layouts nutzen können und stattdessen margin and padding verwenden müssen, würde die Verwendung von margin-right für das Icon scheinbar ausreichen, aber das gilt nur für Sprachen wie Deutsch, die erst von links nach rechts und dann von oben nach unten gelesen werden. Bei arabischem Text, der von rechts nach links und dann oben nach unten gelesen wird, würde das Icon rechts vom Label erscheinen, so dass der Abstand auf der falschen Seite wäre. Bei Japanisch, das erst von oben nach unten und dann rechts nach links gelesen wird, wäre es nochmal anders.

Man könnte die Richtung der Margins für die verschiedenen Sprachen überschreiben, aber das für jedes Element zu tun, erhöht die Komplexität des Codes enorm. Zum Glück gibt es jetzt CSS-Eigenschaften, die die Textrichtung berücksichtigen:

margin-inline-start und margin-inline-end funktionieren in der Hauptleserichtung des Textes, d.h. in einer links nach rechts, dann oben nach unten-Sprache wie Deutsch würden sie margin-left und margin-right entsprechen. Umgekehrt funktionieren margin-block-start und margin-block-end auf der anderen Achse, sie würden also margin-top und margin-bottom im Deutschen entsprechen. Somit braucht man nichts mehr zu überschreiben, da sich die Abstände automatisch an die Leserichtung anpassen, z.B. wäre margin-inline-start gleichbedeutend mit margin-top anstelle von margin-left im Japanischen.

Für die Größe von Elementen gibt es ähnliche Attribute: inline-size und block-size können die Eigenschaften width bzw. height ersetzen.

Browser Support-Tabelle für die Eigenschaft "margin-block-start"

Environment-Variablen

Als Apple 2017 das erstes iPhone mit einer Notch vorstellte, erzeugte das die Herausforderung, dass die Notch Teile einer Webseite verdecken konnte, wenn diese im Vollbildmodus im Querformat angezeigt wurde. Standardmäßig verkleinerte Apple den Viewport im Querformat einfach horizontal, gab aber Entwickler:innen die Möglichkeit, mit einem speziellen Viewport-Meta-Tag den gesamten Platz des Displays zu nutzen. Um die Notch zu berücksichtigen, führte Apple CSS-Konstanten ein, um die Einzüge für den sicheren Bereich innerhalb des Viewports bereitzustellen, der nicht verdeckt wird.

die mobile YouTube-Webseite berücksichtigt den Bereich der Dynamic Island auf dem iPhone 14 Pro Max-Simulator

die YouTube-Webseite nutzt den gesamten Viewport mit Safe Areas für die Dynamic Island und die App-Switcher-Leiste

Daraus hat sich der offizielle CSS Environment Variables-Standard entwickelt, der inzwischen von allen wichtigen Browsern unterstützt wird. Er kann auch für Progressive Web Apps verwendet werden, die auf Desktop-Computern in einem eigenen Fenster gestartet werden, um die Fenstersteuerungs-Buttons in der Titelleiste zu berücksichtigen.

Browser Support-Tabelle für CSS Environment Variables


Fazit

Wir haben uns mit einigen neuen Webfunktionen in den Bereichen Webfonts, Bildoptimierung, Scroll-Effekte und Seitenlayouts vertraut gemacht, die seit kurzem browserübergreifend unterstützt werden und nun problemlos in Webprojekten eingesetzt werden können.

Ich hoffe, dass diese Tipps nützlich waren und Ihnen helfen, bei Ihrem nächsten Projekt einige Probleme schneller und mit weniger Code zu lösen.

Da der Artikel bereits ziemlich lang geworden ist, konnte ich keine weiteren HTML- und CSS-Neuerungen mit aktueller Cross-Browser-Unterstützung aufnehmen, insbesondere neue CSS-Selektoren, Formularelemente und Theming-Möglichkeiten, die eventuell Teil eines weiteren zukünftigen Artikels werden.