Помогаю новичкам найти ошибки в вёрстке ChatGPT. Accessibility.. Accessibility. HTML.. Accessibility. HTML. ruvds_статьи.. Accessibility. HTML. ruvds_статьи. Блог компании RUVDS.com.. Accessibility. HTML. ruvds_статьи. Блог компании RUVDS.com. бэм.. Accessibility. HTML. ruvds_статьи. Блог компании RUVDS.com. бэм. Веб-разработка.. Accessibility. HTML. ruvds_статьи. Блог компании RUVDS.com. бэм. Веб-разработка. вёрстка.. Accessibility. HTML. ruvds_статьи. Блог компании RUVDS.com. бэм. Веб-разработка. вёрстка. доступность сайтов.
Помогаю новичкам найти ошибки в вёрстке ChatGPT - 1

Мне кажется, что сегодня начинающие фронтендеры уже не пишут код сами. Они отдают всё на откуп искусственному интеллекту. Хорошо это или плохо — судить не буду.

Я хочу помочь вам найти плохие решения в вёрстке, которые ChatGPT вам предлагает. Для этого я собрал наиболее популярные примеры, которые очень просто исправить. Я вам всё покажу.

Только, пожалуйста, не судите меня строго. Я не очень хорошо умею пользоваться ChatGPT. Но примеры взяты из реальных приложений. Так что о них в любом случае стоит знать.

Давайте посмотрим, что я вам подготовил.

Не копируйте находящийся рядом текст в качестве значения атрибута alt

Альтернативный текст является очень важной штукой для пользователей скринридера и одновременно суперсложной для разработчиков. Сложность заключается в том, что есть ситуации, когда альтернативный текст только ухудшает воспринимаемость интерфейсов.

Давайте рассмотрим пример с вёрсткой раздела «Наши сотрудники». В ChatGPT я отправил вот такой запрос:

«Давай напишем разметку раздела «Наши сотрудники». Блок содержит три блока с информацией о каждом сотруднике. Один такой блок содержит фото сотрудника, имя, должность и ссылки на социальные сети. Название классов надо сделать по БЭМ».

В результате он отправил мне разметку.

<body>
  <section class="team">
    <div class="team__container">
      <h2 class="team__title">Наши сотрудники</h2>
      <div class="team__list">
        <article class="team-card">
          <img alt="Иван Петров" class="team-card__photo" src="images/employee-1.jpg"  width="280" height="320">
          <h3 class="team-card__name">Иван Петров</h3>
          <p class="team-card__position">Разработчик интерфейсов</p>
          <!-- здесь разметка соц.сетей -->
        </article>

        <article class="team-card">
          <img alt="Анна Смирнова" class="team-card__photo" src="images/employee-2.jpg"  width="280" height="320">
          <h3 class="team-card__name">Анна Смирнова</h3>
          <p class="team-card__position">Проектировщик</p>
          <!-- здесь разметка соц.сетей -->
        </article>

        <article class="team-card">
          <img alt="Дмитрий Волков" class="team-card__photo" src="images/employee-3.jpg"  width="280" height="320">
          <h3 class="team-card__name">Дмитрий Волков</h3>
          <p class="team-card__position">Менеджер проекта</p>
          <!-- здесь разметка соц.сетей -->
        </article>
      </div>
    </div>
  </section>
</body>

Обращу ваше внимание на то, какой текст добавил ChatGPT в атрибут alt. Он такой же, как в элементе h3, который находится рядом. На примере разметки блока первого сотрудника покажу, какой результат получит пользователь скринридера NVDA.

Сначала я слышу «Иван Петров. Изображение». Нажимаю клавишу со стрелкой вниз (). Слышу «Иван Петров. Заголовок третьего уровня». Ещё раз нажимаю клавишу со стрелкой вниз (). Слышу «Разработчик интерфейсов».

Дважды озвученные имя и фамилия сотрудника бессмысленны для пользователя. Он не получит ничего полезного. Мой незрячий знакомый Илья называет такой текст спамом.

«Для меня подобные описания изображений — это спам. У меня весь день ридер болтает в телефоне и ноутбуке, поэтому я прослушиваю очень много информации. Обычно к вечеру едет крыша. Да и слух притупляется. Поэтому всё лишнее стараюсь отбрасывать».

Лучшим решением этой проблемы будет скрыть изображение, объявив атрибут alt с пустым значением.

<body>
  <section class="team">
    <div class="team__container">
      <h2 class="team__title">Наши сотрудники</h2>
      <div class="team__list">
        <article class="team-card">
          <img alt="" class="team-card__photo" src="images/employee-1.jpg"  width="280" height="320">
          <h3 class="team-card__name">Иван Петров</h3>
          <p class="team-card__position">Разработчик интерфейсов</p>
          <!-- здесь разметка соц.сетей -->
        </article>
        <!-- здесь оставшиеся блоки -->
      </div>
    </div>
  </section>
</body>

Теперь скринридер NVDA сначала скажет «Иван Петров. Заголовок третьего уровня». Если нажать клавишу со стрелкой вниз (), то пользователь услышит «Разработчик интерфейсов».

