惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Hacker News: Ask HN
Hacker News: Ask HN
N
News and Events Feed by Topic
Forbes - Security
Forbes - Security
The Last Watchdog
The Last Watchdog
TaoSecurity Blog
TaoSecurity Blog
Schneier on Security
Schneier on Security
SecWiki News
SecWiki News
V
Vulnerabilities – Threatpost
Project Zero
Project Zero
O
OpenAI News
W
WeLiveSecurity
Security Archives - TechRepublic
Security Archives - TechRepublic
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
H
Hacker News: Front Page
Cisco Talos Blog
Cisco Talos Blog
Spread Privacy
Spread Privacy
Help Net Security
Help Net Security
P
Privacy & Cybersecurity Law Blog
K
Kaspersky official blog
S
Security @ Cisco Blogs
Latest news
Latest news
AWS News Blog
AWS News Blog
U
Unit 42
Martin Fowler
Martin Fowler
阮一峰的网络日志
阮一峰的网络日志
S
Secure Thoughts
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Know Your Adversary
Know Your Adversary
Scott Helme
Scott Helme
博客园 - 司徒正美
B
Blog RSS Feed
C
Check Point Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
Docker
Google Online Security Blog
Google Online Security Blog
Jina AI
Jina AI
aimingoo的专栏
aimingoo的专栏
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Last Week in AI
Last Week in AI
月光博客
月光博客
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
SegmentFault 最新的问题
NISL@THU
NISL@THU
T
The Blog of Author Tim Ferriss
C
Cisco Blogs
Attack and Defense Labs
Attack and Defense Labs
小众软件
小众软件

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Помогаю новичкам найти ошибки в вёрстке ChatGPT
melnik909 (R · 2026-05-12 · via Все публикации подряд на Хабре

Уровень сложностиСредний

Время на прочтение9 мин

Охват и читатели12

Обзор

Привет, Хабр!

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

Я хочу помочь вам найти плохие решения в вёрстке, которые 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>

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

Улучшить понимание элемента 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>

Вот так лучше. В списке отобразился элемент «Наши сотрудники». Теперь скринридер 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 ООО «МТ ФИНАНС»