Blog

Core Web Vitals: wat INP écht meet, en hoe scheduler.yield() de hoofdthread redt

In het artikel over micro-interacties schreef ik dat transform en opacity animeren op de compositorthread, zodat zelfs een zware pagina de animatie van een knop niet hoeft te laten haperen. Dat klopt nog steeds – met één voorbehoud waar dat artikel over zweeg: als de hoofdthread geblokkeerd is door een lange JS-taak, krijgt de animatie misschien nooit de kans om te starten, omdat de klik-handler zelf in de wachtrij staat. INP is de metriek die precies dat gat meet – en scheduler.yield() is een van de weinige manieren om het echt te dichten.

content-visibility: offscreen renderen zonder lijstvirtualisatie

Een lijst van duizend reacties rendert traag, dus grijp je naar react-window – en in ruil voor soepel scrollen verlies je Ctrl+F, het afdrukken van de pagina en gedeeltelijk de navigatie van schermlezers, omdat elementen buiten het venster fysiek ophouden te bestaan in de DOM. content-visibility lost hetzelfde probleem anders op: de elementen blijven in de DOM, de browser slaat alleen het kostbare layout- en paintwerk ervoor over totdat ze dicht bij het zichtbare gebied komen – en, verrassend genoeg, kan ze tijdelijk weer tonen zodra je er tekst in zoekt.

Popover API en de native <dialog>: einde van modals die handmatig van nul worden gebouwd

In het artikel over toegankelijkheid was een modal met display:none, die nog steeds in de accessibility-boom stond, een voorbeeld van een fout die ontstaat door een modal van nul op te bouwen met divs. De echte vraag is: waarom moest hij überhaupt van nul worden opgebouwd? Ik zoek uit wat de native <dialog> en het popover-attribuut gratis bieden – top layer, focus trap, light dismiss – en waar deze twee mechanismen zo sterk verschillen dat ze door elkaar halen zo naar een ontoegankelijke interface leidt.

Optimistic UI in React: een interface die bewust liegt

De knop 'Vind ik leuk' reageert onmiddellijk, het hart vult zich, de teller loopt op – nog voordat de server ook maar heeft geantwoord. Dit is geen illusie van snelheid zoals in het artikel over micro-interacties, het gaat een stap verder: de interface toont een status die nog niet bestaat, en gaat ervan uit dat hij er zo aankomt. Ik zoek uit hoe je dit veilig bouwt – met een echte terugtrekking uit de leugen wanneer de aanname niet uitkomt – en waarom een handmatige setState plus catch een slechtere versie is van wat useOptimistic biedt.

CSS @layer: hoe cascade layers de oorlog om specificiteit beëindigen

De utility-klasse .mt-4 verliest het van de regel .card .card__header .card__title, ondanks dat ze logisch zou moeten winnen omdat ze later is toegevoegd. Dat is geen toeval – dat is specificiteit die precies doet waarvoor ze is ontworpen. @layer introduceert een compleet nieuwe as voor het oplossen van conflicten, die vóór specificiteit werkt, niet ernaast – met één valkuil zo contra-intuïtief dat zelfs een deel van de documentatie op het web hem verkeerd beschrijft.

Server Actions in Next.js: een formulier dat werkt voordat JavaScript is geladen

'use server' oogt als syntactische suiker voor een fetch naar een API-route – en precies daarom behandelen de meeste implementaties het als een gewone functieaanroep. Dat is een vergissing met concrete gevolgen: elke functie gemarkeerd met 'use server' wordt een publiek eindpunt op het netwerk, en een formulier dat op dit mechanisme is gebouwd, werkt zelfs voordat JavaScript de kans heeft gehad om te laden. Ik zoek uit wat er echt achter deze directive gebeurt, en waar de valkuilen zitten die je in de documentatie niet meteen ziet.

CSS :has() — de ouder die weet wat er binnenin gebeurt

Een formulierveld moet rood oplichten zodra de input erbinnen ongeldig is. Simpel genoeg – behalve dat CSS 25 jaar lang niet in staat was om een element te vragen wat er in zijn binnenste gebeurt, alleen andersom. Ik zoek uit hoe :has() die richting omdraait, hoe het verschilt van gewone combinators, en waar deze nieuwe kracht echt performance kost.

Container Queries: een component dat zijn eigen container kent, niet de viewport

Dezelfde productkaart ziet er in een grid geweldig uit en breekt in een smalle sidebar – ondanks zorgvuldig gekozen media queries. Het probleem zit niet in je code, maar in de vraag die een media query stelt: die gaat over de breedte van het scherm, niet over de ruimte die het component daadwerkelijk heeft gekregen. Ik zoek uit hoe container queries die vraag terugbrengen naar waar ze vanaf het begin had moeten liggen, en wat er echt onder de motorkap gebeurt zodra een element een 'query-container' wordt.

Toegankelijke componenten maken voor schermlezers

Correcte HTML is slechts het startpunt. Ontdek hoe de accessibility tree écht werkt, waarom ARIA vaker kwaad doet dan goed dan je zou denken, en bouw samen met mij een echte accordion, een live region en focusbeheer in Next.js.

Geanimeerde Micro-interacties in E-commerce

Twee webshops, hetzelfde product, dezelfde serverresponstijd - toch voelt de ene sneller en betrouwbaarder aan dan de andere. Het verschil zit in micro-interacties: een paar honderd milliseconden animatie die bepalen of een gebruiker vertrouwt wat er op zijn scherm gebeurt. Ik ontleed ze vanaf de grondbeginselen - het trigger/feedback-model, wat er in de render-engine van de browser daadwerkelijk gebeurt, en prefers-reduced-motion.