Избегайте детализированных слов в названиях классов

Недавно мне попалась на глаза шпаргалка по названию классов по БЭМу. В целом она очень крутая, но для меня был один важный нюанс, который резал глаза.

При формировании задания в предыдущем примере я использовал фразу ссылки на социальные сети. Мне было интересно посмотреть, какие названия будет использовать ChatGPT для этого блока.

<body>
  <section class="team">
    <div class="team__container">
      <h2 class="team__title">Наши сотрудники</h2>
      <div class="team__list">
        <article class="team-card">
          <img alt="Иван Петров" class="team-card__photo" src="images/employee-1.jpg"  width="280" height="320">
          <h3 class="team-card__name">Иван Петров</h3>
          <p class="team-card__position">Frontend Developer</p>
          
          <ul class="team-card__socials">
            <li class="team-card__socials-item">
              <a class="team-card__socials-link" href="#" aria-label="Телеграм">
                <!-- здесь иконка --->
              </a>
            </li>
            <!-- здесь оставшиеся ссылки на соц.сети -->
          </ul>
        </article>

        <!-- здесь оставшиеся элементы -->
      </div>
    </div>
  </section>
</body>

Обращу ваше внимание на класс team-card__socials-link. В нём конкретно передаётся сущность элемента, то есть он является ссылкой. Но что произойдёт, если он будет размечен элементом button?

<body>
  <section class="team">
    <div class="team__container">
      <h2 class="team__title">Наши сотрудники</h2>
      <div class="team__list">
        <article class="team-card">
          <img alt="Иван Петров" class="team-card__photo" src="images/employee-1.jpg"  width="280" height="320">
          <h3 class="team-card__name">Иван Петров</h3>
          <p class="team-card__position">Frontend Developer</p>
          
          <ul class="team-card__socials">
            <li class="team-card__socials-item">
              <button class="team-card__socials-link" type="button" aria-label="Телеграм">
                <!-- здесь иконка --->
              </button>
            </li>
            <!-- здесь оставшиеся ссылки на соц.сети -->
          </ul>
        </article>

        <!-- здесь оставшиеся элементы -->
      </div>
    </div>
  </section>
</body>

Уже происходит путаница. В коде используется элемент button, а класс у него содержит слово «ссылка». Читая такой код, у другого разработчика может всплыть вопрос: «Так это кнопка или ссылка?».

По этой причине лучше не использовать в названиях классов слова, передающие детализированную информацию, которая может поменяться со временем. Например, это информация о сущности элемента, его позиции или цвете. Лучше подбирайте более универсальные названия классов.

В нашем примере уже используется классное название team-card__socials-item. Но оно добавлено к элементу li. Давайте у него уберём этот класс и добавим класс team-card__socials-group. А класс team-card__socials-item добавим для элемента a.

<body>
  <section class="team">
    <div class="team__container">
      <h2 class="team__title">Наши сотрудники</h2>
      <div class="team__list">
        <article class="team-card">
          <img alt="Иван Петров" class="team-card__photo" src="images/employee-1.jpg"  width="280" height="320">
          <h3 class="team-card__name">Иван Петров</h3>
          <p class="team-card__position">Разработчик интерфейсов</p>
          
          <ul class="team-card__socials">
            <li class="team-card__socials-group">
              <a class="team-card__socials-item" href="#" aria-label="Телеграм">
                <!-- здесь иконка --->
              </a>
            </li>
            <!-- здесь оставшиеся ссылки на соц.сети -->
          </ul>
        </article>

        <!-- здесь оставшиеся элементы -->
      </div>
    </div>
  </section>
</body>

Дополнительно могу посоветовать ещё один вариант, который я использую в своём коде.

Для классов и переменных, которые применяются к кнопкам или ссылкам, я вместо слов link или button использую слово control, потому что эти элементы для меня являются элементами управления.

<body>
  <section class="team">
    <div class="team__container">
      <h2 class="team__title">Наши сотрудники</h2>
      <div class="team__list">
        <article class="team-card">
          <img alt="Иван Петров" class="team-card__photo" src="images/employee-1.jpg"  width="280" height="320">
          <h3 class="team-card__name">Иван Петров</h3>
          <p class="team-card__position">Разработчик интерфейсов</p>
          
          <ul class="team-card__socials">
            <li class="team-card__socials-group">
              <a class="team-card__socials-control" href="#" aria-label="Телеграм">
                <!-- здесь иконка --->
              </a>
            </li>
            <!-- здесь оставшиеся ссылки на соц.сети -->
          </ul>
        </article>

        <!-- здесь оставшиеся элементы -->
      </div>
    </div>
  </section>
</body>

А как вы поступаете в таких ситуациях? Какие слова используете в классах, чтобы они одновременно могли применяться к элементам a и button. Поделитесь, пожалуйста, в комментариях.

Связывайте элемент section с его заголовком

Я много внимания уделяю теме адаптации интерфейсов для пользователей скринридера. К сожалению, не всегда можно обойтись только HTML-элементами. Приходится их улучшать ARIA-атрибутами.

