De 10 meest voorkomende fouten van AI bij webontwikkeling

Gepubliceerd: 11 november 2026

Deze week hebben we versie 1.0 van Modern Web Guidance uitgebracht, een set vaardigheden die expertise over webplatforms, best practices en gegevens over browsercompatibiliteit rechtstreeks in je programmeeragents inbedden. Ons doel met Modern Web Guidance is om ontwikkelaars die AI-coderingagents gebruiken, te helpen de kracht en mogelijkheden van het moderne webplatform optimaal te benutten en uiteindelijk de webervaring voor gebruikers te verbeteren.

Sinds we in mei onze vroege preview van Modern Web Guidance introduceerden, zijn programmeeragents steeds beter geworden en zijn er veel geweldige nieuwe frontiermodellen uitgebracht. Een van de vragen die we het vaakst horen, is: Volgen deze nieuwe frontiermodellen niet al de best practices voor webontwikkeling?

Helaas is het antwoord 'nee'. En we weten dat het antwoord 'nee' is omdat we het testen.

Elke gids in Modern Web Guidance definieert een reeks verwachtingen die waar moeten zijn als de best practices in de gids op de juiste manier zijn gevolgd. Onze evaluatiesuite test die handleidingen vervolgens door dezelfde prompt te geven aan een agent die wordt uitgevoerd met Modern Web Guidance geïnstalleerd (de begeleide agent) en een andere agent die wordt uitgevoerd zonder Modern Web Guidance geïnstalleerd (de niet-begeleide agent). De uitvoer van beide uitvoeringen wordt gecontroleerd aan de hand van de verwachtingen die in de handleiding zijn gedefinieerd.

Als je de slagingspercentages met en zonder begeleiding vergelijkt, zie je dat AI-modellen, zelfs de nieuwste frontiermodellen, niet zelfstandig de best practices voor moderne webontwikkeling volgen.

Gemiddeld slagen niet-begeleide programmeeragents voor slechts ongeveer 50% van de controles in onze evaluatiesuite, vergeleken met ongeveer 90% wanneer Modern Web Guidance wordt gebruikt.

Horizontaal staafdiagram waarin de gemiddelde slagingspercentages van evaluatiecontroles worden vergeleken voor geavanceerde programmeeragents (per 9 november 2026): 52% zonder Modern Web Guidance versus 91% met Modern Web Guidance.

In ons evaluatiedashboard vind je de volledige lijst met specifieke controles die we voor elke gids uitvoeren en hoe elk model daarop scoort.

In deze post geven we een overzicht op hoog niveau van 10 van de meest problematische gebieden waar AI-modellen consequent de fout in gaan, binnen belangrijke disciplines die webontwikkelaars het meest tegenkomen in hun dagelijkse werk, zoals toegankelijkheid, gebruikerservaring, prestaties en beveiliging.

1. Toegankelijkheid: toetsenbordfocus en inert-beheer

Voor mensen die navigeren met een toetsenbord of schermlezer, is een voorspelbare focusvolgorde wat interactieve UI's bruikbaar maakt. Zonder deze functie kan de focus afdwalen naar verborgen achtergrondcontent of vastlopen in tientallen extra tabstops.

Focus- en inert-beheer is een van de grootste toegankelijkheidskloven in onze evaluaties en een van de gebieden die het meest verbeteren met Modern Web Guidance. Dit zijn de meest voorkomende fouten:

  • De focus niet verplaatsen naar nieuw geopende weergaven en vergeten de focus te herstellen naar het activerende element als je terugnavigeert.
  • Vertrouwen op handmatige JavaScript-tabtraps en aria-modal="true" op aangepaste modale vensters, in plaats van een modaal venster <dialog> te gebruiken of achtergrondcontent te markeren inert.
  • Elk item in een werkbalk of richtingsraster weergeven als een afzonderlijke tabstop in plaats van één tabstop te gebruiken met een bewegende tabindex.
  • Aangepaste :focus-visible-contouren maken die geen contrastverhouding van 3:1 hebben met aangrenzende achtergronden.

2. Toegankelijkheid: ondersteuning voor minder beweging

