10 ошибок, которые ИИ допускает в веб-разработке

· 5 мин чтения
ai-coding web-dev best-practices accessibility security
10 ошибок, которые ИИ допускает в веб-разработке

«Модели не соблюдают современные практики веб-разработки по умолчанию» — команда Google Chrome превратила это утверждение в измеримый факт и опубликовала список из десяти вещей, которые кодинг-агенты делают чаще всего неправильно. Автор списка — Филип Уолтон. Поводом стал выход версии 1.0 набора скиллов Modern Web Guidance, который встраивает в агентов экспертизу по веб-платформе.

Метод простой. Один и тот же промпт прогоняется через два агента: «с руководством» и без. Результат проверяется автоматическими проверками из каждого гайда. Без скиллов агенты проходят около половины проверок: 52% против 91% со скиллами (данные на 9 ноября 2026 года). Полные результаты собраны на дашборде.

Дальше — сами ошибки. Они делятся на четыре группы: доступность, UX, производительность и безопасность.

1. Доступность: порядок фокуса и атрибут inert

Без правильного порядка фокуса интерфейсом невозможно пользоваться с клавиатуры или через скринридер. Типовые промахи моделей:

  • при открытии нового экрана фокус не переносится в него, а при возврате назад — не восстанавливается;
  • ловушка табуляции и aria-modal="true" строятся вручную на JavaScript, хотя есть модальный <dialog> и атрибут inert;
  • каждый элемент тулбара или таблицы становится отдельной точкой фокуса, вместо «бегущего» tabindex (roving tabindex);
  • собственные обводки :focus-visible не дают контраст 3:1.

2. Доступность: поддержка prefers-reduced-motion

Анимации у пользователей с чувствительным вестибулярным аппаратом вызывают головокружение и тошноту. Базовые transition модели обрабатывают правильно, но новые возможности платформы проваливают: безусловный глобальный scroll-behavior: smooth; CSS-анимации, привязанные к скроллу (scroll-driven animations), без проверки этой настройки; удаление у карусели transition без удаления transform. Ещё две ошибки похуже. Первая: сброс всех анимаций до 0.01ms через * и псевдоэлементы. Такой сброс заодно убивает важные переходы, не связанные с движением. Вторая: включение cross-document view transitions без проверки, что пользователь не отключил анимации.

3. Доступность: валидация форм и подсказки

Основы в порядке, детали — нет:

  • модели дублируют поведение CSS-селектора :user-invalid вручную через JavaScript-валидацию на событии blur — и помечают ошибкой поля, которые пользователь ещё не трогал;
  • атрибут aria-invalid расходится с видимой ошибкой на экране;
  • подсказки формата прячутся в исчезающие плейсхолдеры вместо постоянных подсказок через aria-describedby;
  • подсказки ставятся под полем — там их перекрывает мобильная клавиатура или поповер автозаполнения;
  • стилизация :autofill делается только цветом рамки, без нецветовой подсказки вроде внутренней тени (box-shadow).

4. UX: свайпы и жесты

Код жестов на JavaScript работает, но ощущается грубее нативного. Модели пишут обработчики pointermove и touchmove там, где платформа предлагает CSS Scroll Snap, — для «смахнул, чтобы закрыть» и «смахнул, чтобы открыть». На свайпах между табами пропадает overscroll-behavior-x: none, и случайное движение уводит пользователя назад или вперёд по истории. Прогресс свайпа считается на главном потоке JavaScript вместо анимаций, привязанных к скроллу. Свайп-панели на скролле не получают поддержки клавиатурного фокуса.

5. UX: диалоги, поповеры и top layer

Здесь модели вручную воспроизводят то, что платформа делает сама: самодельные оверлеи на position: fixed с обработкой клика вне окна вместо атрибута popover; анимации появления и исчезновения через JavaScript, requestAnimationFrame, transitionend и запасной setTimeout() вместо @starting-style и transition-behavior; блокировка скролла через overflow: hidden на <html> вместо встроенного перехвата прокрутки у модального <dialog>; ручные слушатели popstate вместо нативного закрытия диалога кнопкой «назад».