Яркий пример — это элемент section. Давайте посмотрим, как скринридер NVDA поймёт разметку раздела «Наши сотрудники» в специальном режиме «Список элементов», нажав комбинацию клавиш insert и f7.

<body>
  <section class="team">
    <div class="team__container">
      <h2 class="team__title">Наши сотрудники</h2>
      <div class="team__list">
        <article class="team-card">
          <img alt="" class="team-card__photo" src="images/employee-1.jpg"  width="280" height="320">
          <h3 class="team-card__name">Иван Петров</h3>
          <p class="team-card__position">Разработчик интерфейсов</p>
          <!-- здесь разметка соц.сетей -->
        </article>

        <!-- здесь оставшиеся элементы -->
      </div>
    </div>
  </section>
</body>
Помогаю новичкам найти ошибки в вёрстке ChatGPT - 2

Ничего нет. Для скринридера наш раздел не существует.

Улучшить понимание элемента sectionможно, связав его с заголовком, который относится к нему. Это реализуется с помощью атрибута aria-labelledby . Если вы раньше не слышали о нём, ничего страшного. Сейчас всё расскажу.

На самом деле атрибут aria-labelledby работает как атрибут for для элемента label. Мы просто объявляем его со значением, которое объявлено для атрибута id у элемента, который содержит краткое описание.

Для демонстрации добавлю атрибуты для элементов section и h2.

<body>
  <section class="team">
    <div class="team__container" aria-labelledby="team-heading">
      <h2 id="team-heading" class="team__title">Наши сотрудники</h2>
      <div class="team__list">
        <article class="team-card">
          <img alt="" class="team-card__photo" src="images/employee-1.jpg"  width="280" height="320">
          <h3 class="team-card__name">Иван Петров</h3>
          <p class="team-card__position">Разработчик интерфейсов</p>
          <!-- здесь разметка соц.сетей -->
        </article>

        <!-- здесь оставшиеся элементы -->
      </div>
    </div>
  </section>
</body>
Помогаю новичкам найти ошибки в вёрстке ChatGPT - 3

Вот так лучше. В списке отобразился элемент «Наши сотрудники». Теперь скринридер NVDA будет сообщать пользователю, что он попал в раздел «Наши сотрудники».

Откладывайте загрузку второстепенных ресурсов

Раздел «Наши сотрудники» является не самым важным на странице. Но в тоже время он содержит изображения, которые могут загружаться долго. Получается ситуация, когда второстепенные ресурсы могут занимать время, которое могло бы пойти на загрузку более важной информации.

Что можно сделать? Из простых решений можно указать приоритет ресурса. Именно его браузеры используют при загрузке страницы. Если он низкий, то они будут загружать его в последнюю очередь.

В HTML есть атрибут fetchpriority. Он как раз указывает браузерам приоритет ресурса. Если для атрибута объявлено значение high, то у ресурса будет наивысший приоритет. Если же используется значение low, то наименьший.

Например, в нашем разделе у изображений как раз должен быть низкий приоритет. Давайте для каждого элемента img объявим значение low для атрибута fetchpriority.

<body>
  <section class="team">
    <div class="team__container" aria-labelledby="team-heading">
      <h2 id="team-heading" class="team__title">Наши сотрудники</h2>
      <div class="team__list">
        <article class="team-card">
          <img alt="" fetchpriority="low" class="team-card__photo" src="images/employee-1.jpg"  width="280" height="320">
          <h3 class="team-card__name">Иван Петров</h3>
          <p class="team-card__position">Разработчик интерфейсов</p>
          <!-- здесь разметка соц.сетей -->
        </article>

        <!-- здесь оставшиеся элементы -->
      </div>
    </div>
  </section>
</body>

Может быть, ChatGPT не добавил атрибут fetchpriority, потому что он относительно новый. Но вы не бойтесь. Вы можете спокойно использовать его в своих проектах. Атрибут поддерживается во всех браузерах с конца 2024 года.

Заключение

Давайте подведём итог. В этой статье я поделился следующими советами:

  • не дублируйте текст, находящийся рядом, в качестве значения атрибута alt;

  • названия классов не должны содержать слова, обозначающие детализированную информацию (сущность элемента, цвет, позицию и т. д.);

  • свяжите элемент section с вложенным заголовком при помощи атрибутов aria-labelledby и id;

  • откладывайте загрузку изображений с помощью атрибута fetchpriority, если они второстепенные.

Дополнительно хочу попросить вас. Поделитесь, пожалуйста, в комментариях своими советами, касающимися HTML и CSS, которые вы бы дали новичкам.

А если вы только начинаете путь в разработке, пожалуйста, не полагайтесь слепо на помощь ChatGPT. Конечно, он вам помогает. Но он может очень легко внедрить плохие решения в ваш код. Будьте бдительны!

На этом я прощаюсь. Спасибо за чтение!

P. S. Помогаю больше узнать про CSS и дружелюбные интерфейсы в своих закрытых ТГ-каналах CSS isn’t magic и UX + Dev = a11y. Присоединяйтесь. Как вступить, написано в профиле.

© 2026 ООО «МТ ФИНАНС»

Автор: melnik909

Источник