Onverwachte paginabewegingen en grootschalige animaties zijn niet alleen afleidend, maar kunnen bij gebruikers met vestibulaire stoornissen of bewegingsgevoeligheid ook duizeligheid, misselijkheid of hoofdpijn veroorzaken.

AI-modellen onthouden meestal om te controleren op prefers-reduced-motion als ze standaard css-overgangen of keyframe-animaties toevoegen. Maar als ze nieuwere functies gebruiken, zoals vloeiend scrollen, weergaveovergangen of scrollgestuurde animaties, vergeten ze vaak de verminderde beweging of maken ze fouten bij de implementatie:

  • scroll-behavior:smooth wereldwijd en onvoorwaardelijk instellen voor het hoofdelement.
  • Scrollgestuurde CSS-animaties gebruiken zonder controle op verminderde beweging.
  • transition duur van carrouselitems verwijderen om minder beweging mogelijk te maken tijdens het scrollen, maar dan vergeten ook transformatie-eigenschappen te verwijderen, waardoor items tijdens het scrollen van grootte veranderen.
  • Een algemene reset van de duur van 0.01ms op *, *::before en *::after toepassen als verminderde beweging actief is, waardoor ook alle essentiële overgangen zonder beweging worden gewist (nodig om wijzigingen in de UI-status te communiceren).
  • Weergaveovergangen tussen documenten onvoorwaardelijk aanzetten en ::view-transition-*-animaties overschrijven als minder beweging actief is, in plaats van de @view-transition-regel alleen te beperken tot een controle op minder beweging.

3. Toegankelijkheid: formuliervalidatie, opmaaktips en statussen voor automatisch invullen

Formulieren zijn een hoeksteen van de meest kritieke gebruikerstrajecten op internet. Een klein probleem in een betaalformulier kan een grote impact hebben op de resultaten van een bedrijf.

AI-modellen kunnen de basisbeginselen van formulieren goed opzetten. Ze gaan vaak de mist in met kleine maar cruciale details, zoals validatiefouten, de juiste plaatsing van tijdelijke aanduidingen en opmaaktips, en de juiste integratie met wachtwoordmanagers en functies voor automatisch invullen:

  • CSS :user-invalid opnieuw implementeren met aangepaste JavaScript blur-validatie, die vaak onaangeraakte required-velden markeert zodra gebruikers er voorbij tabben.
  • aria-invalid niet meer synchroniseren met zichtbare fouten, aria-invalid="true" voortijdig instellen op blur of :user-invalid stylen in CSS zonder aria-invalid te synchroniseren in JavaScript.
  • Vertrouwen op verdwijnende placeholder-tekst om vereiste indelingen te tonen (zoals MM/YY bij een invoerveld voor de vervaldatum van een kaart) in plaats van een permanente hint te tonen die is gekoppeld aan aria-describedby.
  • Indelingshints en wachtwoordregels onder de <input> (in plaats van erboven) plaatsen, waar ze kunnen worden verborgen door mobiele toetsenborden en pop-overs voor automatisch invullen, net wanneer de gebruiker ze moet lezen.
  • :autofill invoervelden worden gemarkeerd door alleen de randkleur te wijzigen in plaats van de kleur te combineren met een niet-kleurige aanwijzing die de vormgeving niet verschuift (zoals een inzet box-shadow).

4. Gebruikerservaring: swipe- en aanraakgebaren

Agents zijn goed in het implementeren van aanraakgebaren met imperatieve JavaScript en het schrijven van hun eigen aangepaste fysicalogica. Deze implementaties werken, maar de op JavaScript gebaseerde aanraakinteracties voelen zelden zo soepel aan als gebruikers gewend zijn van systeemeigen apps.

Veel van deze interacties kunnen worden geïmplementeerd met CSS en native scroll-API's, zodat de browser de fysica van gebaren buiten de hoofdthread kan uitvoeren. In onze evaluaties zien we dat AI-modellen deze functies vaak over het hoofd zien:

  • Gebaren voor swipen om te sluiten of swipen om te tonen implementeren met pointermove- of touchmove-listeners in plaats van CSS Scroll Snap te gebruiken.
  • overscroll-behavior-x:none weglaten in interfaces met tabbladvegen, die per ongeluk een terug- of vooruitnavigatie van de browser kunnen activeren tijdens een over-swipe.
  • Swipe-voortgangseffecten op de hoofdthread in JavaScript-callbacks aansturen in plaats van scrollgestuurde animaties te gebruiken.
  • Toetsenbordfocus wordt niet goed ondersteund in op scrollen gebaseerde veegactievensters.