6. UX: тёмная тема

  • нет <meta name="color-scheme" content="light dark"> — при загрузке вспыхивает белый экран;
  • тёмные цвета задаются вручную, а color-scheme не объявлен — нативные скроллбары и контролы остаются светлыми;
  • игнорируется функция light-dark();
  • переключатель темы работает только как «вкл/выкл» с сохранением в localStorage, без возврата к системной теме;
  • нет слушателя события storage — открытые вкладки рассинхронизируются.

7. Производительность: отзывчивость во время работы

Модели усвоили уроки эпохи Lighthouse: они умеют ускорять загрузку страницы. А вот отзывчивость интерфейса во время работы (метрика INP) — нет:

  • самодельные очереди задач на setTimeout() вместо scheduler.postTask() и scheduler.yield();
  • тяжёлые страницы с большим количеством элементов без content-visibility: auto и contain-intrinsic-size — любое взаимодействие заставляет браузер перерисовывать страницу целиком;
  • скрытые экраны SPA через display: none вместо content-visibility: hidden с inert — во втором случае рендер остаётся в кэше;
  • остановка offscreen canvas через Intersection Observer вместо связки content-visibility: auto с событием contentvisibilityautostatechange;
  • слушатели событий скролла для подсказок о прокрутке вместо CSS scroll-state queries.

8. Производительность: скачки макета и мерцание (CLS)

Размеры на <img> модели выставляют, дальше начинаются пропуски. У <video> размеров нет — по умолчанию он занимает 300×150. Вместо aspect-ratio и object-fit на медиа стилизуются обёртки. Резервные шрифты идут без font-size-adjust, и при подмене шрифта текст переезжает. Вместо единиц dvh/svh берутся статические vh, и мобильные тулбары дёргают макет. Старые анти-мерцательные фрагменты A/B-тестов с opacity: 0 не заменяются на blocking="render". Наконец, cross-document view transitions запускаются до разбора критической разметки, вместо того чтобы удерживать рендер через rel="expect" и blocking="render".

9. Безопасность: DOM XSS и санитайзинг HTML

Самый слабый блок. Без явного запроса модели вообще не добавляют CSP и заголовки cross-origin isolation. Даже с явным запросом они проваливают больше половины проверок безопасности:

  • самодельные санитайзеры на DOMParser со списком разрешённых тегов вместо проверенной библиотеки вроде DOMPurify;
  • DOMPurify включается в бандл сразу, вместо нативного setHTML() с DOMPurify как лениво подгружаемым запасным вариантом;
  • разрешительные политики Trusted Types вида (input) => input, которые пропускают всё подряд и обнуляют защиту;
  • CSP со списком источников 'self' на статических страницах вместо хэшей SHA-256 для инлайн-скриптов;
  • в nonce-политиках script-src пропущены 'strict-dynamic' и 'report-sample'.

10. Безопасность: passkey-вход и жизненный цикл учётных данных

API сериализации WebAuthn модели почти полностью игнорируют:

  • ручные Base64URL-хелперы на atob() и btoa() вместо parseCreationOptionsFromJSON(), parseRequestOptionsFromJSON() и credential.toJSON();
  • при входе не вызывается PublicKeyCredential.signalUnknownCredential() — устаревшие passkey остаются в менеджерах паролей;
  • перед отрисовкой интерфейса управления не проверяется PublicKeyCredential.getClientCapabilities();
  • при повторной аутентификации не подключаются AbortController и AbortSignal;
  • вместо правильного uiMode: "immediate" передаётся mediation: "immediate".

Что с этим делать

Автор подчёркивает: список не исчерпывающий, и пробелы будут меняться вместе с моделями и самой платформой. Всё перечисленное закрывает Modern Web Guidance 1.0. Скилл устанавливается одной командой:

npx modern-web-guidance@latest install

или находится в маркетплейсах плагинов вашего агента. О других ошибках моделей автор просит сообщать в issues репозитория или присылать исправления по правилам из CONTRIBUTING.md.

Источник: https://developer.chrome.com/blog/top-10-things-ai-gets-wrong-in-web-dev