Designer-til-ingeniør-overdragelsen svigter tilgængelighed
en undersøgelse af 50 Figma-filer
Vi fik adgang til 50 produktions-Figma-filer fra 28 produktteams — med tilladelse og fuld anonymisering — og gennemgik dem hver med ét spørgsmål: Når ingeniøren åbner denne fil og begynder implementeringen, hvilke tilgængelighedsbeslutninger har designeren allerede truffet — og hvilke er overladt til ingeniøren at opfinde fredag klokken 16? Svaret, fil efter fil, er, at de fleste stadig opfindes fredag klokken 16.
1. Sådan auditerede vi de 50 filer
Stikprøven er 50 Figma-filer fra 28 produktteams inden for SaaS, detailhandel, fintech, den offentlige sektor og edtech. Vi forhandlede adgang til at se filer på ikke-attributionsbasis: intet i denne artikel identificerer et brand, et team eller en designer. Filerne blev udvalgt til at afspejle, hvad en ingeniør faktisk ville modtage ved overdragelse — ikke et poleret case study fra et porteføljewebsted — så vi bad hvert team dele filen, som den seneste feature blev leveret fra, ikke den fil de var stoltest af. Tolv af filerne kom fra teams med en dedikeret design-systempraksis; de øvrige 38 var produktniveaufiler, der importerede et systembibliotek eller rullede deres egne komponenter inline.
Vi gennemgik hver fil med fokus på fem tilgængelighedsegenskaber: fokustilstand-design på hver interaktiv komponent, alternativ tekst-annotationer på hvert billede eller ikke-dekorativt ikon, læserækkefølge-dokumentation på tværs af layoutet, bevægelsespræferencehåndtering for ethvert animeret eller overgående element og mørk-tilstand-kontrastspecifikation for enhver komponent leveret til både lys og mørk tema. For hver egenskab scorede en fil “dokumenteret” kun, hvis en kompetent ingeniør kunne implementere designet uden selv at opfinde svaret. “Nævnt i en sticky note” talte ikke. “Hex specificeret i én hover-tilstand” talte ikke. Standarden var: er beslutningen i filen i en form, ingeniøren kan handle på uden at spørge?
Hovedfundet er, at overdragelsen, efter denne standard, mangler tilgængelighedsbeslutningerne langt oftere end den inkluderer dem. Fokustilstand-design forekom på ca. 40% af interaktive komponenter i korpus’et. Alternativ tekst-annotationer forekom på ca. 22% af de billeder, der havde brug for dem. Læserækkefølge var eksplicit dokumenteret i 16% af filerne. Bevægelsespræferencer var adresseret i 10%. Mørk-tilstand-kontrast — for de 31 filer, der leverede begge temaer — var specificeret for 30% af komponenterne. Gabet sidder ikke i én enkelt egenskab. Det sidder i alle fem, og ingeniøren overlades til at lukke dem ét skøn ad gangen.
Vi brugte standarden “ingeniøren læser og implementerer”. En fokustilstand tæller som dokumenteret, hvis filen viser den visuelle specifikation — konturfarve, bredde, afstand, kontrast mod det fokuserede elements baggrund — i en form, ingeniøren kan mappe til et CSS-token. En nærliggende Slack-besked, der siger “brug brand-blå”, tæller ikke, fordi Slack-beskeder ikke overlever overdragelsen. Filen skal bære beslutningen alene.
„Overdragelsen fejler ikke, fordi designere ikke bekymrer sig om tilgængelighed. Den fejler, fordi filformatet behandler tilgængelighed som en kommentar-annotation, når det burde være en førsteklasses egenskab for enhver komponent.“
2. Fokustilstand-design: de 60% mangler
Af de ca. 1.800 interaktive komponenter berørt i korpus’et — knapper, links, inputfelter, checkbokse, kontakter, faner, comboboxes, menupunkter, kort-som-knapper, alt en tastaturbruger kan nå — leverede ca. 40% et designet fokustilstand. De øvrige 60% leverede en standard-, en aktiv- og en hover-tilstand og stoppede der. Den ingeniør, der bygger komponenten, vælger en fokuskontur ved implementeringstidspunktet, som regel ved at kopiere browserstandarden, som regel uden at kontrollere, at standarden har 3:1-kontrast mod komponentens flade i begge de lys- og mørke temaer, filen leverer.
Hvordan ser “intet fokustilstand-design” ud i praksis? Det ser ud som en knapkomponent med tre varianter på canvasset — hvile, hover, trykket — og ingen fjerde variant. Det ser ud som et inputfelt med en stilet kant og ingen anden kantstil for fokustilstanden. Det ser ud som et checkbox-primitiv med en fokusring kun på hvile-varianten, hvor ingeniøren overlades til at gætte, om den samme ring skal vises på den markerede eller den ubestemte variant. Mønsteret gentager sig på tværs af komponenter, teams og sektorer. Det er det største enkelttilgængelighedsgab i korpus’et og det letteste at designe ind.
De teams, der designede fokustilstande godt, havde én af to ting med sig. Det første var en eksplicit design-systemregel: enhver interaktiv komponent skal levere en variant, hvis navn starter med focus-, og komponenten frigives ikke i biblioteket, inden den variant eksisterer. Det andet var en Figma-komponentegenskab kaldet state med focus, focus-visible og focus-within som oplistede værdier, så filens komponentbrowser synliggør de manglende varianter. Teams uden én af de to stilladsstrukturer overlod fokustilstanden til ingeniøren ca. ni gange ud af ti.
Knapkomponent, fire varianter: state=default, state=hover, state=pressed, state=focus-visible. Focus-visible-varianten viser en 2px-kontur, 2px afstand, farvetoken —focus-ring (som selv er mappet til en hex, der består 3:1 mod knapfladen i begge temaer). Ingeniøren læser inspektionspanelet og kopierer tokenreferencen; intet opfindes.
Samme knapkomponent, tre varianter: default, hover, pressed. Ingen fokusvariant på canvasset. En sticky note fra designeren siger “brug systemets fokusring”. Ingeniøren søger i design-systembiblioteket, finder to kandidatfokusringe (én fra knapper, én fra inputfelter, lidt forskellige bredder), vælger én, leverer den, og QA-passet tre uger senere flagger det, fordi den valgte ring falder under 3:1 på den deaktiverede-men-stadig-fokuserbare sekundærknapflade.
Når fokustilstanden ikke er i filen, leverer ingeniører ofte browserstandarden — og browserstandarden tilsidesættes af den globale *:focus { outline: none } i de fleste CSS-nulstillinger, som den samme ingeniør tilføjede seks måneder tidligere for at rydde en anden review-kommentar. Resultatet er en komponent, der ser fin ud i Figma-forhåndsvisningen, ser fin ud i udviklingsmiljøet med nulstillingen deaktiveret, og leveres uden nogen synlig fokusindikator overhovedet.
3. Alternativ tekst-annotationer: stort set tomme
Af filerne i korpus’et, der indeholdt indholdsbilleder — produktfoto, hero-illustrationer, ikon-only-knapper, infografikfigurer — havde 78% ingen alternativ tekst-annotationer på billedlagene. Billedet var placeret, størrelsessat og stilet; den tekstmæssige ækvivalent, som ingeniøren forventedes at sætte på det renderede <img>, var ikke i filen. Otte af de 50 filer havde alternativ tekst på nogle billeder men ikke alle, normalt med hero-illustrationen annoteret og indholdsbillederne i brødteksten tomme. Tre filer havde alternativ tekst på hvert billede. Ingeniøren, i 47 ud af 50 filer, forventedes at opfinde alternativ teksten — og arvede i praksis den ofte fra filnavnet, figcaption’en eller en hvilken som helst streng, der passede den visuelle rytme.
Gabet er strukturelt betinget af Figmas billedeprimitiv. Der er ingen native “alt”-egenskab på en billedfyldning eller et billedlag; alternativ tekst skal bæres som et lagnavn, en kommentar, en sticky note, et separat specifikationsdokument eller et plugin-tilføjet felt. Ingen af disse bæres gennem inspektionspanelet som standard, så den ingeniør, der læser filen i inspektionsvisningen, ikke ser alternativ teksten, selv om designeren har skrevet den et andet sted. Teams, der konsekvent lukkede gabet, brugte én af tre løsninger: plugin-styrede alternativ tekst-felter på enhver billedvariant, en dokumenteret konvention om at lagnavnet er alternativ teksten, eller et separat alternativ tekst-regneark nøglet til billedfilnavne, der fulgte med filen.
Ikon-only-knapper var en delfejl inden for denne fejltilstand. I 41 ud af 50 filer havde ikonknapper — søgeluppen, hamburger-menuen, luk-X’et, dele-pilen — ingen tilgængeligt-navn-annotation, der overlod ingeniøren til at skrive aria-label=“Søg” ud fra den visuelle kontekst uden bekræftelse af, at “Søg” var det rette ord i brandets stemme (var det “Find”? var det “Opslag”? var det ingenting, fordi knappen åbner et panel, der er mærket et andet sted?). Ikonnavngivning er præcis den slags mikrotekstbeslutning, der har gavn af en designers pen, og præcis den slags, overdragelsen mister.
Hvert billede er enten dekorativt (alternativ tekst skal være tom, skærmlæseren springer det over) eller informativt (alternativ tekst bærer den information, det visuelle formidler). Det valg er en indholdsbeslutning, og den tilhører designeren eller forfatteren, ikke ingeniøren, der gætter ved midnat. En fil, der ikke siger noget om, hvilke billeder der er dekorative, leverer enten for meget alternativ tekst (hvert billede beskrives udførligt, inklusive dem, der er ren pynt) eller for lidt (hero-illustrationen beskrives, hvert indholdsbillede får alt="", fordi ingeniøren spillede det sikkert).
4. Læserækkefølge, bevægelse og mørk-tilstand-kontrast
De resterende tre egenskaber havde distinkte fejlformer. Læserækkefølge — den rækkefølge, hvori en skærmlæser vil fortælle siden, som i moderne responsive layouts ikke længere er garanteret at svare til den visuelle top-til-bund-rækkefølge — var dokumenteret i 16% af filerne. Dokumentationen, hvor den fandtes, var normalt et nummereret overlay på canvasset (1, 2, 3 …) tilføjet med et plugin. De øvrige 84% overlod ingeniøren til at mappe læserækkefølgen fra den DOM-rækkefølge, de tilfældigvis skrev, som på et CSS Grid-layout med eksplicit række-og-kolonne-placering kan afvige fra det visuelle layout med en hel kolonne.
Bevægelsespræferencer klarede sig dårligst. Ti procent af filerne nævnte prefers-reduced-motion overhovedet. De resterende 90% specificerede animationer og overgange — modal-indgange, accordion-udvidelser, snackbar-slides, sideovergange — uden at specificere, hvad den samme komponent skal gøre, når brugeren har reduceret bevægelse aktiveret. Ingeniøren byggede enten det reducerede bevægelsestilfælde ved implementeringstidspunktet (ofte uden en visuel reference) eller leverede den samme animation til alle, hvilket er standarden og som overtræder 2.3.3 Animation from Interactions for brugere, der har indstillet præferencen.
Mørk-tilstand-kontrast var specificeret for 30% af komponenterne i filer, der leverede begge temaer. De øvrige 70% specificerede lys-tema-kontrasten — normalt med en Stark- eller kontrasttjekker-annotation i filen — og udgav derefter det mørke tema med en hex-vendt palette, der overlod ingeniøren til at kontrollere, om det vendte par stadig oversteg 4,5:1 på brødtekst og 3:1 på UI-komponenter. I ca. en femtedel af de 31 temaer med to udgaver faldt mindst én komponent under kontrasttærsklen i det mørke tema, fordi den mørke flade og den mørke tekst begge var tunet til lys-temaets kontrastregning, ikke det mørke temas.
Matrixen sporer “fuldstændighedsraten” for hver egenskab på tværs af korpus’et — andelen af filer, hvori egenskaben var dokumenteret til standarden “ingeniøren læser og implementerer”. Kolonnerne opdeler raten efter, om filen kom fra et team med en dedikeret design-systempraksis eller et produktteam, der ruller komponenter inline; gabet mellem de to kolonner er system-vs-intet-system-delta’et.
| Tilgængelighedsegenskab | Alle 50 filer | Design-systemteams (12) | Produktteams (38) | System-vs-produkt-delta |
|---|---|---|---|---|
| Fokustilstand-design (interaktive komponenter) | 40% | 75% | 29% | +46pp |
| Alternativ tekst-annotationer (indholdsbilleder) | 22% | 50% | 13% | +37pp |
| Læserækkefølge (canvas-niveau) | 16% | 42% | 8% | +34pp |
| Bevægelsespræferencer (animerede elementer) | 10% | 33% | 3% | +30pp |
| Mørk-tilstand-kontrast (kun filer med to temaer, n=31) | 30% | 55% | 19% | +36pp |
„Design-systemteams dokumenterer tilgængelighedsbeslutningerne med ca. dobbelt så høj rate som produktteams — men selv systemteamene overstiger standarden på kun én egenskab ud af de fem det meste af tiden.“
5. Stark og Able: ujævn brug
De to plugins, der oftest dukker op i korpus’et, er Stark og Able. Begge er modne, begge er velrenommerede, og begge leverer funktioner, der lukker flere af de ovennævnte gab. Stark tilføjer en kontrasttjekker, et fokusrækkefølgeoverlay, en reduceret bevægelsesforhåndsvisning og et alternativ tekst-annotationsfelt på billedlag. Able tilføjer en farvekontrastinspektor, et synssimuleringsoverlay og en berøringsmåltjekker. Ethvert af pluginsene, brugt konsekvent i en fil, ville løfte den fil ud af det nederste kvartil i korpus’et.
Brugt konsekvent er den operative frase. På tværs af de 50 filer var Stark installeret og synligt brugt i 18, og Able i 11. I de filer, hvor pluginet var brugt, blev det normalt brugt på hero-komponenten og den primære CTA — de komponenter, der sandsynligvis var på canvasset, da designeren åbnede pluginet — og kun sparsomt andetsteds. Seks filer brugte Stark i en global gennemgang; én brugte Able i en global gennemgang. Mønsteret er: plugins eksisterer, designere kender til dem, de hentes frem til spot-checks, og spot-checket stopper ved de komponenter, designeren tilfældigvis kiggede på, da pluginet var åbent.
De to teams, der lukkede auditen på pluginbrug, gjorde én ting anderledes: de kørte pluginets audit-funktion på hver side af filen som et release-gate-trin, inden filen blev delt med engineering. Auditen kørte i filen, producerede en rapport, og rapporten skulle være tom (eller dens undtagelser dokumenterede), inden filen gik fra “under design” til “klar til engineering”. Dette er plugin-som-workflow frem for plugin-som-spot-check, og det er forskellen mellem 80% dækning og 20% dækning i vores stikprøve.
Et plugin løfter gulvet: kontrasttjekkeren fanger de åbenlyse 2,1:1-fejl, alternativ tekst-feltet giver designeren et sted at skrive. Intet af det hjælper, hvis pluginet kører på tre komponenter og ikke de resterende 27. Rettelsen er at sætte pluginet i workflowet — et release-gate-trin, en pre-overdragelsestjekliste, en Figma-branch, der ikke kan merges uden en tom pluginrapport — frem for i designerens skøn i det øjeblik, de husker, det eksisterer.
6. En overdragelsestjekliste og en token-kontrakt
Auditen producerer en tjekliste og en kontrakt. Tjeklisten er, hvad en designer skal kunne sætte kryds ved, inden filen deles med engineering. Kontrakten er formen på de design-tokens, der følger med filen, så ingeniøren mapper Figma-variabler til CSS custom properties uden at opfinde mellemliggende værdier. Begge er korte med vilje: hvert punkt på tjeklisten er en egenskab, auditen målte, og hvert token i kontrakten er en værdi, der lukkede et gab i korpus’et.
Enhver interaktiv komponent leverer en state=focus-visible-variant.
Ikke “systemet har en fokusring.” En variant med navn focus-visible på selve komponenten, med konturfarve, bredde og afstand bundet til fokusring-tokenet. Varianten er, hvad ingeniøren kopierer ind i implementeringen; uden den gætter ingeniøren.
Hvert indholdsbillede har alternativ tekst i et plugin-styret felt eller en dokumenteret lagnavn-konvention.
Vælg ét sted og håndhæv det. Stark-alternativ tekst-feltet, lagnavnet behandlet som alternativ tekst, eller et sidecar-regneark — alle tre virker, men kun hvis hvert billede i filen bruger det samme. Ikon-only-knapper får også en tilgængeligt-navn-annotation, samme sted, med den præcise streng, ingeniøren skal sætte i aria-label.
Læserækkefølge er dokumenteret på enhver side, hvor DOM-rækkefølgen vil afvige fra den visuelle rækkefølge.
Den simpleste dokumentation er et nummereret overlay tilføjet med et plugin (Stark har ét, adskillige community-plugins ligesom). For sider, hvis rækkefølge er trivielt top-til-bund-venstre-til-højre, kan man springe overlayet over; for alt, der bruger CSS Grid-placering, navngivne areas eller absolut positionering, er overlayet obligatorisk.
Hvert animeret eller overgående element har en reduceret-bevægelses-variant på canvasset.
En anden ramme, en anden variant, eller en dokumenteret “ingen animation”-version. Ingeniøren skal ikke opfinde det reducerede bevægelsestilfælde — designeren skal specificere, om modalen cross-fader i stedet for at slide, snackbaren vises øjeblikkeligt i stedet for at slide, sideovergangen udelades helt.
For filer med to temaer kontrolleres kontrasten i det mørke tema separat, ikke afledt af lys-temaet.
Mørk-tilstand-kontrastregning er sit eget problem; at vende paletten er ikke nok. Kør Stark eller Able på enhver komponent i mørk tilstand, ikke kun i lys. Dokumenter kontrastforholdet i variantens noter, så ingeniøren kan bekræfte, at implementeringen matcher.
Filen leveres med en token-kontrakt: en flad liste over alle Figma-variabler mappet til deres CSS custom property.
Kontrakten er broen mellem filen og kodebasen. En typisk kontrakt ser ud som tabellen nedenfor: hver række navngiver en Figma-variabel, den CSS custom property, ingeniøren skal binde den til, værdien i lys tema, værdien i mørkt tema og det WCAG-kriterium, tokenet deltager i.
| Figma-variabel | CSS custom property | Lys-tema-værdi | Mørkt-tema-værdi | WCAG-tilknytning |
|---|---|---|---|---|
| color/focus-ring | —focus-ring | #0B57D0 | #A8C7FA | 2.4.7, 1.4.11 |
| color/text/body | —text-body | #1F1F1F | #E3E3E3 | 1.4.3 (4,5:1 mod flade) |
| color/surface/raised | —surface-raised | #FFFFFF | #1F1F1F | 1.4.11 (3:1 mod nabo) |
| size/touch-target/min | —touch-target-min | 44px | 44px | 2.5.5, 2.5.8 |
| motion/duration/standard | —motion-standard | 200ms | 200ms | 2.3.3 (spring over ved reduceret bevægelse) |
| motion/duration/reduced | —motion-reduced | 0ms | 0ms | 2.3.3 |
Når kontrakten eksisterer, er ingeniørens opgave mekanisk: bind CSS custom property til Figma-variablen, lever implementeringen, auditér ved at sammenligne de renderede værdier med kontrakten. Uden kontrakten er enhver binding et skøn, og skøn akkumulerer sig til de 60% gab. Kontrakten er det eneste artefakt, der flytter tilgængelighed fra “ingeniøren er ansvarlig ved overdragelsestidspunktet” til “systemet er ansvarligt ved designtidspunktet.”
Konklusion: filen er kontrakten
50-fil-auditen slutter med et simpelt fund. Overdragelsen svigter tilgængelighed — ikke fordi designere ikke bekymrer sig, og ikke fordi ingeniører ikke bekymrer sig — men fordi filen, Figma-filen, det eneste artefakt, alle parter læser, ikke bærer tilgængelighedsbeslutningerne som førsteklasses egenskaber. Fokustilstande, alternativ tekst, læserækkefølge, bevægelsespræferencer, mørk-tilstand-kontrast: hver af dem er en designbeslutning, hver hører hjemme i filen, og hver befinder sig i øjeblikket et andet sted. I en sticky note, i en Slack-besked, i et separat regneark, i ingeniørens hoved fredag klokken 16.
Rettelsen er ikke en heroisk designer eller en heroisk ingeniør. Det er en workflow-ændring på teamniveau: enhver interaktiv komponent leverer en fokusvariant, hvert billede bærer alternativ tekst ét plugin-styret sted, læserækkefølge lægges over på alle ikke-trivielle sider, animationer specificerer deres reducerede-bevægelses-modpart, mørk-tilstand-kontrast kontrolleres separat fra lys, og filen leveres med en token-kontrakt, der navngiver alle variabler, implementeringen binder til. Ingen af disse trin er nye, ingen kræver et værktøj, vi ikke allerede har, og ethvert team, der vedtager dem som release-gate-trin, vil lukke de fleste af de gab, vi målte, i ét releasecyklus.
Det dybere fund er, at design-systemteams allerede gør dette med ca. dobbelt så høj rate som produktteams. Det løft, design-systemteamene giver, er præcis det løft, disciplinen i at bygge et system pålægger: komponenter navngives, egenskaber opregnes, varianter gøres synlige, tokens gøres eksplicitte. At bringe den samme disciplin til produktniveaufiler — selv uden et fuldt designsystem nedenunder — lukker størstedelen af overdragelsesgabet. Det er ikke længere et værktøjsproblem. Det er et workflow-valg.
„Filen bør ankomme med tilgængelighedsbeslutningerne allerede truffet. Alt andet er ingeniøren, der opfinder dem på det værst mulige tidspunkt, med den mindst mulige kontekst, med den strammest mulige deadline.“