5. Gebruikerservaring: dialoogvensters, pop-overs en overgangen op de bovenste laag

In onze evaluaties vallen modellen vaak terug op imperatieve JavaScript-workarounds bij het animeren, sluiten of beperken van scrollen rond modale dialoogvensters en popovers.

In plaats van te vertrouwen op moderne HTML- en CSS-functies die zijn gemaakt voor overlays op de bovenste laag, maken agents vaak handmatig invoer- en uitvoerstatemachines, geschiedenishooks en scrollvergrendelingen voor de hoofdtekst die moeilijker te onderhouden zijn en gevoelig zijn voor subtiele UI-bugs.

Als je deze interacties goed uitvoert, kan een kwetsbare ervaring worden omgezet in een verfijnde ervaring die gebruikers vertrouwen. Dit zijn de meest voorkomende fouten die we tegenkomen:

  • Aangepaste position:fixed-overlays maken met handmatige click-outside-handlers voor licht sluiten, in plaats van alleen popover te gebruiken.
  • Maak animaties voor binnenkomst en vertrek door css-overgangsklassen aan en uit te zetten en te coördineren met requestAnimationFrame()- en transitionend-listeners (met setTimeout()-fallbacks), in plaats van dit in pure css te doen met @starting-style en transition-behavior.
  • Het scrollen op de pagina vergrendelen achter een open modaal door overflow:hidden in te stellen op <html> in plaats van een <dialog>-element te gebruiken om overscroll te bevatten.
  • popstate-listeners toevoegen om Android-terugbewegingen te detecteren en open modale elementen te sluiten, in plaats van de systeemeigen sluitfunctionaliteit van de terugknop van een modaal <dialog>-element te gebruiken.

6. Gebruikerservaring: Donkere modus en thema-aanpasbare bedieningselementen

Gebruikers zetten de donkere modus aan om vermoeide ogen en schittering te verminderen. Een felle witte flits bij het laden van de pagina, formulieropties zonder thema of een schakelaar die niet synchroon loopt met de OS-voorkeur ondermijnt de gebruikerservaring onmiddellijk.

Een schakelaar voor de donkere modus lijkt misschien eenvoudig, maar ongestuurde modellen in onze evaluaties missen consequent belangrijke platformdetails die nodig zijn om thema's te wisselen en systeemeigen formulierbedieningselementen goed te krijgen:

  • <meta name="color-scheme" content="light dark"> ontbreekt in de <head>, waardoor gebruikers in de donkere modus een wit canvas zien flitsen terwijl externe stylesheets worden geladen.
  • Donkere thema's of componenten met een donkere achtergrond stylen met aangepaste kleuren zonder color-scheme in te stellen, waardoor systeemeigen schuifbalken en formulierbedieningselementen vast blijven zitten in de lichte modus.
  • De CSS-functie light-dark() over het hoofd zien bij het definiëren van thema-adaptieve kleurtoken die automatisch de actieve color-scheme volgen.
  • Alleen een binaire schakelaar voor licht of donker bieden die een expliciete overschrijving instelt in localStorage zonder optie om terug te keren naar de standaardinstelling van het OS.
  • Vergeten een storage-gebeurtenislistener toe te voegen, waardoor andere open tabbladen niet worden gesynchroniseerd als de gebruiker van thema wisselt.

7. Prestaties: Responsiviteit en soepelheid tijdens de runtime

Gebruikers brengen de meeste tijd door op een webpagina nadat deze is geladen. Trage interacties en haperende overgangen kunnen de gebruikerservaring net zo veel schaden als een langzame eerste keer laden.

In onze evaluaties volgen modellen over het algemeen de klassieke best practices voor laadtijd die al jaren worden gepromoot in tools zoals Lighthouse. Ze weten meestal ook dat ze voor de hand liggende zware loops moeten overdragen aan een Web Worker. Waar ze consequent moeite mee hebben, is de reactiesnelheid van de hoofdthread, wat essentieel is voor de optimalisatie van INP: isoleren van opmaakwerk, taken plannen op prioriteit en gebruikmaken van nieuwe HTML- en CSS-functies die weergavewerk buiten de hoofdthread uitvoeren.

