Предаването от дизайнер към инженер проваля достъпността
проучване на 50 Figma файла
Изтеглихме достъп само за преглед до 50 продукционни Figma файла от 28 продуктови екипа, с разрешение и пълна анонимизация, след което обходихме всеки от тях с един въпрос: когато инженерът отвори този файл и започне да го реализира, какви решения за достъпност вече е взел дизайнерът — и кои са оставени на инженера да измисля в 16 ч. в петък? Отговорът, файл след файл, е, че повечето от тях все още се измислят в 16 ч.
1. Как одитирахме 50-те файла
Извадката е 50 Figma файла от 28 продуктови екипа в областите SaaS, търговия на дребно, финтех, обществен сектор и edtech. Договорихме достъп само за преглед на принципа на неприписване: нищо в тази статия не идентифицира марка, екип или дизайнер. Файловете бяха избрани да отразяват какво инженерът реално би получил при предаване — не излъскано казусно проучване от портфолио сайт — затова помолихме всеки екип да сподели файла, от който е реализирана най-новата функция, а не файла, с който се гордее най-много. Дванадесет от файловете бяха от екипи с отделена практика за дизайн система; останалите 38 бяха файлове на продуктово ниво, които внасяха системна библиотека или си правеха собствени компоненти на място.
Обходихме всеки файл, търсейки пет свойства за достъпност: дизайн на състоянието на фокус на всеки интерактивен компонент, анотации с алтернативен текст на всяко изображение или недекоративна икона, документация на реда на четене в целия оформление, обработка на предпочитанието за движение за всеки анимиран или преходен елемент и спецификация на контраста в тъмен режим за всеки компонент, доставен и за светла, и за тъмна тема. За всяко свойство файлът получаваше „документиран“ само ако компетентен инженер можеше да реализира дизайна, без сам да измисля отговора. „Споменато в лепкава бележка“ не се броеше. „Шестнадесетичен код, посочен в едно-единствено състояние на задържане“ не се броеше. Летвата беше: решението в ли е във файла във форма, по която инженерът може да действа, без да пита?
Водещата констатация е, че предаването, по тази летва, изпуска решенията за достъпност далеч по-често, отколкото ги включва. Дизайнът на състоянието на фокус се появи на прибл. 40% от интерактивните компоненти в целия корпус. Анотации с алтернативен текст се появиха на приблизително 22% от изображенията, които се нуждаеха от тях. Редът на четене беше изрично документиран в 16% от файловете. Предпочитанията за движение бяха адресирани в 10%. Контрастът в тъмен режим — за 31-те файла, които доставиха и двете теми — беше специфициран за 30% от компонентите. Разликата не е в едно отделно свойство. Тя е и в петте, а инженерът е оставен да я затваря по едно субективно решение наведнъж.
Използвахме летвата „инженерът чете и реализира“. Едно състояние на фокус се брои за документирано, ако файлът показва визуалната спецификация — цвят на контура, ширина, отместване, контраст спрямо фона на фокусирания елемент — във форма, която инженерът може да съпостави с CSS токен. Близко съобщение в Slack с „използвай марковото синьо“ не се брои, защото съобщенията в Slack не оцеляват при предаването. Файлът трябва да носи решението сам по себе си.
„Предаването не се проваля, защото дизайнерите не ги е грижа за достъпността. То се проваля, защото форматът на файла третира достъпността като анотация-коментар, докато тя би трябвало да е първокласно свойство на всеки компонент.“
2. Дизайн на състоянието на фокус: разликата от 60%
От приблизително 1800-те интерактивни компонента, разгледани в целия корпус — бутони, връзки, полета за въвеждане, отметки, превключватели, табове, комбобоксове, елементи от менюта, картички-като-бутон, всичко, до което потребител на клавиатура може да достигне — приблизително 40% доставиха проектирано състояние на фокус. Останалите 60% доставиха състояние по подразбиране, активно и при задържане, и спряха дотам. Инженерът, който изгражда компонента, избира контур на фокуса в момента на реализацията, обикновено като копира браузърния default, обикновено без да провери дали default-ът има контраст 3:1 спрямо повърхността на компонента и в светлата, и в тъмната тема, които файлът доставя.
Как изглежда „липса на дизайн на състоянието на фокус“ на практика? Изглежда като компонент-бутон с три варианта на платното — покой, задържане, натиснат — и без четвърти вариант. Изглежда като поле за въвеждане със стилизирана рамка и без втори стил на рамката за фокусираното състояние. Изглежда като примитив за отметка с пръстен на фокуса само на варианта в покой, като инженерът е оставен да гадае дали същият пръстен трябва да се появи на варианта „отметнат“ или „неопределен“. Моделът се повтаря през компонентите, през екипите, през секторите. Това е единичната най-голяма разлика в достъпността в корпуса и единичната най-лесна за вграждане в дизайна.
Екипите, които проектираха състоянията на фокус добре, имаха едно от две неща в своя полза. Първото беше изрично правило на дизайн системата: всеки интерактивен компонент трябва да достави вариант, чието име започва с focus-, и компонентът не се пуска в библиотеката, докато този вариант не съществува. Второто беше свойство на компонент в Figma на име state с focus, focus-visible и focus-within като изброени стойности, така че браузърът на компоненти на файла извежда липсващите варианти визуално. Екипите без едно от тези две скелета оставяха състоянието на фокус на инженера приблизително девет пъти от десет.
Компонент-бутон, четири варианта: state=default, state=hover, state=pressed, state=focus-visible. Вариантът focus-visible показва контур 2px, отместване 2px, токен за цвят —focus-ring (който сам е съпоставен с шестнадесетичен код, който преминава 3:1 спрямо повърхността на бутона и в двете теми). Инженерът чете inspect панела и копира препратката към токена; нищо не се измисля.
Същият компонент-бутон, три варианта: default, hover, pressed. Без вариант за фокус на платното. Лепкава бележка от дизайнера казва „използвай системния пръстен на фокуса“. Инженерът претърсва библиотеката на дизайн системата, намира два кандидат-пръстена на фокуса (един от бутоните, един от полетата, с леко различни ширини), избира един, доставя го, и преминаването на QA три седмици по-късно го отбелязва, защото избраният пръстен пада под 3:1 на повърхността на деактивирания-но-все-още-фокусируем вторичен бутон.
Когато състоянието на фокус не е във файла, инженерите често доставят браузърния default — а браузърният default се презаписва от глобалния *:focus { outline: none } в повечето CSS reset-и, който същият инженер е добавил шест месеца по-рано, за да изчисти друг коментар от ревю. Резултатът е компонент, който изглежда наред в предварителния преглед на Figma, изглежда наред в средата за разработка с деактивиран reset и се доставя изобщо без видим индикатор на фокуса.
3. Анотации с алтернативен текст: предимно празни
От файловете в корпуса, които включваха съдържателни изображения — продуктова фотография, hero илюстрации, бутони само с икони, инфографични фигури — 78% нямаха анотации с алтернативен текст на слоевете с изображения. Изображението беше поставено, оразмерено и стилизирано; текстовият еквивалент, който инженерът трябваше да постави върху изобразения <img>, не беше във файла. Осем от 50-те файла имаха алтернативен текст на някои изображения, но не на всички, обикновено с анотирана hero илюстрация и празни съдържателни изображения в тялото. Три файла имаха алтернативен текст на всяко изображение. Инженерът, в 47 от 50 файла, трябваше да измисли алтернативния текст — а на практика често го наследяваше от името на файла, от подписа на фигурата или от какъвто низ пасваше на визуалния ритъм.
Разликата е структурна за примитива за изображения на Figma. Няма родно свойство „alt“ на запълване с изображение или слой с изображение; алтернативният текст трябва да се носи като име на слой, коментар, лепкава бележка, отделен спецификационен документ или поле, добавено от плъгин. Нито едно от тях не преминава през inspect панела по подразбиране, така че инженерът, който чете файла в изгледа inspect, не вижда алтернативния текст, дори ако дизайнерът го е написал другаде. Екипите, които затвориха разликата последователно, използваха един от три заобиколни подхода: полета за алтернативен текст, управлявани от плъгин, на всеки вариант на изображение, документирана конвенция, че името на слоя е алтернативният текст, или отделна електронна таблица с алтернативен текст, обвързана с имената на файловете на изображенията, доставяна заедно с файла.
Бутоните само с икони бяха под-провал в рамките на този режим на провал. В 41 от 50 файла бутоните-икони — лупата за търсене, хамбургер менюто, X за затваряне, стрелката за споделяне — нямаха анотация с достъпно име, оставяйки инженера да напише aria-label=“Search” от визуалния контекст без потвърждение, че „Search“ е правилната дума в гласа на марката (беше ли „Find“? беше ли „Lookup“? беше ли нищо, защото бутонът отваря панел, означен другаде?). Именуването на иконите е точно онзи вид микрокопирайтинг решение, което печели от писалката на дизайнера, и точно онзи вид, който предаването губи.
Всяко изображение е или декоративно (алтернативният текст трябва да е празен, екранният четец го пропуска), или информативно (алтернативният текст носи информацията, която визуалното предава). Този избор е решение за съдържанието и принадлежи на дизайнера или на автора, а не на инженера, гадаещ в полунощ. Файл, който не казва нищо за това кои изображения са декоративни, доставя или твърде много алтернативен текст (всяко изображение е словоохотливо описано, включително онези, които са чиста украса), или твърде малко (hero илюстрацията е описана, всяко изображение в тялото получава alt="", защото инженерът е играл на сигурно).
4. Ред на четене, движение, контраст в тъмен режим
Останалите три свойства имаха отчетливи форми на провал. Редът на четене — редът, в който екранен четец ще разказва страницата, който в съвременните адаптивни оформления вече не е гарантирано да съвпада с визуалния ред отгоре надолу — беше документиран в 16% от файловете. Документацията, където съществуваше, обикновено беше номериран наслагващ слой на платното (1, 2, 3 …), добавен с плъгин. Останалите 84% оставяха инженера да съпостави реда на четене от DOM реда, който той случайно е написал, който при CSS Grid оформление с изрично разполагане по редове и колони може да се разминава с визуалното оформление с цяла колона.
Предпочитанията за движение се справиха най-зле. Десет процента от файловете изобщо споменаваха prefers-reduced-motion. Останалите 90% специфицираха анимации и преходи — влизания на модални прозорци, разгъвания на акордеони, плъзгания на snackbar-и, преходи между страници — без да специфицират какво трябва да прави същият компонент, когато потребителят е активирал намалено движение. Инженерът или изграждаше случая с намалено движение в момента на реализацията (често без визуална референция), или доставяше същата анимация на всички, което е по подразбиране и което нарушава 2.3.3 Animation from Interactions за потребители, които задават предпочитанието.
Контрастът в тъмен режим беше специфициран за 30% от компонентите във файлове, които доставиха и двете теми. Останалите 70% специфицираха контраста на светлата тема — обикновено с анотация от Stark или проверка на контраста във файла — и след това пускаха тъмната тема с обърната по шестнадесетичен код палитра, оставяйки инженера да провери дали обърнатата двойка все още покрива 4.5:1 на основния текст и 3:1 на елементите от UI. В около една пета от 31-те файла с две теми поне един компонент падна под прага на контраста в тъмната тема, защото тъмната повърхност и тъмният текст бяха настроени и за двете спрямо математиката на контраста на светлата тема, а не на тъмната.
Матрицата проследява „степента на завършеност“ за всяко свойство в целия корпус — делът на файловете, в които свойството е документирано до летвата „инженерът чете и реализира“. Колоните разделят степента според това дали файлът е от екип с отделена практика за дизайн система, или от продуктов екип, който прави компоненти на място; разликата между двете колони е делтата система-срещу-без-система.
| Свойство за достъпност | Всички 50 файла | Екипи с дизайн система (12) | Продуктови екипи (38) | Делта система-срещу-продукт |
|---|---|---|---|---|
| Дизайн на състоянието на фокус (интерактивни компоненти) | 40% | 75% | 29% | +46 пр.п. |
| Анотации с алтернативен текст (съдържателни изображения) | 22% | 50% | 13% | +37 пр.п. |
| Ред на четене (на ниво платно) | 16% | 42% | 8% | +34 пр.п. |
| Предпочитания за движение (анимирани елементи) | 10% | 33% | 3% | +30 пр.п. |
| Контраст в тъмен режим (само файлове с две теми, n=31) | 30% | 55% | 19% | +36 пр.п. |
„Екипите с дизайн система документират решенията за достъпност приблизително с двойно по-висока честота от продуктовите екипи — но дори системните екипи покриват летвата на едно свойство от петте през повечето време.“
5. Stark и Able: непоследователно възприемане
Двата плъгина, които се появяват най-често в корпуса, са Stark и Able. И двата са зрели, и двата са с добра репутация, и двата доставят функции, които затварят няколко от разликите, документирани по-горе. Stark добавя проверка на контраста, наслагване на реда на фокуса, преглед с намалено движение и поле за анотация с алтернативен текст на слоевете с изображения. Able добавя инспектор на цветовия контраст, наслагване със симулация на зрението и проверка на размера на целта за докосване. Който и да е от двата плъгина, използван последователно в целия файл, би извел този файл от долната четвъртина на корпуса.
„Използван последователно“ е оперативната фраза. В 50-те файла Stark беше инсталиран и видимо използван в 18, а Able — в 11. Във файловете, където плъгинът беше използван, той обикновено беше използван на hero компонента и основния CTA — компонентите, които най-вероятно са на платното, когато дизайнерът отвори плъгина — и само спорадично другаде. Шест файла използваха Stark при глобално преминаване; един използваше Able при глобално преминаване. Моделът е: плъгините съществуват, дизайнерите знаят за тях, биват издърпвани за точкови проверки, а след това точковата проверка спира при компонентите, които дизайнерът случайно е разглеждал, когато плъгинът е бил отворен.
Двата екипа, които затвориха одита по използване на плъгини, направиха едно нещо различно: пуснаха функцията за одит на плъгина на всяка страница от файла като стъпка-гейт за пускане, преди файлът да бъде споделен с инженерството. Одитът се изпълни във файла, произведе доклад и докладът трябваше да е празен (или изключенията му — документирани), преди файлът да премине от „в дизайн“ към „готов за инженерство“. Това е плъгин-като-работен-процес, а не плъгин-като-точкова-проверка, и това е разликата между 80% и 20% покритие в нашата извадка.
Плъгинът повдига пода: проверката на контраста улавя очевидните провали 2.1:1, полето за алтернативен текст дава на дизайнера къде да пише. Нищо от това не помага, ако плъгинът се изпълнява на три компонента, а не на останалите 27. Поправката е да се сложи плъгинът в работния процес — стъпка-гейт за пускане, чеклист преди предаване, Figma клон, който не може да бъде слят без празен доклад от плъгина — а не в усмотрението на дизайнера в момента, в който си спомни, че съществува.
6. Чеклист за предаване и договор за токени
Одитът произвежда чеклист и договор. Чеклистът е това, което дизайнерът трябва да може да отметне, преди файлът да бъде споделен с инженерството. Договорът е формата на дизайн токените, които пътуват заедно с файла, така че инженерът да съпостави Figma променливите с CSS custom properties, без да измисля междинни стойности. И двата са кратки нарочно: всяка точка в чеклиста е свойство, което одитът измери, а всеки токен в договора е стойност, която затвори разлика в корпуса.
Всеки интерактивен компонент доставя вариант state=focus-visible.
Не „системата има пръстен на фокуса“. Вариант на име focus-visible на самия компонент, с цвят, ширина и отместване на контура, обвързани с токена за пръстена на фокуса. Вариантът е това, което инженерът копира в реализацията; без него инженерът гадае.
Всяко съдържателно изображение има алтернативен текст в поле, управлявано от плъгин, или в документирана конвенция за име на слой.
Изберете едно местоположение и го наложете. Полето за алтернативен текст на Stark, името на слоя, третирано като alt, или придружаваща електронна таблица — всеки от трите работи, но само ако всяко изображение във файла използва един и същи. Бутоните само с икони също получават анотация с достъпно име, на същото място, с точния низ, който инженерът трябва да постави в aria-label.
Редът на четене е документиран на всяка страница, където DOM редът ще се разминава с визуалния ред.
Най-простата документация е номериран наслагващ слой, добавен с плъгин (Stark има такъв, няколко плъгина от общността също). За страници, чийто ред е тривиално отгоре-надолу-отляво-надясно, можете да пропуснете наслагването; за всичко, използващо CSS Grid разполагане, именувани области или абсолютно позициониране, наслагването е задължително.
Всеки анимиран или преходен елемент има вариант с намалено движение на платното.
Втора рамка, втори вариант или документирана версия „без анимация“. Инженерът не бива да измисля случая с намалено движение — дизайнерът трябва да специфицира дали модалният прозорец прелива вместо да се плъзга, дали snackbar-ът се появява мигновено вместо да се плъзга, дали преходът между страниците е изпуснат изцяло.
За файлове с две теми контрастът се проверява в тъмната тема отделно, а не се извежда от светлата тема.
Математиката на контраста в тъмен режим е отделен проблем; обръщането на палитрата не е достатъчно. Пуснете Stark или Able на всеки компонент в тъмен режим, не само в светъл. Документирайте съотношението на контраста в бележките на варианта, така че инженерът да може да потвърди, че реализацията съответства.
Файлът се доставя с договор за токени: плосък списък на всяка Figma променлива, съпоставена с нейното CSS custom property.
Договорът е мостът между файла и кодовата база. Типичен договор изглежда като таблицата по-долу: всеки ред назовава Figma променлива, CSS custom property, с което инженерът трябва да я обвърже, стойността в светлата тема, стойността в тъмната тема и критерия на WCAG, в който токенът участва.
| Figma променлива | CSS custom property | Светла стойност | Тъмна стойност | Връзки с WCAG |
|---|---|---|---|---|
| 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 на повърхност) |
| color/surface/raised | —surface-raised | #FFFFFF | #1F1F1F | 1.4.11 (3:1 спрямо съседа) |
| 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 (пропуска се при намалено движение) |
| motion/duration/reduced | —motion-reduced | 0ms | 0ms | 2.3.3 |
След като договорът съществува, работата на инженера е механична: обвържи CSS custom property с Figma променливата, достави реализацията, одитирай чрез сравнение на изобразените стойности с договора. Без договора всяко обвързване е субективно решение, а субективните решения се натрупват в разликата от 60%. Договорът е единичният артефакт, който премества достъпността от „инженерът е отговорен в момента на предаване“ към „системата е отговорна в момента на дизайн“.
Заключение: файлът е договорът
Одитът на 50-те файла завършва с проста констатация. Предаването проваля достъпността не защото дизайнерите не ги е грижа и не защото инженерите не ги е грижа, а защото файлът — Figma файлът, единственият артефакт, който всяка страна чете — не носи решенията за достъпност като първокласни свойства. Състояния на фокус, алтернативен текст, ред на четене, предпочитания за движение, контраст в тъмен режим: всяко от тях е дизайнерско решение, всяко принадлежи във файла, всяко в момента е някъде другаде. В лепкава бележка, в съобщение в Slack, в отделна електронна таблица, в главата на инженера в 16 ч. в петък.
Поправката не е героичен дизайнер или героичен инженер. Тя е промяна в работния процес на ниво екип: всеки интерактивен компонент доставя вариант за фокус, всяко изображение носи алтернативен текст на едно местоположение, управлявано от плъгин, редът на четене е наслоен на всяка нетривиална страница, анимациите специфицират своя аналог с намалено движение, контрастът в тъмен режим се проверява отделно от светлия, а файлът се доставя заедно с договор за токени, който назовава всяка променлива, с която реализацията се обвързва. Нито една от тези стъпки не е нова, нито една не изисква инструмент, който вече нямаме, и всеки екип, който ги приеме като стъпки-гейтове за пускане, ще затвори повечето от разликите, които измерихме, в рамките на един цикъл на пускане.
По-дълбоката констатация е, че екипите с дизайн система вече правят това приблизително с двойно по-висока честота от продуктовите екипи. Подемът, който осигуряват екипите с дизайн система, е точно подемът, който дисциплината на изграждането на система налага: компонентите са именувани, свойствата са изброени, вариантите са видими, токените са изрични. Внасянето на същата дисциплина във файловете на продуктово ниво — дори без пълна дизайн система отдолу — затваря по-голямата част от разликата при предаване. Това вече не е проблем на инструментите. Това е избор на работен процес.
„Файлът трябва да пристига с вече взетите решения за достъпност. Всичко друго е инженерът да ги измисля в най-лошия възможен момент, с най-малкия възможен контекст, при най-стегнатия възможен краен срок.“