Im Artikel über Mikrointeraktionen schrieb ich, dass transform und opacity auf dem Compositor-Thread animiert werden, sodass selbst eine schwere Seite die Button-Animation nicht zum Stocken bringen sollte. Das stimmt weiterhin – mit einer Einschränkung, über die jener Artikel schwieg: Ist der Hauptthread durch eine lange JS-Aufgabe blockiert, bekommt die Animation womöglich nie die Chance zu starten, weil schon der Klick-Handler in der Warteschlange wartet. INP ist die Metrik, die genau diese Lücke misst – und scheduler.yield() ist eines der wenigen Mittel, sie wirklich zu schließen.
Eine Liste mit tausend Kommentaren rendert langsam, also greifst du zu react-window – und tauschst dafür flüssiges Scrollen gegen Strg+F, den Seitendruck und teilweise die Navigation von Screenreadern ein, weil Elemente außerhalb des sichtbaren Bereichs physisch aufhören, im DOM zu existieren. content-visibility löst dasselbe Problem anders: Die Elemente bleiben im DOM, der Browser überspringt für sie nur die teure Layout- und Malarbeit, solange sie nicht in der Nähe des sichtbaren Bereichs sind – und kann sie, überraschenderweise, vorübergehend wieder sichtbar machen, wenn du in ihnen nach Text suchst.
Im Artikel über Barrierefreiheit war ein Modal mit display:none, das trotzdem noch im Accessibility-Baum existierte, ein Beispiel für einen Fehler, der beim Bau eines Modals von Grund auf mit Divs entsteht. Die eigentliche Frage lautet: Warum musste man es überhaupt von Grund auf bauen? Ich schaue mir an, was das native <dialog> und das popover-Attribut kostenlos mitbringen – Top Layer, Fokusfalle, Light Dismiss – und wo sich diese beiden Mechanismen so sehr unterscheiden, dass eine Verwechslung schnell zu einer unzugänglichen Oberfläche führt.
Der „Gefällt mir"-Button reagiert sofort, das Herz füllt sich, der Zähler steigt – noch bevor der Server überhaupt geantwortet hat. Das ist nicht die Geschwindigkeitsillusion aus dem Artikel über Mikrointeraktionen, das geht weiter: Die Oberfläche zeigt einen Zustand, der noch nicht existiert, und nimmt an, dass er gleich existieren wird. Ich schaue mir an, wie man das sicher baut – mit einem echten Rückzug aus der Lüge, wenn sich die Annahme nicht bestätigt, und warum manuelles setState plus catch die schlechtere Variante dessen ist, was useOptimistic bietet.
Die Utility-Klasse .mt-4 verliert gegen die Regel .card .card__header .card__title, obwohl sie logisch gewinnen sollte, weil sie später hinzugefügt wurde. Das ist kein Zufall – das ist Spezifität, die exakt das tut, wofür sie entworfen wurde. @layer führt eine völlig neue Achse zur Konfliktlösung ein, die vor der Spezifität greift, nicht neben ihr – und hat eine Falle, die so unintuitiv ist, dass selbst ein Teil der Dokumentation im Netz sie falsch darstellt.
„use server" wirkt wie syntaktischer Zucker für einen fetch-Aufruf an eine API-Route – und genau deshalb behandelt die Mehrheit der Umsetzungen es wie einen gewöhnlichen Funktionsaufruf. Das ist ein Fehler mit konkreten Konsequenzen: Jede mit „use server" markierte Funktion wird zu einem öffentlichen Netzwerk-Endpunkt, und ein auf diesem Mechanismus aufgebautes Formular funktioniert sogar, bevor JavaScript überhaupt geladen ist. Ich schaue mir an, was hinter dieser Direktive tatsächlich passiert, und wo Fallen lauern, die man in der Dokumentation nicht auf den ersten Blick sieht.
Ein Formularfeld soll sich rot einfärben, wenn der Input darin ungültig ist. Klingt simpel – nur konnte CSS 25 Jahre lang ein Element nicht danach fragen, was in seinem Inneren passiert, sondern immer nur umgekehrt. Ich schaue mir an, wie :has() diese Richtung umkehrt, wie es sich von gewöhnlichen Kombinatoren unterscheidet und wo diese neue Macht die Performance wirklich kostet.
Dieselbe Produktkarte sieht im Grid großartig aus und bricht in der schmalen Sidebar zusammen – trotz sorgfältig gewählter Media Queries. Das Problem liegt nicht in deinem Code, sondern in der Frage, die eine Media Query überhaupt stellt: nach der Bildschirmbreite, nicht nach dem Platz, den die Komponente tatsächlich bekommen hat. Ich schaue mir an, wie Container Queries diese Frage dorthin verlagern, wo sie von Anfang an hingehört, und was unter der Haube wirklich passiert, wenn ein Element zum „Query-Container" wird.
Korrektes HTML ist nur der Ausgangspunkt. Erfahre, wie der Accessibility Tree wirklich funktioniert, warum ARIA öfter schadet als nützt, als man denkt, und bau mit mir ein echtes Akkordeon, eine Live-Region und Next.js-Fokus-Handling.
Zwei Shops, dasselbe Produkt, dieselbe Server-Antwortzeit – und trotzdem wirkt der eine schneller und vertrauenswürdiger. Der Unterschied liegt in Mikrointeraktionen: ein paar hundert Millisekunden Animation, die darüber entscheiden, ob Nutzer dem trauen, was sie auf dem Bildschirm sehen. Ich zerlege sie bis auf die Grundlagen – Trigger/Feedback-Modell, was im Rendering-Prozess des Browsers wirklich passiert, und prefers-reduced-motion.
CSS Houdini ist keine einzelne Technologie, sondern eine Sammlung von Spezifikationen mit sehr unterschiedlichem Reifegrad. Finden Sie heraus, welcher Teil davon heute produktionstauglich ist, wie @property und der Paint Worklet wirklich funktionieren – und warum der Rest weiterhin ein Experiment bleibt.