We zien bijvoorbeeld vaak dat makelaars:

  • Aangepaste setTimeout()-wachtrijen implementeren voor achtergrondwerk of werk met een lage prioriteit in plaats van prioriteit te geven aan voor de gebruiker zichtbare taken met scheduler.postTask() of gebruik te maken van taakvoortzetting met scheduler.yield() als de browser dit ondersteunt.
  • Complexe lay-outs (zoals dichte gegevensrasters) bouwen zonder content-visibility:auto en contain-intrinsic-size toe te passen, wat betekent dat updates na gebruikersinteracties een herstroom van de hele pagina activeren.
  • Inactieve SPA-weergaven verbergen met display:none (of ze verwijderen) in plaats van content-visibility:hidden te gebruiken (gekoppeld aan inert). De eerste optie vernietigt de gecachte weergavestatus, dus als je terugschakelt, worden de volledige vormgeving en weergave geactiveerd.
  • <canvas>-animaties buiten het scherm en achtergrondloops worden onderbroken met Intersection Observer-callbacks in plaats van content-visibility:auto te koppelen aan de gebeurtenis contentvisibilityautostatechange (indien beschikbaar). Hierdoor ontbreekt de prerender-marge van de browser voordat elementen in beeld worden gescrold.
  • UI-hints voor scroll-affordance maken met scroll-gebeurtenislisteners die continue opmaakberekeningen afdwingen, in plaats van CSS-scrollstatusquery's te gebruiken als deze beschikbaar zijn (met Intersection Observer-fallbacks).

8. Prestaties: Indelingsverschuivingen en visuele flikkering

Onverwachte verschuivingen in de indeling verstoren de focus van een lezer en kunnen ertoe leiden dat gebruikers op onverwachte knoppen klikken, soms met onomkeerbare gevolgen.

Modellen voegen op betrouwbare wijze de kenmerken width en height toe aan standaard <img>-elementen om verschuivingen in de vormgeving te voorkomen, maar ze missen consequent andere veelvoorkomende bronnen van verschuivingen in de vormgeving en pre-paint-flitsen van <video>-elementen, weblettertypewisselingen, werkbalken van mobiele browsers en experimenten aan de clientzijde. Al deze elementen kunnen van invloed zijn op de CLS.

  • Expliciete width- en height-kenmerken weglaten voor <video>-elementen (zodat niet-geladen spelers standaard 300×150 zijn en de indeling verschuiven zodra metadata worden geladen) of mediawrapper-elementen opmaken in plaats van aspect-ratio en object-fit rechtstreeks in te stellen voor media-elementen.
  • Weblettertypen koppelen aan reservelettertypen van het systeem zonder font-size-adjust, waardoor alinea's en koppen zichtbaar opnieuw worden ingedeeld als weblettertypen worden gewisseld.
  • De grootte van hero-secties en indelingen op volledig scherm worden bepaald met statische vh-eenheden in plaats van dynamische of kleine viewport-eenheden (dvh, svh), waardoor content verspringt als de werkbalken van mobiele browsers worden uitgevouwen en ingetrokken.
  • Content verbergen met verouderde opacity:0- of visibility:hidden-fragmenten tegen knipperen en time-outs van meerdere seconden voor A/B-tests aan de clientzijde (waardoor LCP wordt vertraagd en onzichtbare elementen klikbaar blijven), in plaats van scripts met blocking="render" te gebruiken wanneer deze beschikbaar zijn.
  • Weergaveovergangen tussen documenten worden geactiveerd voordat kritieke opmaak boven de vouw is geparseerd in plaats van de eerste weergave vast te houden met rel="expect" en blocking="render", waardoor half geparseerde elementen halverwege de overgang verschijnen.

9. Beveiliging: DOM XSS-verdediging en HTML-opschoning

Met één cross-site scripting-fout (XSS) kan een aanvaller willekeurige code uitvoeren in de browsers van je gebruikers, sessiegegevens stelen of namens hen acties uitvoeren. Daarom zijn door de browser afgedwongen beveiligingsmaatregelen zoals veilige HTML-opschoning, Trusted Types en strikte CSP's zo belangrijk.

Modellen pakken deze beveiligingsproblemen zelden proactief aan. In alle taken in onze volledige evaluatiesuite voegden modellen bijvoorbeeld geen Content Security Policy (CSP) of cross-origin geïsoleerde header toe zonder expliciete prompt.

Zelfs als prompts rechtstreeks om beveiliging vragen, mislukken onbegeleide modellen nog steeds bij meer dan de helft van onze beveiligingscontroles. Ze grijpen dan naar kwetsbare aangepaste fallbacks of onvolledig beleid. Dat wordt duidelijk als je je verdedigt tegen DOM XSS:

  • Zelfgeschreven DOMParser-sanitizers op de toelatingslijst schrijven (als setHTML()-fallback of binnen een Trusted Types-beleid) in plaats van een gecontroleerde bibliotheek zoals DOMPurify te gebruiken als systeemeigen opschoning niet beschikbaar is.
  • DOMPurify wordt bij elke pagina geladen in plaats van de systeemeigen setHTML() te gebruiken als deze wordt ondersteund en DOMPurify alleen als fallback te laden.
  • Er worden permissieve (input) => input-passthrough-beleidsregels voor vertrouwde typen geregistreerd die de handhaving van de sink ondermijnen.
  • Vertrouwde typen op statische pagina's koppelen aan CSP's met host-toelatingslijst script-src 'self' in plaats van inline scripts te vergrendelen met SHA-256-hashes.
  • 'strict-dynamic' en 'report-sample' weglaten bij de configuratie van op nonce gebaseerd script-src Content Security Policy.

10. Beveiliging: inloggen met toegangssleutel, herverificatie en levenscyclus van inloggegevens

Toegangssleutels verbeteren de beveiliging voor gebruikers en de inlogconversies voor bedrijven, maar de implementatie ervan (zelfs met de hulp van agents) is een uitdaging.

WebAuthn heeft specifieke API's voor serialisatie, mogelijkheidsdetectie en signalering die niet-begeleide modellen bijna volledig missen in onze evaluaties. Als je een AI-model vraagt om inloggen met toegangssleutels, beheer of herverificatie toe te voegen, schrijft het vaak handmatige bytecoderingshelpers, slaat het mogelijkhedencontroles over in de beheer-UI of laat het inloggegevens niet gesynchroniseerd met wachtwoordmanagers:

  • Handmatig atob()- en btoa() Base64URL-conversiehelpers maken, als primair pad of als redundante standaardcode, in plaats van te vertrouwen op ingebouwde serialisatiemethoden zoals parseCreationOptionsFromJSON(), parseRequestOptionsFromJSON() en credential.toJSON().
  • PublicKeyCredential.signalUnknownCredential() wordt weggelaten tijdens het inloggen als de server een onbekende inloggegevens-ID meldt. Verwijderde of ingetrokken toegangssleutels blijven dan in de wachtwoordmanagers van gebruikers staan.
  • PublicKeyCredential.getClientCapabilities() overslaan voordat de UI voor het maken en beheren van toegangssleutels wordt gerenderd.
  • Een AbortController en AbortSignal weglaten bij het starten van verzoeken voor hernieuwde verificatie met een toegangssleutel.
  • De optie origin trial mediation:"immediate" doorgeven in plaats van uiMode:"immediate" voor gestroomlijnde inlogverzoeken.

Deze gaten dichten

Deze 10 gebieden zijn verre van een volledige lijst en we verwachten dat de specifieke kennishiaten in de loop van de tijd zullen veranderen. Modellen zullen zich aanpassen en het webplatform zal zich blijven ontwikkelen.

Het goede nieuws is dat Modern Web Guidance al deze hiaten aanpakt en zich blijft ontwikkelen samen met het platform.

Als je aan de slag wilt gaan met Modern Web Guidance, voer je de volgende opdracht uit of zoek je ernaar in de plug-inmarktplaats van je agent:

npx modern-web-guidance@latest install

Heb je gezien dat modellen andere webontwikkelingstaken verkeerd uitvoerden? We horen graag van u. Open een probleem in de GitHub-repository van Modern Web Guidance of help ons deze hiaten voor andere ontwikkelaars te dichten door bij te dragen aan het project.