HTML · Урок 2

Теги и атрибуты

Учимся работать со списками, заголовками и атрибутами — они сделают вашу разметку осмысленной.

Атрибуты

Атрибуты — это дополнительные настройки тега. Пишутся в открывающем теге в виде имя="значение":

<img src="photo.jpg" alt="Моя фотография">
<a href="https://example.com" target="_blank">Сайт</a>
АтрибутГде бываетЗачем
href<a>Адрес ссылки
src<img>, <script>Путь к файлу
alt<img>Альтернативный текст (важно для доступности)
target="_blank"<a>Открыть ссылку в новой вкладке
classлюбойМетка для стилей CSS
idлюбойУникальный идентификатор элемента
ℹ️
class — повторяемая метка, их может быть много с одинаковым значением. А вот id на странице должен быть уникальным — встречаться один раз.

Заголовки: древовидная структура

Заголовки создают иерархию смысла. Не пропускайте уровни: сначала <h1>, потом <h2> и так далее. Так странице проще понимать поисковые системы и скринридеры.

Мой сайт

Обо мне

Проекты

Сайт для кофейни

Списки

Три вида списков: маркированный, нумерованный и список определений.

<ul>
  <li>Кофе</li>
  <li>Чай</li>
</ul>

<ol>
  <li>Открыть редактор</li>
  <li>Написать код</li>
  <li>Сохранить файл</li>
</ol>
  • Кофе
  • Чай
  • Какао
  1. Открыть редактор
  2. Написать код
  3. Запустить страницу
💡
Списки можно вкладывать друг в друга — внутри <li> может находиться ещё один список, так получаются многоуровневые меню.

Форматирование текста

ТегЭффект
<strong>Жирный текст (смысловой акцент)
<em>Курсив (акцент интонацией)
<mark>Выделение маркером
<br>Перенос строки
<blockquote>Цитата-блок

Семантика: <div> и <span> vs осмысленные теги

<div> и <span> — «пустые» обёртки без значения. Но у HTML есть набор семантических тегов, которые несут смысл для людей и машин:

<header>
  <nav><a href="#">Главная</a></nav>
</header>
<main>
  <section>
    <h2>Статья</h2>
    <p>Текст статьи...</p>
  </section>
</main>
<footer>© 2026</footer>

Атрибуты data-*

Любые атрибуты с префиксом data- — ваши личные «кармашки» для информации. Их не видно на странице, зато легко читать из JavaScript (урок 9) или CSS:

<button data-action="delete" data-id="42">Удалить</button>
<div data-theme="dark">...</div>
💡
По правилам валидного HTML придумывать свои не-data- атрибуты нельзя. Всё, что содержит значение только для скриптов или стилей, — прячьте в data-*.

Глобальные атрибуты

Существуют атрибуты, которые работают у любого тега. Самые полезные:

АтрибутЧто делает
title="..."всплывающая подсказка при наведении
hiddenскрывает элемент со страницы
tabindex="0"делает элемент доступным для перехода с клавиатуры
lang="en"отдельно переопределяет язык у куска текста
draggable="true"разрешает перетаскивание
translate="no"запрещает встроенный перевод для фрагмента
<abbr title="HyperText Markup Language">HTML</abbr>
<p hidden>Этого никто не увидит.</p>

Код в тексте: <pre> и <code>

<code> показывает фрагмент кода в тексте, а <pre> сохраняет форматирование (пробелы и переносы строк). Вместе они идеально показывают примеры:

<pre><code>
  const x = 5;
  console.log(x);
</code></pre>
⚠️
Внутри таких блоков браузер распознаёт угловые скобки как теги. Чтобы показать сам символ <, пишите сущность &lt;.

Правильная вложенность

HTML-теги должны вкладываться по принципу «матрёшки»: открывающий и закрывающий тег не должны пересекаться.

<ul>
  <li>
    <strong>Важно!</strong>
  </li>
</ul>

Неправильно:

<strong><em>пересечение тегов</strong></em>   <!-- так нельзя -->
ℹ️
Браузер «починит» перепутанную вложенность, но результат может отличаться от задуманного. Следите за отступами — они показывают уровень вложенности.

HTML-сущности

Спецсимволы, которые трудно или нельзя набрать напрямую, записываются как сущности — амперсанд, имя и точка с запятой:

<p>4 &lt; 5 — верно. Пиши &nbsp;&mdash; это знак тире.</p>
ЗаписьРезультат
&lt;<
&gt;>
&amp;&
&copy;©
&nbsp;неразрывный пробел
💡
Свёрстанный текст с переносами по смыслу разбивают &nbsp;: «№&nbsp;7», «10&nbsp;кг» — число не оторвётся от единицы измерения.

<b>/<i> или <strong>/<em>?

Разница между ними — в смысле, а не в виде. <strong> и <em> несут смысловой акцент, а <b>/<i> — только визуальное выделение:

<p><strong>Важно!</strong> Сохранение прошло.</p>
<p>Цена — <b>999 ₽</b></p>   <!-- просто жирный текст -->
💡
Правило: есть смысловой удар — используйте strong/em. Просто «покрасить» — b/i, или вообще span с классом.

Контактный блок: <address>

Тег <address> семантически выделяет контакты автора контента — его удобно находить скриптам и скринридерам:

<address>
  Автор: Иван Иванов,
<a href="mailto:ivan@mail.ru">ivan@mail.ru</a>
<a href="tel:+79990000000">+7 999 000-00-00</a> </address>

Время: <time> и скрыто-раскрывающееся <details>

<time> хранит читаемую машиной дату, а <details>/<summary> создают раскрывающийся аккордеон без JavaScript:

<time datetime="2026-02-14">14 февраля 2026</time>

<details>
  <summary>Показать ответ</summary>
  <p>Текст, скрытый по умолчанию.</p>
</details>
💡
<details open> — развернуть блок сразу. Это готовый FAQ-аккордеон: доступен с клавиатуры и не требует ни строчки JS.

Изображение с подписью: <figure>

Связка «картинка + подпись» оформляется тегами <figure> и <figcaption>:

<figure>
  <img src="team.jpg" alt="Команда проекта">
  <figcaption>Команда WebDev Уроки, 2026</figcaption>
</figure>

Ширина и высота: где указывать

Размеры изображений раньше писали прямо в HTML. Сегодня это делают в CSS, а атрибуты Оставляют для резервирования места — чтобы страница не «прыгала» при загрузке:

<img src="photo.jpg" alt="Пейзаж" width="640" height="480">
⚠️
Атрибуты width/height нужны, чтобы браузер знал пропорции кадра заранее. В CSS ширину ставьте в процентах — и пропорции сохранятся автоматически.

Список описаний: dl, dt, dd

Тип списка для терминов и их определений — пара «ключ → значение»:

<dl>
  <dt>HTML</dt>
  <dd>Язык разметки гипертекста</dd>
  <dt>CSS</dt>
  <dd>Каскадные таблицы стилей</dd>
</dl>
💡
Именно для словарных статей, FAQ и описания параметров используют dl, а не пустые div.

Цитаты: blockquote и cite

Длинная цитата — <blockquote>, встроенная в текст — <q>. Источник отмечают <cite>:

<blockquote>
  Хорошо структурированный код читают, как прозу.
  <cite>— Анонимный разработчик</cite>
</blockquote>

<p>Он сказал: <q>Код — это текст</q>.</p>

Линии и разделы: hr

Горизонтальная линия <hr> отделяет смысловые части документа, чтобы между ними не путались читатели:

<h2>Часть первая</h2>
<p>...</p>
<hr>
<h2>Часть вторая</h2>

id в деталях

id — уникальный паспорт элемента: для якорей, JavaScript и CSS-селекторов:

<section id="pricing">Тарифы</section>

<a href="#pricing">К тарифам</a>

<!-- в JS: -->
<script>document.getElementById("pricing")</script>
⚠️
id может встретиться на странице только один раз. Если блок повторяется — это класс.

Классы: группа меток

Класс можно вешать на много элементов и сочетать несколько классов на одном:

<div class="card featured">...</div>
<div class="card">...</div>
<div class="card sale">...</div>
ℹ️
Имена классов — только латиницей: btn-primary, card--big. Дефисы и двойные дефисы стандартны (методология BEM).

article против section

<article> — самостоятельная единица (пост, новость, комментарий), <section> — тематический раздел:

<section>
  <h2>Новости</h2>
  <article>Новость 1</article>
  <article>Новость 2</article>
</section>
ℹ️
Слово-подсказка: если содержимое можно унести на другой сайт и оно не потеряет смысл — это article. Раздел просто тематически группирует контент — это section.

Выделение: mark, small, sub, sup

Мелочи форматирования, которые придают тексту характера:

<mark>Выделено маркером</mark>
<small>мелкий примечательный текст</small>
H<sub>2</sub>O  —  индексы
x<sup>2</sup>  —  степени

Пробелы в HTML: слипание

Браузер съедает лишние пробелы и переводы строк — не пишите «перенос» как несколько Spaces подряд:

<p>Один        пробел</p>   <!-- станет «Один пробел» -->
💡
Если нужен гарантированный пробел — &nbsp;. Для переноса строк вне текста используйте CSS, а не десяток <br>.

Переключение языка: lang на фрагменте

Можно сменить язык для отдельных слов — полезна цитатам на иностранном:

<p lang="en">Keep calm and code on.</p>
ℹ️
Эта роль уникальна для тегов: правильная отмека языка помогает скринридерам выбрать голос и браузеру — словарь.

Datalist: подсказки для поля

<datalist> даёт встроенный список подсказок без JavaScript:

<input list="browsers">
<datalist id="browsers">
  <option value="Chrome">
  <option value="Firefox">
  <option value="Edge">
</datalist>

Готовый каркас страницы

Прогрессивный «шаблон на каждый день» — открывайте в срок и не изобретайте заново:

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Название</title>
</head>
<body>
  <header>Шапка</header>
  <main>Контент</main>
  <footer>Подвал</footer>
</body>
</html>

Как смотреть HTML глазами

«Сырую» разметку любой живой страницы видно без всяких инструментов:

💡
Чёрпайте вдохновение из чужих разметок, но не забывайте про лицензии и авторство, если берёте целиком.

Короткая цитата: q

Цитата прямо в строке — браузер сам добавит кавычки:

Он сказал <q>код — это стихи</q> и замолчал.
ℹ️
Для больших цитат — blockquote, для коротких внутри абзаца — q. Кавычки приходят из языка страницы.

Аббревиатуры: abbr и dfn

Расшифровка термина по наведению и определение понятия:

<abbr title="HyperText Markup Language">HTML</abbr>

<dfn>Хэш-функция</dfn> — преобразование данных фиксированной длины.

Правки: ins и del

Показывают, что добавлено и что удалено — с датой:

Цена: <del datetime="2026-01-01">990 ₽</del>
      <ins datetime="2026-02-01">790 ₽</ins>

Зачёркнутое: s

Неактуальная, но оставленная информация:

<s>Старое название</s> — теперь так не называется

Подчёркивание: u

Аккуратно: подчёркивание обычно означает ссылку. Используйте редко:

<u>Неправильное написание</u>

Код и переменные: kbd, samp, var

Разные роли машинного текста:

Нажмите <kbd>Ctrl + S</kbd>.
Программа выведет <samp>OK</samp>.
Формула: <var>a</var> + <var>b</var>.

Изоляция направления: bdi

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

Пользователь <bdi>مرحبا</bdi> оставил отзыв.

Восточная типографика: ruby

Подсказка-произношение над иероглифом:

<ruby>漢<rt>kan</rt></ruby>

Мягкий перенос: wbr

Разрешает перенос длинного слова в нужном месте, но не вставляет дефис:

https://<wbr>very-long-<wbr>path-<wbr>to-page

Группа заголовка: hgroup

Объединяет h1 с подзаголовком, чтобы поисковик видел один заголовок:

<hgroup>
  <h1>Курс по CSS</h1>
  <p>От основ до анимаций</p>
</hgroup>

Шаблон в разметке: template

Фрагмент, который браузер не покажет, но отдаст JavaScript:

<template id="card-tpl">
  <article class="card"><h3>Заголовок</h3></article>
</template>
💡
Содержимое template невидимо и не грузится (картинки, скрипты). Идеально для повторяющихся карточек.

Когда JS выключен: noscript

Сообщение пользователю без поддержки скриптов:

<noscript>
  <p>Включите JavaScript, чтобы работали фильтры.</p>
</noscript>

Секция внутри секции

Вложенные смысловые куски — это нормально, если они правда самостоятельны:

<section>
  <h2>Услуги</h2>
  <section>
    <h3>Фронтенд</h3>
  </section>
  <section>
    <h3>Бэкенд</h3>
  </section>
</section>

Внутри статьи свои части

Article может содержать собственные header и footer — например, мета-подпись:

<article>
  <header><h2>Что нового в CSS</h2></header>
  <p>Текст статьи...</p>
  <footer><time>2026-09-20</time></footer>
</article>

Спецсимволы типографики

©, ™, длинное тире, неразрывный дефис — пишите сущностями:

&copy; 2026 Студия
Бренд&trade;
Справа&nbsp;&mdash;&nbsp;слева
по&#8209;русски

Пробелы разной ширины

HTML даёт несколько видов пробелов для отступов и «прилипания»:

A&nbsp;B      <!-- неразрывный -->
A&ensp;B      <!-- полукруглая (en) -->
A&emsp;B      <!-- круглый (em, шире) -->
A&thinsp;B    <!-- тонкий -->

Мягкий перенос: shy

Перенос покажет дефис только при необходимости:

экстра&shy;ординарный  <!-- «экстра-ординарный» при переносе -->

Русская типографика: ёлочки

Кавычки в текстах на русском — «ёлочки», вложенные — „лапки“:

&laquo;Внешние &bdquo;вложенные&ldquo; кавычки&raquo;
💡
Не путайте кавычки с символом дюйма (&quot;) — в вёрстке это разные знаки.

Дефис против тире

Разные знаки и разные роли:

крепкий мир —  <!-- это тире (—) -->
сине-зелёный   <!-- это дефис (-) -->
Пётр&nbsp;I&nbsp;&mdash; царь

Параграф не внутри параграфа

Вложенный <p> браузер сам разорвёт — валидатор поругается:

<!-- НЕПРАВИЛЬНО -->
<p>Текст <p>вложенный</p></p>

<!-- ПРАВИЛЬНО -->
<p>Текст</p><p>новый абзац</p>

Максимум один h1

Один главный заголовок на страницу — и он должен отражать суть:

<h1>Пиццерия «Дрова»</h1>  <!-- один раз -->
<h2>Меню</h2>
<h2>О нас</h2>

Заголовки без пропусков

Если после h2 идёт h4 — структура «прыгнула». Не пропускайте уровни:

<!-- плохо: -->
<h2>Раздел</h2><h4>Подраздел</h4>

<!-- хорошо: -->
<h2>Раздел</h2><h3>Подраздел</h3>

Описательный текст ссылок

«Читать далее» ничего не говорит. Называйте, куда ведёт ссылка:

<!-- плохо -->
Подробности <a href="/tariffs">здесь</a>.

<!-- хорошо -->
<a href="/tariffs">Сравнить тарифы</a>.

Источник цитаты: cite

Название произведения или источник со словом «—»:

<blockquote>
  <p>Простота — залог надёжности.</p></blockquote>
<cite>Алан Журнал, «Заметки о коде»</cite>

Строки стихотворения

Каждая строка с br, строфы — отдельными блоками:

<p>
Буря мглою небо кроет,<br>
Вихри снежные крутя...
</p>
ℹ️
To <br> — разделитель строк, а не «отступ». Большие отступы делайте CSS.

Списки внутри текста

Список может жить внутри пункта другого списка:

<ul>
  <li>Фрукты
    <ul>
      <li>Яблоки</li>
    </ul>
  </li>
</ul>

Единственный main

Основное содержимое страницы маркируется один раз:

<body>
  <header>...</header>
  <main>Уникальный контент</main>
  <footer>...</footer>
</body>

Боковая заметка: aside

Материал «в стороне» — цитата, реклама, сноска:

<aside>
  <h3>Кстати</h3>
  <p>Этот приём называют «прогрессивным улучшением».</p>
</aside>

Навигация: nav

Группа ссылок для перехода по сайту или странице:

<nav aria-label="Основное меню">
  <ul>
    <li><a href="/">Главная</a></li>
  </ul>
</nav>

Несколько изображений в figure

Figure может содержать галерею с одной общей подписью:

<figure>
  <img src="1.jpg" alt="Слева">
  <img src="2.jpg" alt="Справа">
  <figcaption>Две стороны одной луны</figcaption>
</figure>

data: машинное значение рядом

Тег <data> связывает видимый текст с машинным значением:

<data value="398">от 398 ₽</data>

Микроразметка: itemscope

Поисковики понимают смысл через schema.org-атрибуты:

<div itemscope itemtype="https://schema.org/Book">
  <span itemprop="name">Как устроен код</span>
</div>

JSON-LD: структура для ботов

Разметка машинным описанием внутри script — её не видно пользователю:

<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "Article", "headline": "Новость" }
</script>

ARIA: имя элемента

Если видимой подписи нет — дайте её скринридеру:

<button aria-label="Закрыть окно">✕</button>
ℹ️
Правило: используйте ARIA только когда нет подходящего нативного тега. Семантика HTML сильнее любой «костыльной» роли.

ARIA: роль области

Атрибут role явно объявляет назначение блока:

<div role="alert">Ошибка сохранения!</div>

Скрыть от скринридера: aria-hidden

Декоративную иконку можно исключить из озвучки:

<span aria-hidden="true">🚀</span> Запуск

Паттерн visually-hidden

Текст невидим глазом, но доступен скринридеру:

<span class="sr-only">Открыть главное меню</span>
<!-- .sr-only прячет через CSS clip, а не display:none -->

Проверка орфографии: spellcheck

Браузерное подчёркивание опечаток — можно выключить:

<textarea spellcheck="false">код, а не проза</textarea>

Атрибут translate

Запрет автоперевода имён и кодов:

<p>Функция <span translate="no">parseInt</span> округляет.</p>

Перетаскивание: draggable

Простое объявление перетаскиваемого элемента:

<div draggable="true">Перетащи меня</div>
ℹ️
Логику drop пишут на JavaScript через события dragstart/drop. Атрибут лишь разрешает жест.

Скрыть элемент: hidden

Глобальный атрибут убирает элемент из отображения и из поиска по странице:

<p hidden>Черновик, ещё не показывать</p>

Инлайн-стиль: style

Быстро проверить оформление — но для проекта плохо:

<p style="color: red; font-size: 20px;">Красный текст</p>
⚠️
Инлайн-стили проигрывают классам, их тяжело переиспользовать и переопределять. Держите стили в CSS.

Событие прямо в теге

Старый способ обработчиков — работает, но не приветствуется:

<button onclick="alert('Привет!')">Нажми</button>
💡
Лучше addEventListener в отдельном JS-файле: HTML остаётся разметкой, а поведение — кодом. Об этом в уроках по JavaScript.

Тренировка

Соберите блок «О себе» на странице:

  1. Заголовок <h1> с вашим именем.
  2. Нумерованный список «Мои навыки» из 3 пунктов.
  3. Вложенный маркированный список внутри одного из навыков.
  4. Добавьте в <head> тег <meta name="description" content="...">.

Подсказка: картинки и ссылки — наш следующий урок.

Тег как контейнер смысла

Тег — это ярлык, который объясняет компьютеру смысл куска контента: <p> — абзац, <h1> — главный заголовок, <nav> — навигация.

💡
Спрашивайте себя при разметке: «что это по смыслу?» — тег находится в ответе на этот вопрос.

Атрибут как настройка поведения

Атрибут уточняет, как ведёт себя элемент: куда вести, какого типа поле, какую показать подсказку. Без атрибутов тег — «чистая заготовка».

<a href="https://developer.mozilla.org">MDN</a>   <!-- куда вести -->
ℹ️
У каждого тега свой список допустимых атрибутов: «href» на <p> ничего не даст.

Как «читать» тег целиком

Тренируйте чтение разметки слева направо: открывающий тег, атрибуты, содержимое, закрывающий тег. Через неделю такие куски будут читаться как обычные предложения.

<p class="lead">Вводный абзац.</p>
└─ открытие ┘└─ атрибут ┘   └─ содержимое ┘  └─ закрытие ┘
💡
Объясняйте каждый тег своими словами — это лучший способ его запомнить.

Заголовок h2: граница раздела

<h2> открывает новый раздел: всё, что относится к его теме, идёт до следующего <h2>.

<h2>Настройка</h2>
<p>Раздел про настройку начинается здесь.</p>
<h2>Запуск</h2>
<p>Следующая тема — запуск.</p>
⚠️
Заголовки не используют как декоративный «жирный текст», а уровни не перескакивают.

Абзацы: что с чем соседствует

Рядом с абзацем живут другие блочные элементы: заголовки, списки, цитаты, картинки. Строчные теги работают внутри текста, а не между блоками.

<p>Первый абзац.</p>
<ul><li>Пункт после абзаца</li></ul>
<p>Второй абзац.</p>
💡
Посмотрите в браузере, как блоки «дышат» сами: между абзацем и списком есть отступ по умолчанию.

Маркированный список: порядок неважен

Когда пункты равнозначны и их можно переставить местами — это <ul>. Примеры: увлечения, характеристики, ингредиенты.

<ul>
  <li>Фотоаппарат</li>
  <li>Ноутбук</li>
</ul>
💡
Если порядок важен хоть немного — используйте <ol>. Тип списка считывают и скринридеры.

Нумерованный список: порядок важен

<ol> — там, где шаги идут по порядку: рецепты, инструкции, списки приоритетов. Нумерацию браузер посчитает сам.

<ol>
  <li>Откройте файл.</li>
  <li>Внесите правку.</li>
  <li>Сохраните.</li>
</ol>
⚠️
Не нумеруйте вручную «1.» «2.» — разметка сделает это сама, и номера не «поедут» при вставке пункта.

Термин и определение: dl на практике

Словарь «термин → определение» — это <dl> с <dt> и <dd>. Удобно для характеристик товара, метаданных, FAQ.

<dl>
  <dt>Процессор</dt>
  <dd>Intel Core i5, 6 ядер</dd>
</dl>
💡
Скринридеры читают пары «термин — определение» отдельно, поэтому смысл не теряется.

Вложенные списки: оглавление и меню

Любой пункт списка может содержать внутри ещё один список — так строятся меню, оглавления, деревья.

<ul>
  <li>Документы
    <ul>
      <li>Паспорт</li>
      <li>Права</li>
    </ul>
  </li>
</ul>
⚠️
Вложенный список всегда лежит внутри <li>, а не «между» пунктами.

Иностранные слова: lang и курсив

Слово из другого языка помечают атрибутом lang на фрагменте — скринридер озвучит его с правильным произношением.

<p>Слово <i lang="en">cookie</i> уже знакомо.</p>
ℹ️
Язык и направление письма — разные вещи: для арабского понадобится ещё и dir.

Строчные элементы вокруг строки

Строчные теги (a, em, code, span) живут внутри строки и не переносят её на новую строку.

<p>Текст с <strong>важным словом</strong> посреди абзаца.</p>
💡
Внутри абзаца не размещайте блочные теги: если нужен блок — сначала закройте абзац.

Почему strong, а не b

<strong> — смысловая «важность», <b> — просто визуальная жирность. Для текстов в интернете важен первый: он доносит акцент и до «чтения вслух».

<p>Аккуратно: <strong>лестница скользкая</strong>.</p>
⚠️
Жирность «для дизайна» — это CSS font-weight, а не тег b.

Почему em, а не i

<em> передаёт смысловое ударение (интонацию «здесь важно»), а <i> — только смену голоса: термины, названия, мысли.

<p>Я точно <em>не собиралась</em> этого делать.</p>
<p>Книга «<i>Мастер и Маргарита</i>».</p>
💡
Правило: em — интонация, i — название или термин. В спорных случаях побеждает em.

Маркер поиска: mark

<mark> выделяет фрагмент, актуальный в этом контексте: результаты поиска, ключевые слова, важные числа.

<p>Городу исполнилось <mark>850 лет</mark>.</p>
⚠️
Не ставьте mark постоянно «для акцента» — любое выделение обесценивается от частоты.

Мелкий текст: small

<small> — примечания и оговорки: лицензии, копирайты, сноски «условия могут отличаться».

<footer>
  <small>© 2026, WebDev Уроки</small>
</footer>
💡
Не прячьте в small важную информацию — его воспринимают как второстепенное.

Индексы и степени: sub и sup

<sub> — нижний индекс (H2O), <sup> — верхний (степени, сноски, 109).

<p>Вода — H<sub>2</sub>O. Скорость света 3·10<sup>8</sup> м/с.</p>
💡
Индексы чуть меняют межстрочное расстояние — если мешает, компенсируйте отступами в CSS.

Код в абзаце: code и pre

<code> — код «в строке», <pre> — многострочный блок с сохранением отступов. Внутри <pre> обычно лежит <code>.

<p>Функция <code>greet()</code> приветствует.</p>
<pre><code>function greet() {
  return "Привет!";
}</code></pre>
💡
Следите за отступами внутри pre: все пробелы «честно» попадут на страницу.

Клавиши и переменные: kbd и var

<kbd> — клавиши и команды, <var> — переменные и формулы. Оба делают инструкции «машинно-читаемыми».

<p>Нажмите <kbd>Ctrl</kbd>+<kbd>S</kbd>, чтобы сохранить <var>файл</var>.</p>
💡
Держите подсказки про клавиши в едином стиле на всём сайте — эту мелочь пользователи замечают.

Аббревиатура с расшифровкой: abbr

<abbr> с атрибутом title расшифровывает сокращение: навели — увидели, а сам текст остаётся чистым.

<p><abbr title="Язык гипертекстовой разметки">HTML</abbr> — основа веба.</p>
⚠️
title не читается на тач-устройствах — первую расшифровку давайте в тексте полным словом.

Определение термина: dfn

<dfn> отмечает термин в том месте, где он впервые определяется. Словари и скринридеры распознают эту «точку определения».

<p><dfn>Гибкая вёрстка</dfn> — подход, при котором блоки приспосабливаются к ширине экрана.</p>
💡
dfn используйте один раз на термин, в остальных местах — обычный текст.

Цитаты: q и blockquote

<q> — короткая цитата в предложении, <blockquote> — длинная, отдельным блоком. Атрибут cite указывает источник.

<p>Он сказал: <q>всё будет хорошо</q>.</p>
<blockquote cite="https://example.ru/article">
  Длинная цитата, которой нужен отдельный блок.
</blockquote>
💡
Кавычки для q браузер добавит сам. Для blockquote отступ слева обычно задают в CSS.

Время: time и datetime

<time> — дата, понятная и человеку, и машине. Атрибут datetime задаёт каноничный формат.

<time datetime="2026-09-20">20 сентября</time>
ℹ️
Календари, поисковики и индексаторы распознают datetime — полезно в новостях и событиях.

Контакты: address

<address> — контакты автора документа или владельца сайта: почта, телефон, юридический адрес.

<address>
  Напишите: <a href="mailto:hi@site.ru">hi@site.ru</a>
</address>
💡
По умолчанию address — обычный текст курсивом. Польза больше в семантике, чем в стилях.

Картинка с подписью: figure

Картинку или другой автономный элемент с подписью оборачивают в <figure>, а подпись кладут в <figcaption>.

<figure>
  <img src="team.jpg" alt="Команда проекта">
  <figcaption>Наша команда, лето 2026</figcaption>
</figure>
💡
figure подпись связывает иллюстрацию с текстом — они переезжают вместе при вёрстке.

Глава и разделы: section с заголовком

<section> группирует связанный контент, и каждая секция почти всегда имеет свой заголовок.

<section>
  <h2>Навыки</h2>
  <ul><li>HTML/CSS</li></ul>
</section>
⚠️
Секция без заголовка — редкий случай. Обычно это сигнал, что нужен <div>.

Строительный блок без смысла: div

<div> — универсальный контейнер без встроенного смысла. Когда семантического тега нет — берут div и группируют им всё остальное.

<div class="card">
  <h3>Название</h3>
  <p>Описание</p>
</div>
💡
Правило большого пальца: если тег «не о чём» — div. Если «о чём-то» — семантика.

Точечная правка: span

<span> — строчный «пустой» контейнер: им помечают кусочек текста, чтобы стилизовать или «поймать» его скриптом.

<p>Цена <span class="price">499 ₽</span></p>
⚠️
Если вокруг span вы постоянно ставите <br> для «новых строк» — вероятно, нужен блочный тег.

Пропуск уровня заголовка: чем грозит

Переход «h1 → h3» без h2 — как дыра в оглавлении: скринридер и поисковик видят «прыжок» иначе, а пользователь теряет иерархию.

<h1>Курс</h1>
  <h3>Начало</h3>   <!-- пропущен h2 -->
⚠️
Пропуск уровня допустим в редких случаях, но на старте лучше держать уровни строго последовательными.

Как валидатор читает вложенность

Валидатор проверяет не только синтаксис, но и «где кому положено жить»: куда нельзя вкладывать, какие атрибуты лишние. Его ошибки читаются как подсказки к уроку.

💡
Откройите валидатор W3C и скормите ему свою страницу: каждая жёлтая строка — пункт из чек-листа «что проверить».

Именование классов: соглашения

Имена классов — это мини-контракт: читая их, другой разработчик должен сразу понять, что за элемент. Используйте смысловые имена, а не «block1».

<!-- понятно -->
<div class="product-card">
<!-- не ясно -->
<div class="x12">
💡
Популярны схемы вроде BEM, но даже простой дефис без хаоса даёт половину пользы.

id и class: когда что выбирать

id — уникальный «паспорт» элемента (один на страницу), class — одно имя для группы. Ссылки и JS часто ищут по id, стили — почти всегда по классу.

<nav id="main-menu">...</nav>
<button class="btn">Купить</button>
<button class="btn">Заказать</button>
⚠️
Два одинаковых id на странице — ошибка: ссылки и скрипты «разъезжаются».

Булевы атрибуты: без значения

Некоторые атрибуты «работают» самим своим присутствием: required, hidden, disabled, multiple. Значение им не нужно.

<input type="email" required>         <!-- включено -->
<input type="email">               <!-- выключено -->
ℹ️
Форма записи required="required" тоже допустима, но проще писать одно слово.

Кавычки в значениях атрибутов

Если внутри значения нужна кавычка — используйте другой тип: двойные снаружи, одинарные внутри (или наоборот).

<p title='Сказал: «привет»'>текст</p>
<input value='a "b" c'>
⚠️
Амперсанд в значении лучше записывать как &amp; — иначе может «поехать» соседний текст.

Смешение языков с разным направлением

Слово на языке с письмом справа налево (арабский, иврит) внутри русского текста нарушает порядок. Атрибут dir и тег <bdi> отделяют такой фрагмент.

<p>Телефоны: <bdi>٣٧٥٠</bdi> и <bdi>١٢٣</bdi></p>
ℹ️
Это скорее «страховка» для интернациональных проектов; на простом сайте встречается редко.

Шаблон, который не видно: template

<template> хранит фрагмент разметки, который не показывается, пока его не «клонируют» скриптом. Полезно для повторяющихся карточек.

<template id="card">
  <div class="card"><p>Карточка</p></div>
</template>
💡
template без JS почти бесполезен — вернитесь к нему в уроке про DOM.

Контент без JavaScript: noscript

<noscript> показывается только когда JavaScript отключён: запасной текст, ссылки, статичные версии компонентов.

<noscript>
  <p>Включите JavaScript для полной версии сайта.</p>
</noscript>
⚠️
Не прячьте в noscript важный контент — поисковики часто считают его «пустым».

Вопрос без ответа: details и summary

<details> — сворачиваемый блок без JavaScript, <summary> — видимый заголовок-«переключатель». Идеально для FAQ и спойлеров.

<details>
  <summary>Зачем нужна семантика?</summary>
  <p>Чтобы смысл читали машины и скринридеры.</p>
</details>
💡
Атрибут open раскроет блок по умолчанию, а стилизовать «галочку» поможет CSS ::marker.

Дополнительный материал: aside

<aside> — контент, связанный с темой, но не обязательный: боковая колонка, заметки, «по теме», словарик по тексту.

<section>
  <p>Основной текст статьи.</p>
  <aside>
    <p>Связанная заметка, которую можно убрать</p>
  </aside>
</section>
⚠️
Если блок нужен всегда и на всех экранах — это не «дополнение», верните часть текста в основной поток.

Статьи, которые повторяются: article

<article> — самостоятельный кусок, который имеет смысл и без страницы-родителя: запись блога, новость, карточка товара.

<article>
  <h2>Заголовок записи</h2>
  <p>Содержимое статьи...</p>
</article>
💡
Тест: если кусок переехал на отдельную страницу и ничего не потерял — это article.

Верх и низ: header и footer

<header> — шапка раздела (заголовок, логотип, меню), <footer> — подвал (автор, ссылки, копирайт). Они могут быть и внутри article/section.

<header>
  <h1>Название сайта</h1>
</header>
<main>...</main>
<footer>
  <p>© 2026</p>
</footer>
⚠️
footer с «главными» контактами — это <address>. Обычный footer — для ссылок и копирайта.

Навигация: что класть в nav

В <nav> живут главные маршруты: меню, оглавления, постраничная разбивка. Служебные ссылки «футер-профиля» туда класть не обязательно.

<nav>
  <a href="index.html">Главная</a>
  <a href="lessons.html">Уроки</a>
</nav>
💡
Один nav — одно «основное» меню. Второй nav можно пометить aria-label = «дополнительное меню».

Как скринридер «читает» разметку

Скринридер проходит по «семантической карте»: заголовки — навигация по разделам, списки — по пунктам. Div вместо тегов превращает карту в «глухую стену». Практика: включите режим виртуального курсора и слушайте собственную страницу.

💡
Проверка «одними стрелками и Tab» занимает две минуты и вскрывает половину ошибок доступности.

Роль элемента поверх тега: role

Атрибут role меняет «роль» элемента для скринридера. Но правило простое: сперва выбирайте правильный тег, потом добавляйте ARIA, а не наоборот.

<div role="navigation">...</div>  <!-- лучше: <nav> -->
⚠️
«div с именами ролей» — признак спешки. Натуральный тег почти всегда чище.

Невидимые подсказки: title в разметке

Атрибут title показывает тултип при наведении. Полезно для сокращений, но не должно быть единственным источником важной информации.

<abbr title="Cascading Style Sheets">CSS</abbr>
⚠️
На тач-устройствах тултипа нет, а с клавиатуры он виден не всегда — дублируйте смысл в тексте.

Разметка «по смыслу»: выбор тега

Тренировка: по описанию куска текста выберете тег. «Перечень в произвольном порядке» → ul. «Шаги по порядку» → ol. «Определение слова» → dfn или dl. Не подходит ничего → div/span.

<!-- что это? -->
Продукт снят с производства в 2024 году.
💡
Нет «правильного» тега — есть самый уместный. Ценность решения проверяется объяснением в одну фразу.

Практика: страница-рецепт

Страница-рецепт — классика тренировки: заголовок, абзацы, маркированный список ингредиентов, нумерованный список шагов, время приготовления (time), примечания (small).

<h1>Омлет</h1>
<p>Готовится <time>10 минут</time>.</p>
<h2>Ингредиенты</h2>
<ul><li>Яйца</li></ul>
<h2>Шаги</h2>
<ol><li>Разбить яйца</li></ol>
💡
Сделайте рецепт на своём сайте и проверьте его скринридером — вы увидите, как работает разметка.

Практика: карточка товара

Карточка: article, картинка figure, название h2/h3, список характеристик dl, цена, кнопка, сноска small про условия.

<article class="product">
  <h3>Кружка</h3>
  <dl><dt>Материал</dt><dd>Керамика</dd></dl>
  <p>499 ₽</p>
</article>
💡
Блок потребует CSS, но семантический «скелет» важнее — стили придут в уроке 4.

Практика: запись в блоге

Запись блога: header с заголовком и датой, article с несколькими section, цитата blockquote, «связанное» в aside, footer с автором.

<article>
  <header>
    <h1>Как я учил HTML</h1>
    <time datetime="2026-09-01">1 сентября</time>
  </header>
  <section><h2>Начало</h2><p>...</p></section>
  <footer><address>Автор: Анна</address></footer>
</article>
💡
Запишите текст о любимом фильме и разметьте его всеми изученными тегами.

Практика: FAQ из details

FAQ из details/summary не требует ни строчки JavaScript — разворачивание встроено. Добавьте по `

` на вопрос и текст-ответ внутрь каждого details.

<details open>
  <summary>Сколько длится курс?</summary>
  <p>Девять уроков.</p>
</details>
<details>
  <summary>Нужен ли опыт?</summary>
  <p>Нет, начинаем с нуля.</p>
</details>
💡
Первый блок можно оставить раскрытым (open), чтобы сразу был виден пример.

Проверка семантики «вслух»

Хитрый тест семантики: попросите кого-нибудь прочитать страницу «по тегам» («заголовок, список, цитата...») и сравните с вашим замыслом. Несовпадения покажут, где семантика врут.

⚠️
Если структура не «прочиталась» красиво — упростите вложенность, а не добавляйте новых тегов.

JSON-LD вне страницы: когда нужна

Микроразметка типа JSON-LD говорит поисковику о рецепте, товаре или событии — за это появляются «звёздочки» в выдаче. Код ставится в head как отдельный скрипт.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Recipe",
  "name": "Омлет"
}
</script>
ℹ️
Это не обязательно для нового сайта — добавьте после того, как страница набрала трафик.

Автор и права в разметке статьи

Автор — это <address> или ссылка на профиль в footer статьи; дату публикации помечайте time; про права напоминайте small.

<footer>
  <address><a href="about.html">М. Иванова</a></address>
  <time datetime="2026-09-20">20 сентября</time>
</footer>
💡
Контакты автора в address «подсвечивают» фрагмент для поиска по персонам.

Анализ чужой разметки: план действий

Разбор чужого HTML: 1) найти главный контейнер main; 2) прочитать иерархию заголовков; 3) посмотреть, что в nav/header/footer; 4) отметить лишние div; 5) спросить «какой тег здесь лучше подошёл бы».

💡
Просматривайте готовый код каждый день по пять минут — глаз привыкает к элегантным решениям.

Порядок элементов в файле: логика

Хороший HTML читается сверху вниз как изложение: шапка, навигация, главный контент, дополнения, подвал. Скрипты и стили обычно собираются в head или перед закрывающим body.

<head>            <!-- мета и стили -->
<body>
  <header>        <!-- верх -->
  <main>          <!-- главное -->
  <footer>        <!-- низ -->
  <script>        <!-- скрипты -->
⚠️
Путаный порядок разметки = путаная структура страницы. Приводите файл в порядок сразу.

Язык страницы: html lang и фрагменты

Атрибут lang на <html> задаёт язык всей страницы (для скринридеров и словарей), на отдельном теге — переключает для фрагмента.

<html lang="ru">
<p>Слово можно проверить на сервисе <i lang="en">Grammarly</i>.</p>
💡
Неправильный lang сбивает всякие переводчики и автоозвучку — проверяйте его первым делом.

Спецсимволы помнить наизусть

Три сущности встречаются постоянно: &amp; — амперсанд, &lt; — «меньше», &gt; — «больше». Остальные символы можно не запоминать — всегда есть справка.

<p>Курс: HTML &amp; CSS. Условие: 5 &lt; 10.</p>
⚠️
Начинающие пишут «&» как есть, и браузер может проглотить начало выдуманной сущности вместе с текстом.

Неразрывный пробел: когда обязателен

Неразрывный пробел &nbsp; не даёт переносить слово на другую строку: «10 кг», «страница 5», «2026 год». Оформление не «разъедется».

<p>Купили 3 кг яблок и 5 кг апельсинов.</p>
💡
Ставьте его между числом и единицей, именем и инициалами, словом «и т. д.».

Тире, дефис и минус: три знака

Дефис (-) соединяет части слова, тире (—) ставится в предложениях как пунктуация, минус (−) — математический знак. Раньше в вебе их путали чаще, чем хочется верить.

<p>по-русски; урок — простой; температура −5°C.</p>
💡
Окно автозамены обычно «исправляет» тире само — но внутри разметки проверяйте глазами.

Длинный текст с сохранением формы: pre

<pre> сохраняет пробелы и переносы как есть — для стихов, ASCII-схем, лог-файлов и примеров кода, где вёрстка строк важна.

<pre>Однажды,
            в студёную
      зимнюю пору
         я из лесу вышел.</pre>
💡
Внутри pre переносы буквальны: лишняя пустая строка в вёрстке = лишняя пустая строка на странице.

Длина абзаца и внутренние списки

Долгий абзац из восьми предложений читатели пропускают. Делите мысль: короткий абзац, затем список или пример — людям так проще «доставать» смысл.

<p>Как улучшить тексты на сайте:</p>
<ul>
  <li>меньше слов на абзац;</li>
  <li>больше примеров.</li>
</ul>
⚠️
Список, где каждый пункт — по пять строк, лучше превратить в подразделы, а не дробить на 40 пунктов.

Заголовок, отражающий содержание

Заголовок — это обещание. Если раздел называется «Ошибки», в нём должны быть ошибки, и только. Раздел «Дополнительно» — признак того, что контент плохо сгруппирован.

<!-- плохо --><h2>Разное</h2>
<!-- лучше --><h2>Типичные ошибки вложенности</h2>
💡
Проверьте: можно ли из одного заголовка угадать три пункта раздела? Если нет — заголовок слабый.

Семантические ошибки, которые не видны

Глазами текст выглядит прекрасно, но разметка врёт: список «по порядку» оформлен через ul, термин — через i, заголовок — через p. Такое не увидит ни один дизайнер, но увидит скринридер.

💡
Инструмент «список всех заголовков» в DevTools мгновенно покажет «дырявую» иерархию.

Проверка доступности: быстрый инструмент

Плагины в браузере (например, axe DevTools) запускаются одной кнопкой и выдают список проблем с пояснениями. «Контраст», «нет подписи у поля», «заголовок пустой» — всё это ловится автоматически.

⚠️
Авто-проверка не заменяет ручную, но отсекает 50–70% типовых ошибок на ранних стадиях.

Почему «всё из div» — это плохо

Страница из одних div работает во всех браузерах. Но её не смогут «пересказать» скринридер, поисковик и будущий вы: где заканчивается меню и начинается статья — непонятно никому.

<div class="menu">...</div>   <!-- div, -->
💡
Правило-минимум: main, header, footer, nav, h1–h6 и list-списки использовать всегда.

Когда семантика реально «покупает»

Семантическая вёрстка окупается не в первый час, а в долгую: обновление чата в Кафе, перевод страниц, сниппеты в поиске, удобство для читателей на скринридерах — всё вырастает из разметки. Легко сэкономить «один вечер», тяжело потом весь срок жизни проекта.

💡
Вёл ли проект команда месяц или год — семантика дешевле чинится именно сейчас, на старте.

Комментарии в разметке: за и против

Комментарии <!-- ... --> помогают ориентироваться в больших файлах, но не являются мусором: их не видит посетитель, однако файл становится длиннее. Держите комментарии короткими и редкими.

<!-- Хиро-блок: меняем под акции -->
<section class="hero">...</section>
💡
Хороший комментарий объясняет «почему», а не «что» — сам код и так читается.

Дублирование разметки: где опасность

Один и тот же блок (меню, карточка) скопированный пять раз — это пять мест правки. Любое изменение потом делается втройне сложнее.

<!-- одно место, код один раз -->
<nav class="menu">...</nav>
⚠️
Копипаста разметки — главный предвестник будущих «невидимых» багов. Не плодите блоки почём зря.

Атрибут hidden: спрятать, не удаляя

hidden убирает элемент со страницы без удаления из кода. Используется для «мобильных» блоков, попапов и условных областей.

<p hidden>Этот текст будут показывать после клика.</p>
💡
hidden снимается атрибутом `hidden` в DevTools — часто проще проверить именно так.

Класс для стиля vs класс для смысла

Один класс выражает «что это» (product, menu, alert), другой — «как выглядит» (theme-dark, size-large). Ранняя привычка разделять их сохраняет CSS от хаоса.

<button class="btn btn-primary size-lg">Купить</button>
💡
Разумное стартовое соглашение: «блок-модификатор», даже если вы пока не знаете BEM формально.

Раньше прописывали: наследие атрибутов

Старые атрибуты вроде align, bgcolor и border давно «умерли»: их обязанности перешли к CSS. В новых проектах они не нужны, но в старых сайтах встречаются — теперь вы знаете, что это такое.

<!-- было: --><p align="center">
<!-- стало: --><p class="text-center">
💡
Нашли align/bgcolor — спокойно заменяйте на класс и CSS-свойство.

Список всех тегов: где искать

Никто не знает все 100+ HTML-тегов наизусть. Справочники — MDN и W3Schools; открывайте страницу тега и копируйте пример. Со временем «в голове» останется 30–40 частых.

💡
Скачайте блокнот с кратким набором и отмечайте теги, которые уже использовали в проекте.

Ошибка «забыл закрыть тег» на практике

Один незакрытый тег ломает «хвост» всей страницы: стили не применяются, скрипты не подключаются, меню едет. Браузер «терпит», но всё ломается при первом чихе.

<!-- забыли </p> -->
<p>Текст без закрытия
⚠️
В редакторе подсветка немедленно выдаст «незакрытый контейнер». Доверяйте ей, а не глазам.

Разумная вложенность: глубина и хаос

Вложенность на 6–8 уровней — звоночек: вероятно, структура переусложнена. Глубина 3–4 уровня покрывает почти все реальные раскладки; простыне лучше упрощать не стилями, а разметкой.

<div class="wrapper">
  <section class="card">...</section>
</div>
💡
Считайте количество закрывающих тегов в файле — если их втрое больше открывающих, это подозрительно.

Тег но, который пишут все: p и div

Спор «p или div» — классика старта: p для текста, rdiv для «обёртки». Внутри p не должно быть блочных элементов; любая группа блоков — это div.

💡
Правило одной строки: абзацу текст — divу коробка, и не наоборот.

Итоги урока 2: что вы умеете

После урока 2 вы размечаете тексты и структуру: заголовки, абзацы, три вида списков, цитаты, код, время, «детали», секции и статьи, «шапки» и «подвалы», формы и их семантику. Ваша страница теперь «читается» — и людьми, и машинами.

Дальше урок 3: ссылки, изображения и таблицы. Завершите рецепт и блог — они станут «подопытными» в уроках про CSS.

💡
Проведите двадцать минут в DevTools на любимом сайте и найдите три момента, которые разметили бы иначе.

Микроразметка «хлебные крошки»: BreadcrumbList

BreadcrumbList описывает «путь» страницы: Главная → Уроки → Основы. Для поиска это «карта хлебных крошек». Каждый шаг — ListItem с position и name.

<nav aria-label="Хлебные крошки">
  <a href="index.html">Главная</a> /
  <a href="lessons.html">Уроки</a>
</nav>
💡
«Крошки» важны человеку, а микроразметка — поиску. Размечать классом или линками — выбор за вами.

Микроразметка товара: Product и цена

В карточку товара добавляют структурированные данные Product: название, цена, доступность. Поиск может показать цену прямо в выдаче — «звёздочки» для интернет-магазинов.

<meta itemprop="price" content="1990">
<span itemprop="priceCurrency">RUB</span>
💡
Цену в itemprop кладут машинным числом, рядом — понятный текст для человека.

Микроразметка отзыва: Review и рейтинг

Отзыв размечают как Review: автор, текст, оценка. Рейтинг из «звёздочек» поиск может показать в результатах. Разметка «честная»: оценка должна совпадать с реальной.

💡
Не «дорисовывайте» звёзды: отдел качества поисковиков проверяет соответствие разметки факту.

Микроразметка события: Event и дата

Афиша события использует Event: название, дата, место, билеты. Схемы type не помню? Проверяйте в справочниках schema.org — там всё по полочкам.

💡
schema.org — словарь, и словарь «по-русски»: можно читать без привязки к языку кода.

Микроразметка организации: Organization

Раздел Organization описывает фирму: название, адрес, телефон, соцсети. Это «визитка» в поисковой выдаче — отличный старт для бизнес-сайта.

<div itemtype="https://schema.org/Organization">
  <span itemprop="name">Студия «Пиксель»</span>
</div>
💡
Разметка Organization — самый частый запрос в доверительном «бизнес»-онлайне.

Микроразметка статьи: Article и автор

Статья размечается как Article: заголовок, автор, дата публикации. Поиск получает «норм метаданные» и лучше понимает, кто написал и когда обновил страницу.

<article itemtype="https://schema.org/Article">
  <meta itemprop="dateModified" content="2026-09-20">
</article>
💡
dateModified «дата обновления» гораздо «говорливее» даты создания для поиска.

Микроразметка вопроса: FAQPage

FAQ с вопросами и ответами можно разметить как FAQPage: каждый вопрос — Question, каждый ответ — Answer. Такие страницы показываются расширенными «аккордеонами» в выдаче.

<script type="application/ld+json">
{"@type":"FAQPage", "mainEntity":[]}
</script>
💡
FAQPage требует, чтобы вопрос и ответ были видны на странице — разметка не «сочиняет», а описывает.

JSON-LD: три поля для начала

Минимальная разметка JSON-LD умещается в три поля: @context (словарь), @type (тип), name (имя). Положить её можно прямо в head скриптом — браузер не тронет, а поиск прочитает.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "Уроки веб-разработки"
}
</script>
💡
Начните с одного скрипта — и замените его на полный, когда разберётесь с полями.

Микроразметка без лишнего: что не размечать

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

💡
Правило: «размечено — значит, понятно для машины». Не найдено пользы — не размечайте.

Проверка микроразметки: валидатор Google

После разметки покажите страницу валидатору структурированных данных (Rich Results Test). Он и «распарсит» разметку, и подскажет, какие поля обязательны, а каких не хватает.

💡
Тест «без ошибок» — отличное чувство: разметка готова попасть в выдачу по-правильному.

ARIA: зачем роли в HTML

ARIA «рассказывает» скринридерам, что «нарисовано» тегами: роль, состояние, свойства. Когда собственных тегов не хватает (кнопка-иконка, аккордеон), ARIA заполняет пробелы.

💡
Главное правило: «предпочитай настоящий тег»: кнопка из button лучше роли из div.

Роль-сообщение: role="alert"

role="alert" говорит скринридеру «сообщи срочно»: ошибка формы, предупреждение. Без фокуса читалка озвучит блок. Аккуратно: не для всего подряд, а для действительно важного.

<p role="alert">Неверный пароль</p>
💡
Постоянно «говорящий» alert утомляет. Объявляйте его только при появлении ошибки.

Роль-статус: role="status"

role="status" — «тихое» обновление: сколько найдено, запись сохранена. Скринридер озвучит, но без срочности alert. Идеален для «живых» счётчиков.

<p role="status">Найдено 12 статей</p>
💡
Разница alert/status — степень «крика»: срочно и громко против спокойно и по-деловому.

Состояние «раскрыто»: aria-expanded

aria-expanded сообщает, раскрыт ли элемент: true/false. Фиксируется на «родителе» (кнопке), меняется по клику. Так скринридер знает, меню открыто или закрыто.

<button aria-expanded="false">Меню</button>
💡
Обновляйте aria-expanded вместе с переключением класса «open» — тогда данные не «врут».

Кнопка-иконка: aria-label вместо текста

Кнопка, где только иконка, не имеет текста для скринридера. aria-label даёт ей имя: «Поиск», «Закрыть». Инструментарий читает это имя вслух — иконка «оживает».

<button aria-label="Закрыть окно">✕</button>
💡
Если у кнопки есть видимый текст — aria-label не нужен: скринридер прочитает сам текст.

Поиск-блок: role="search"

role="search" помечает зону поиска. Скринридер имеет «поиск по странице» и быстрые ссылки на такие блоки. Добавьте role на form посика — небольшая, но заметная забота.

<form role="search">
  <input placeholder="Найти">
</form>
💡
role="search" не заменит настоящую реализацию поиска, но сделает её «видимой» для помощника.

Имена для навигации: aria-label у nav

Несколько nav на странице нуждаются в различии: «Основное меню», «Нижнее меню». aria-label на nav даёт имя каждой навигации — скринридер сможет предложить их по названию.

<nav aria-label="Основное меню">...</nav>
<nav aria-label="Ссылки в подвале">...</nav>
💡
Как вы называете блоки «речью», так их и назовут «в слух»: выбирайте имена, отличимые в списке.

Вкладки без JS: details и summary глубоко

details/summary — «раскрывашка» без скриптов: summary показывает заголовок, details прячет содержимое до клика. Семантика уже «в теге» — скринридер читает сам.

<details>
  <summary>Как оплатить?</summary>
  <p>Картой или по ссылке.</p>
</details>
💡
Для «FAQ» дивами и заголовками details — доступное решение «из коробки».

Скан-чтение: как скринридер «ходит» списками

Скринридер умеет «собирать» все заголовки, ссылки, списки страницы в навигацию. Отсюда урок: абзацы и пункты списка должны «дорого» отвечать на вопрос «о чём тут».

💡
Золотая проверка: «а хорошо ли звучит только список ссылок?» — если да, разметка читабельна.

Цвет не единственный сигнал: иконки и текст

Различать «отправлено» и «ошибка» только цветом — плохо: дальтоники и скринридеры не увидят. Добавьте текст или иконку. Сигнал «в дубле» = сигнал доступный.

💡
Иконка «часами» не обязательна: достаточно пары слов «Готово»/«Ошибка» рядом с цветом.

Типографика: кавычки «ёлочки» на практике

Русская типографика любит «ёлочки» (<< >>), внутри — «лапки». На клавиатуре их нет, поэтому в HTML их вводят или сущностями, или просто копируют готовые символы из текста.

«ёлочки»
„лапки“
💡
Типографические «ёлочки» важны «по смыслу»: кавычки-прямые годится только для кода и машин.

Типографика: тире длинное и короткое

Длинное тире «—» ставится между частями предложения, короткое «–» — в диапазонах (2026–2027). Дефис «-» — внутри слов. Разные символы несут разные смыслы.

Урок — это практика.
Цены: 2026–2027 гг.
front-end‑разработка
💡
Uncommon правило: между «—» и словами стоят пробелы; у «-» и «–» в диапазоне пробелов нет.

Скобки и вложенность: «своё» и «чужое»

Скобки внутри текста — «( ), [ ], { }» — лишь персонажи. В математике и списках у них своя роль. Размечать их HTML-тегами не нужно: они рабочие символы текста.

💡
Для «визуальных» скобок в вёрстке часто используют CSS/декорацию, а не текст.

Неразрывный пробел: когда он обязателен

Неразрывный пробел   удерживает слова «вместе» при переносе строки: «т. д.», «10 000₽», «г. Москва». Без него браузер унесёт «₽» на новую строку, но имел в виду пару «10 ₽».

Стоимость: 1 500 ₽
💡
Ищите «разрывающиеся пары»: число+единица, инициалы+фамилия, №+номер — и связывайте их неразрывным.

Слоговые переносы: словарные ​

Wbr — «место, где можно перенести». Внутри wbr браузер может переставить строку, если не влезает. Полезно для длинных URL и слов без естественных разрывов.

супермаркетисточникданных
💡
Не ставьте wbr повсюду: только там, где слово в самом деле «длиннющее» без тире.

Ширина строки: 45–75 символов абзаца

Читать удобно, когда в строке 45–75 символов: глаза «не теряются». Длинные абзацы целой страницы — чтение по диагонали. Это касается и текстов сайтов, и ваших комментариев в коде.

💡
Не влезает? Разбейте статью на большее число коротких абзацев — оба мира выиграют.

Абзацы читаются: ритм вёрстки

Один абзац — одна мысль. Два абзаца, говорящие «одно и то же», ужимаются в один. Ритм «короткий–длинный» удерживает внимание лучше ровного «потока воды».

💡
Перечитайте: если абзац можно «потерять» без потери смысла — скорее всего, он лишний.

Иноязычный фрагмент: lang и курсив

Слово на другом языке внутри русского текста помечают и lang="en", и смысловым курсивом: design. Скринридер прочитает его «по-английски», словно с акцентом.

<p>
  Понял <span lang="en">maintain</span> значит «поддерживать».
</p>
💡
Сочетание lang+курсив — «двойной сигнал»: помощник знает, что это иностранное слово.

Числа и единицы: 15 км в разметке

Число и единицу измерения люди читают вместе. Размечать их отдельно не обязательно, но в «машинном» контексте (прогноз, статистика) единицу дают как данные. Проявляйте согласованность: метрики — метриками.

💡
Когда единица «смысловая» (км, ₽, %), а не «форматная» — держите её рядом с числом неразрывным пробелом.

Даты и время: datetime формат ISO

Тег time с datetime имеет машиночитаемый формат: 2026-09-20T14:30. Расшифровка: год-месяц-день T время. Так помощники и поиск понимают дату без догадок «20 сентября».

<time datetime="2026-09-20T10:00">
  в субботу утром</time>
💡
ISO-формат поддерживают почти все калькуляторы дат — проверяйте им свои datetime.

Карточка товара: анатомия семантичных блоков

Карточка товара — мини-документ: заголовок, картинка, описание, цена, кнопка. Разметка «по смыслу»: article для карточки, figure для фото, dl для параметров, button для покупки.

<article class="card">
  <h3>Наушники «Тишина»</h3>
  <p>Беспроводные, белые.</p>
  <button type="button">В корзину</button>
</article>
💡
Каждая карточка — самостоятельный article: переносная «вниз по сетке» восстанавливается целиком.

Заголовок карточки: h2 или h3

Заголовок карточки зависит от уровня секции: если карточка в разделе h2 — в ней h3; если страница «вся сетка карточек» — каждая может начинаться с h2. Без «пропусков» уровней.

💡
Представьте заголовки как «оглавление»: по нему должно быть понятно, где что лежит.

Ссылка «подробнее»: но с описанием

Ссылки-анонсы «Подробнее» никто не любит: непонятно «куда». Сделайте текст осмысленным — «Читать обзор наушников» — или добавьте aria-label с названием раздела, куда ведёт.

<a href="review.html">
  Читать обзор целиком</a>
💡
Проверка: «куда я попаду?» по тексту ссылки — если догадаться нельзя, текст ссылки плохой.

Кнопка-ссылка на карточке: так правильно

«Купить» и «Читать» на карточке — это переход, значит тег , а не button. Кнопку оставляют действиям: «Добавить в корзину», «Голосовать». Ссылка ведёт — кнопка действует.

💡
Правило-памятка: href = переход. Задача «не переход» — ищите button или input.

Аватары и подписи: figure в профилях

Аватар с именем — тандем figure и figcaption: «изображение + подпись». Подпись живёт рядом и «привязана» к картинке, скринридер читает её вместе.

<figure>
  <img src="user.jpg" alt="Фото автора">
  <figcaption>Анна, автор курса</figcaption>
</figure>
💡
figure «держит связку»: переносите его целиком — подпись пойдёт с картинкой.

Список функций: ul без маркера

Перечисление возможностей логично быть списком ul — даже если маркеры потом скрыты CSS. Смысл «набор пунктов» сохраняется: скринридер озвучит «список из трёх пунктов».

<ul>
  <li>Турбо-режим</li>
  <li>Тихое охлаждение</li>
</ul>
💡
Перечисляете характеристики — выбирайте ul. Это «железо», маркер можно убрать стилями.

Контакты в подвале: address против p

Для контактной информации ближайший тег — address: телефон, адрес, почта «в одном месте». Для «случайного» абзаца с реквизитами годится p, но контакты — это address.

<address>
  г. Москва, ул. Примерная, 42
</address>
💡
address «привязан» к ближайшему «хозяину» страницы: автору статьи или сайту целиком.

Логотип семантично: img с alt или svg

Логотип в шапке выполняет роль «ссылка на главную». Картинку делаем ссылкой Название компании — или встроенным SVG: он масштабируется и «легчает».

<a href="index.html">
  <img src="logo.svg" alt="Студия «Пиксель»">
</a>
💡
alt у логотипа дублирует название: человек кликнет по картинке, скринридер прочитает имя.

Доп. кнопки: small-подпись

Кнопка с оговорённой мелкой подписью — например, «Условия», «Последний срок»: small внутри button или рядом. «Мелочь» со смыслом, которую скринридер прочитает отдельно.

💡
Если подпись критична для решения, не прячьте её «в small» — оставьте основной текст.

«Читать далее»: анонс в карточке

Анонс «Читать далее» вежливее: первый абзац текста на странице статьи + ссылка «дословно на саму статью». Так читатель понимает «о чём», а не «где кнопка».

<h3>Как наладить сон</h3>
<p>Советы, которые проверены лично...</p>
<a href="sleep.html">Читать статью</a>
💡
Анонс — «приманка», а не полный текст: пишите интригу, не пересказ.

Длинная страница: оглавление и якоря

Для длинного материала нужна «точка входа»: оглавление с якорями. Ссылки ведут к id заголовков; после клика скрипт или CSS подсвечивают текущую секцию — навигация «живая».

<nav>
  <a href="#favs">Любимые приёмы</a>
</nav>
💡
Оглавление «для длинного» не редкость — это удобный UX разметки, а не роскошь.

FAQ-блок: применённые details

Вопрос-ответ «в один клик»: details/summary. Каждый вопрос — summary, ответ — контент details. Никакого JS: раскрытие работает в каждом браузере из коробки.

<details open>
  <summary>Сколько длится курс?</summary>
  <p>Девять уроков, в своём темпе.</p>
</details>
💡
Атрибут open раскрывает первый вопрос «сразу» — удобная «приветственная» подсказка.

Иерархия практикой: глава/раздел/подраздел

Чем глубже материал, тем «глубже» заголовки: h2 — глава, h3 — раздел, h4 — подраздел. Неприкосновенное правило: не перескакивайте уровень «вверх» без причины.

<h2>Основы</h2>
  <h3>Теги</h3>
    <h4>Строчные</h4>
💡
Начните «три уровня» — в этой книге уроков именно так: глава, раздел, пример.

Шаблон блога: структура поста

Пост в блоге бьётся на: статья (article), заголовок, дата (time), вступительный абзац, тело текста, контакты автора. Опишите это один раз — дальше копируйте «скелет» на все посты.

💡
Размечаете «второй пост» — скопируйте разметку первого и замените тексты: скорость растёт.

Шаблон «Контакты»: проверенные блоки

Контактная страница складывается из проверенных блоков: заголовок, адрес (address), телефон и почта ссылками, схема-карта, форма. Ваша страница — «очередная», но каждая удобна одинаково.

💡
Проверьте кликом: телефон звонит, почта открывает письмо, карта показывает место.

Заголовки и поиск: индексация структуры

Поисковые системы строят «аннотацию» страницы по заголовкам.h2 с осмысленными вопросами («как починить...», «почему...») попадают в расширенную выдачу. Структура = «карта знаний».

💡
Формулируйте заголовки «как вопрос читателя» — и вопрос и ответ окажутся в нужном месте.

Норма вёрстки: валидность против читаемости

Валидность — «браузер не спотыкается». Читаемость — «человек понимает». Иногда идеальная валидность проигрывает практичности: начните с валидного, а «удобнее-но-с-оговоркой» оставляйте на потом.

💡
Не «ломайте» семантику ради галочки валидатора; валидность — цель, а не оковы.

Ссылки-звенья: связка тегов внутри

Термин в тексте может быть ссылкой на его описание: <a href="#def">див</a>. Так «звенья» текста складываются в сеть знаний — как в википедии.

💡
Связывайте то, что поясняете прямо: «это понятие» и «это объяснение» — читателю приятно.

Строка меню: strong против b в навигации

В активном пункте меню жирный текст уместен. Его делает strong (смысловое ударение на «вы здесь»), но чаще это CSS. Для «вы здесь» хватает класса и атрибута aria-current="page" — никаких extra b.

<a href="#lessons" aria-current="page">
  Уроки</a>
💡
aria-current="page" — «правильное» выделение активного пункта: скринридер озвучит «текущий».

Якорные заголовки: id для h2 глубоко

id у заголовков делает их целями ссылок-якорей: #oi может быть id="oi" у h2. Если название «короедское», дайте якорю id, а в ссылке используйте этот «машинный» адрес.

<h2 id="faq-price">Сколько стоит курс</h2>
<a href="#faq-price">про цену</a>
💡
Добрый якорь-ид: короткий, лаконичный, на латинице, уникальный на странице.

Практика: страница «рецепт» с микроразметкой

Соберите рецепт: article с заголовком, списком ингредиентов (ul), шагами (ol), временем (time). Добавьте микроразметку Recipe — и это будет «оживлённый» пример сразу с пользой для SEO.

<h1>Блины на молоке</h1>
<ul>
  <li>Молоко — 500 мл</li>
</ul>
💡
Один рецепт — один article: и человек, и поиск увидят границы блюда.

Практика: карточка товара с ARIA

Добавьте доступность к карточке: aria-label у иконки-кнопки, aria-expanded у «раскрыть описание», состояние «в корзине» через aria-live. Мини-макросы ARIA превращают карточку в «дружелюбный» интерактив.

💡
Сначала сделайте «работает», потом «слышится» — но оба шага обязательны в реальном проекте.

Практика: блог-пост полный свод правил

Соберите пост по всем правилам: единственный h1, дата в time, цитаты в blockquote, списки для перечислений, автор в address, ссылки «с понятным текстом». Всё — без стилей, только семантика.

💡
«Голый» HTML-пост — лучшее упражнение: если структура читается — стили почти не нужны.

Практика: FAQ с details и микроразметкой

Вопросы-ответы через details/summary плюс JSON-LD FAQPage: готовый «аккордеон» с расширенным поиском. Один блок — две выгоды: удобный контент и «продвинутая» выдача.

<details>
  <summary>Где смотреть результаты?</summary>
  <p>На странице вашего профиля.</p>
</details>
💡
Вопрос в summary должен дословно совпадать с «question» в FAQPage-разметке.

Итоги урока 2: чек-лист семантики

Чек-лист: тег «по смыслу», а не «по виду»; один h1 и ровная иерархия; списки для перечислений; цитаты и время — смысловыми тегами; формы с label; alt у картинок; lang проставлен; микроразметка там, где она решает.

💡
Прошли чек-лист — страница «говорит» машине и человеку одно и то же.

Аудит семантики: 4 шага

Аудит за 4 шага: выключите CSS (Ctrl+Shift+P — «Emulate CSS disabled»); прочитайте страницу «сверху вниз»; отметьте, где структура «развалилась»; верните стили и «почините» смысл. Чистка запутанного HTML успокаивает.

💡
«Без стилей читается» — эталон семантической страницы. Упражнение учит выделять главное.

Частые ошибки семантики: 5 штук

1) свой h2 без h1; 2) div вместо ul для перечислений; 3) кавычки «ёлочкой» через HTML-сущности «на память»; 4) картинки без alt повсюду; 5) span вместо p для абзацев. Увидели — сразу правьте.

💡
Три из пяти «ошибок» не видны глазами и находятся только поиском или аудитом.

Прогрессия: от div к осмысленному

Путь новичка: «всё из div» → «что-то из section/article» → «тег по смыслу от корня». На каждом шаге страница становится доступнее. Не осуждайте «дивы»: важно направление роста.

💡
Прагматичная цель — «смысл» в блоках, где он важен: шапка, навигация, статьи, формы.

Рефакторинг: превращаем div в section/article

Рефакторинг: замените div на section там, где есть заголовок; на article — где «самостоятельный блок»; на header/footer/main/nav/aside — где очевидно. Обновите классы «по смыслу», перечитайте.

<div class="block">   <!-- было -->
<section>               <!-- стало -->
  <h2>Услуги</h2>
</section>
💡
Меняем тег, но не разметку внутри: семантика надстраивается, вёрстка остаётся «как была».

Финальное задание: сверстать «справочник тегов»

Сделайте страницу-справочник: введите 20 знакомых тегов, у каждого — описание и пример в code. Пока вы пишете содержимое, вы «читаете» теги заново. Итог: шпаргалка, которая всегда под рукой.

💡
Справочник своими руками — самый «липкий» конспект: запоминается, пока пишется.

Семантика как «язык» страницы

Семантические теги — «слова» единого языка: заголовок, список, цитата, навигация. Браузер, поиск и скринридер «понимают» их одинаково. Чем «чище» разметка — тем легче «диалог» всех участников.

💡
«Смысл» — не украшение: это «инструкция», как читать вашу страницу.

Секция и её заголовок: связка по правилам

Раздел начинается с заголовка: h2 после открывающего section. «Пустая» секция «без» заголовка «сбивает» оглавление. Одна секция — «один» заголовок — «одна» тема.

<section>
  <h2>Наша команда</h2>
  <p>...</p>
</section>
💡
«Секция без заголовка» — дыра в структуре: добавляйте h2 или меняйте тег на div.

Article внутри статьи: вложенные «публикации»

Article может «жить в» article: комментарии внутри записи, цитата-статья внутри обзора. «Содержимое элемента» — «самостоятельный» материал. Вложенность — по «логике», не «для красоты».

💡
«Самостоятельность» — критерий article: вынесите «кусок» на другую страницу — смысл «цел»?

Aside: контент «в сторону» от основного

Aside — боковая «приписка»: справка, цитата, блог-виджет. «Связанно», но «отстраняется». Внутри статьи — «врезка»; вне — «сайдбар» сайта. Разделяет «главное» и «дополнительное».

💡
«Врезка» не «обязательна» для чтения сюжета — тогда aside «честный» выбор.

Footer: не только «подвал страницы»

Footer «закрывает» раздел: подпись, автор, «связанные» ссылки. У статьи — «свой» footer (автор, дата), у страницы — «общий». Тег «переносим»: footer «внутри» section — законно.

💡
«Подпись» к статье ≠ «подвал» сайта: дайте каждому «свой» footer в «своей» зоне.

Порядок и размер заголовков vs смысл

Оголовок «не про размер»: h3 может «выглядеть» крупнее h2 (стилизация CSS). Смысл — в «уровне» иерархии. «Больше-меньше» — дело стилей; «выше-ниже» — дело разметки.

💡
Не «выравнивайте» заголовок «визуально», меняя тег: сначала «логика», потом «размер» в CSS.

Оглавление из заголовков: навигация «по уровням»

Заголовки всех страниц образуют «оглавление». Скринридер «перемещается» по H-тегам, как по меню. «Прыжки» уровней «подпрыгивают» и читателя. Стройте «лестницу» без ступеней-«скачков».

💡
Проверьте «лестницу»: h1→h2→h3; нет ли «дырок» в титульном «ёлочном» переходе h2→h4.

Лента новостей: article как единица потока

Список записей — «серия» article: заголовок, абзац, ссылка «читать». Повторяемая «карточка» = повторяемый article. Поток «новостных» элементов «читается» семантикой «карточки».

💡
«Список статей» через ul > li > article — «и списком», и «статьями» сразу.

Образа навигации: nav против «всех ссылок»

nav — «главные» блоки ссылок: меню сайта, «постраничная» навигация. Не обертывайте «каждую» ссылку текста в nav: перегрузите «карту». «Маленькая» справка-ссылки в nav — «без смысла».

💡
nav — «ничего» не «меню»: будь то «меню загружаемых» или «нумерация страниц», «роль» — навигация.

Main: «главная» зона документа

main — «центральное» содержимое страницы, «одно» на документ. Шапка, подвал, сайдбар — «вне». Скринридер «прыгает» в main «мимо меню». «Связка» страниц — «общие» блоки вне main.

💡
«Главное» в main, «общее» (шапка, подвал) — рядом: «доступная» «прыг-ссылка» использует main.

Микроразметка против JSON-LD: два подхода

Микроразметка живёт «в» тегах (itemscope, itemprop), JSON-LD — «отдельный» блок <script type="application/ld+json">. JSON-LD «не трогает» видимый HTML — меньше «риска поломки». Выбор — «по удобству» команды.

💡
JSON-LD проще «встраивать и удалять»: это «самый» популярный формат у поисковиков.

Метки микроразметки: itemscope и itemprop

itemscope «открывает» элемент-объект; itemprop «называет» свойства. «Товар» — itemscope; «название», «цена», «рейтинг» — itemprop. Иерархия «объект→свойство» — как «вложенные» словари.

<div itemscope itemtype="https://schema.org/Product">
  <span itemprop="name">Кроссовки</span>
  <span itemprop="price">5900</span>
</div>
💡
itemtype «ссылается» на словарь schema.org: с него начните «знакомство» с форматами.

JSON-LD: карточка товара в голове

Блок JSON-LD «Product» рассказывает про товар: название, цену, доступность. Поиск «строит» расширенную выдачу «из» него. Примеры: «цена», «наличие», «рейтинг» — полезные свойства.

<script type="application/ld+json">
{"@context": "https://schema.org", "@type": "Product", "name": "Кроссовки", "offers": {"@type": "Offer", "price": "5900", "priceCurrency": "RUB"}}
</script>
💡
«Данные» — в «голове», прочее — «в теле»: JSON-LD не «висит» на визуальном каркасе.

Recipe JSON-LD: рецепт в выдаче

Schema Recipe «описывает» блюдо: название, ингредиенты, время, калории. Поиск показывает «карточку блюда» — минуты выигрыша «у конкурентов». Ингредиенты — «имя» каждая единица.

💡
«Время» пишите в ISO: PT30M — «30 минут»; робот «понимает» без расшифровки.

Organization JSON-LD: фирма и её логотип

Schema Organization — «имя», «логотип», «контакты», «соцсети». В выдаче — «знакомый» бренд-блок. Компаниям «стоит» разместить «частичку» на страницах контактов.

💡
logo задаётся URL картинки «в» sameAs — «сопоставление» «бренд-страниц» поиском.

Person JSON-LD: автор и карточка личности

Schema Person на «странице автора»: имя, роль, ссылки, фотография. Личные бренды — «поисковая визитка». Свойства name, jobTitle, url, image — «стартовый набор».

💡
«Авторство» полезно «в» статьях: добавьте Person «в» AboutPage — и «расширенная» выдача «автора».

Breadcrumb JSON-LD: «хлебные крошки» в выдаче

Схема BreadcrumbList отражает путь: Главная > Раздел > Страница. В выдаче — «крошки» под статьёй: «куда» ведёт страница. itemListElement — «по позиции» позиции пути.

💡
position от 1 вверх; url — настоящие адреса; крошки «соединяют» с иерархией сайта.

FAQ JSON-LD: вопросы-ответы для расширенной выдачи

FAQPage «массив» вопросов и ответов → в выдаче «раскрывающиеся» строки. «Частые» вопросы «находятся» быстрее. Не «раздувайте» — главное «пользуйтесь», «без спама».

<script type="application/ld+json">
{"@context":"https://schema.org","@type":"FAQPage","mainEntity":[{"@type":"Question","name":"Сколько длится курс?","acceptedAnswer":{"@type":"Answer","text":"Около месяца."}}]}
</script>
💡
Вопросы «из» текста страницы (не «выдуманные»): поиск «не любит» «GPU-набор» из воздуха.

Event JSON-LD: афиша мероприятия

Schema Event для концерта/вебинара: название, дата, место, билеты. В выдаче — «событие» с «купить». startDate — ISO; location — PostalAddress или VirtualLocation.

💡
«Купить билет» (offers) — «бонус»: поиск направляет на продажу из «афиши».

Video JSON-LD: видео в поиске

VideoObject: «имя», «описание», «длительность», «миниатюра», URL. Видеоцитаты — «расширенная» строка. thumbnailUrl — картинка «превью»; duration — ISO «PT15M».

💡
«Видео» без разметки — «обычная» ссылка; с VideoObject — «проигрыватель в выдаче».

ARIA: когда она «не нужна»

Нативные элементы «говорят сами»: button — уже «кнопка», nav — уже «навигация». Дублировать роль ARIA «на родном» теге — лишнее. ARIA «включается», когда «своего» тега или «свойства» не хватает.

💡
«Первый» принцип: родной тег > роль ARIA. Не «наряжайте» button ролью button.

aria-labelledby: подпись из другого места

Свойство «ссылается» на id другого элемента: подпись «глазами» берётся оттуда. Диалог с заголовком, поле «привязанное» к тексту. «Подпись» переиспользуется без «дублирования» текста.

<div id="t">Окно сообщения</div>
<div role="dialog" aria-labelledby="t">...</div>
💡
Один id — «одна» подпись; несколько — разделяйте «пробелом»: "a b".

aria-describedby: описание-примечание

Дополнительная справка: «к полю» — «подсказка», «дальше» — «уточнение». Скринридер «читает» после «имени поля». Отличие от aria-labelledby: «основное имя» против «вспомогательного объяснения».

💡
«Пароль: минимум 8 букв» — «хорошее» aria-describedby к полю пароля.

Невидимость для скринридера: aria-hidden в деле

aria-hidden="true" «прячет» элемент от чтения: декоративную иконку, «дублирующую» надпись. «Видимый» контент «остаётся» видимым — «эффект» только «для слуха». Не прячьте «важное подсказки».

💡
«Иконка_лупа» в кнопке поиска — aria-hidden=true; «текст» кнопки — «доступный».

Живой регион: aria-live и обновления

Когда «часть» страницы меняется скриптом — читатель «не заметит». aria-live="polite" — «сообщать» после текущей речи, "assertive" — «срочно». Статусы «отправлено», «загрузка…» — «его» работа.

💡
Текст в aria-live «читается» при «обновлении»: вставляйте «сообщение» динамически, не «заранее».

Списки в ARIA: role list и listitem

Если «внешние» списки «сделаны» div-ами — role="list" и role="listitem" возвращают «структуру». Для «настоящего» ul это не нужно. «Только» для «нестандартных» конструкций.

💡
«div-список» — повод задаться вопросом: может, «проще» настоящий ul? Начинайте «с него».

Меню в ARIA: role menu и menuitem

«Прикладные» меню у приложений — role=menu/menuitem с клавиатурой. На сайтах «выпадашки» — чаще «навигация»+ссылок, а не «меню приложения». Не «называйте» site-навигацию словом «menu» без нужды.

💡
Строгое menu «обязан» стрелки-клавиши поддерживать; дешевле оставить «просто ссылки».

Вкладки в ARIA: роли tab, tablist, tabpanel

Вкладки «скрывают-показывают» панели: tablist «ряд», tab — «заголовок», tabpanel — «содержимое». aria-selected — «активность». Клавиатура: стрелки «переключают», Tab — «в панель».

<div role="tabpanel" aria-labelledby="tab1">...</div>
💡
«Свои» стрелки + «в панель» по Tab — «доступные» вкладки без «мыши».

Диалог: role dialog и его фон

Модальное окно — role="dialog" с aria-modal="true": контент «снаружи» — «в тени». aria-labelledby — «заголовок» окна, «фокус» «внутрь» при открытии. Закрытие по «Esc» — «этикет» диалогов.

💡
«После» закрытия возвращайте фокус туда, откуда «вызвали» окно: «не теряйте» пользователя.

Роль presentation: «снять» семантику

role="presentation" «гасит» смысл элемента: «таблица-разметка» читается «строками», «декоративная» группа — «молча». Используйте «рядко»: когда «сам» элемент «ничего не значит» для чтения.

💡
«Разметочная таблица» лучше «станет» div + классов; role=presentation — «костыль-запас».

Кавычки: «ёлочки» против «лапок»

Для русского текста «правильные» кавычки — «ёлочки»: « » в тексте, „лапки" для «в кавычках». HTML-сущности « » дают аккуратные «ёлочки». Не «рисуйте» кавычки «двумя грудами» («) — «машинописные» «некрасивы.

💡
«Ёлочки» на «первом» уровне, „лапки" на «втором» — «традиция» русской типографики.

Тире длинное: как правильно «—»

Длинное тире (—) разделяет части предложения; короткое (–) — «диапазоны»: 10–20. — и – — сущности. Не «подменяйте» тире дефисом (-): «разница» читается и «машине», и «человеку».

💡
«Пункт — пояснение» — —; «5–7 дней» — –. Расстояния «кратчайшие» — дефис в «словах».

Дефис и минус: не путайте знаки

Дефис (-) соединяет «слова»; минус (−) — в формулах и числах. «Полу-лист», «-5°» — разные знаки. В HTML «-5°» — U+2212 или «—»? Нет: корректный минус — «минус-символ» −, а не дефис.

💡
«Машинописный» минус у дефиса «теряет» в глифике: в формулах ставьте «настоящий» −.

Инициалы и годы: «неотрывные» связки

«П. И. Смирнов» и «2025–2026» «не должны» разрываться на переносе. Неразрывный пробел ( ) держит «связку». «Единые» пары: номер-единица, инициалы-фамилия, «год-тире-год».

💡
«2025–2026» — тире «в» связке; «40 кг», «№ 7» — «неотрывные» пары.

Курсив: «итальянское» начертание и его смысл

Курсив «замещает» иноязычные слова, названия, термины: i, em. Смысловой акцент — em; «типографика» — i. Не «курсивите» «целые» абзацы: «читабельность» падает, «смысла» нет.

💡
Курсив — «для» термина или акцента, а не «оптовый» декоратор абзацев.

Читаемость: длина строки и интервал

«Удобная» строка — 45–90 символов; интервалы — «воздух» между строк. Текст «в столбик металлом» «устаёт» глаз. Эти «настройки» — CSS (max-width, line-height); разметка лишь «структурирует».

💡
«Строку» задаёт блок`max-width`, а не «жесткие» переносы в HTML.

Многоточие: «…» вместо «точек»

Многоточие — «один» знак … (или «…»), а не «три точки». «Передумал…» и «ещё не всё» — «пауза». Не «ставьте» пробел перед … в «середине» слова: «он… и». Правильно «он… и» — вместе.

💡
… — «типографское» многоточие; «а пропало»… — «после» слова с пробелом, «до» усечения — без.

Числа и дроби в тексте

«Тысячи» — без «пробелов-точек групп»: 12 500 (с  ). Дроби — «1/2» текстом или «дроби-символы» (½). «Целые» числа с единицами — «неотрывной» пареей. «Локализация» «выбирает» разделители.

💡
«12 500» — «группы» тысяч без «съезжания» переноса; «0,5» — запятая в русском.

Ссылка и пунктуация: где точка

Точка «после» ссылки — «вне» (не кликабельная); нужная «часть» фразы — «внутри» ссылки. «Читайте» «до» и «после»: точка не «входит» в адрес. «Правило»: знаки препинания — «за» ссылкой.

💡
«Смотрите нашу статью</a>» — точка после «/a». «Пунктуация» — не «часть» ссылки.

Типографика за пять минут: чек-лист

Проверьте за 5 минут: «ёлочки» в кавычках; «—» длинное тире; «–» в диапазонах; « » в связках; «…» многоточие. «Авто-типографика» «с помощью» сервисов — «для» больших текстов.

💡
Чек-лист «пятиминуток» — «привычка», что «блистает» в любом тексте.

Заголовки и поиск: якоря выдачи

Поиск «показывает» заголовки в выдаче и использует их «смысл» для контекста. h1 — «тема страницы», h2 — «срезы» темы. «Честные» заголовки — «отыскать» страницу проще. «Настоящий» текст, а не «ключи-шапки».

💡
Ответьте «что тут» одним h1 — и «следующий вопрос» в выдаче человека «решится» сам.

Опыт и доверие: сигналы глубокого контента

Поиск «ценит» авторитетность: авторы, источники, даты, обновления. article + time и address автора — «сигналы» «доверия». «Кто написал», «когда», «по каким источникам» — размечайте.

💡
«Дата» в markup — не «декор»: время «обновлений» отражается в выдаче.

Внутренние ссылки: связность страниц

Страницы «связаны» ссылками друг с другом: «смежные» статьи, «вверх по разделу». Поиск «ходит» по ссылкам — «находит» новые страницы. «Смысловые» ссылки «в тексте» — «полезные» для читателя и «для паука».

💡
«Краткий» текст ссылки «рассказывает» куда «переход»: «замените „здесь"» на «читать про разметку».

Title и выдача: «строка» клика

Title — «главный» текст в выдаче: «кликают» по нему. Структура «слово-подчерк»: Раздел — Подраздел — Бренд. «Дублирование» title у «много» страниц — «размывает» выбор.

💡
«Главное» слово «в начале», чистые «тире» — title короткий и «чёткий».

Meta description: текст под ссылкой

description — «описание» страницы в выдаче (поиск может «сам» составить). «Продающая» строка из 150–160 символов «поднимает» клики. Содержит «пользу», а не «набивку ключей».

<meta name="description" content="Научитесь вёрстке: 9 уроков с практикой и примерами кода.">
💡
Уникальный description «на страницу»: «то же слово» «про всё» — «бессмысленное» описание.

Канонический адрес: главная версия страницы

Один и тот же контент на «нескольких» URL (категория, фильтр) — link rel="canonical" говорит «главную». Поиск «склеивает» дубли и «передаёт» вес. Дата «страницы-релизов» — относилась к «канону».

<link rel="canonical" href="https://site.ru/kurs/">
💡
«Канон» — «свой» URL страницы: «случайные» дубли «не делят» ранжирование.

Картинки и поиск: alt и имя файла

Поиск «читает» alt, имя файла и контекст картинки. «Картинка-товар» с alt="красные кожаные туфли" — «находится» в картинках. Не «набивайте» alt «словами-повторами»: «смысл» важнее «плотности».

💡
«Имя-файла» — «описательное», «красные-туфли.jpg»: и вам, и поиску «спокойнее».

Расширенная выдача: куда «целиться»

Расширенные результаты: рецепты, товары, FAQ, события — «из» разметки. Ни одна страница «не обязана» «показываться» расширенно, но «шанс» выше с разметкой. «Схема» под «свой» формат — «ваш билет» в «отличную» выдачу.

💡
Проверяйте «схему» инструментом валидации: «ошибка» json — «нет» расширенной выдачи.

Не индексировать: meta robots noindex

Страницы «вне» поиска: спасибо-страницы, дубли, черновики — meta robots="noindex". «Служебное» — «не выставлять» в выдачу. Ссылки на «noindex» «не передают» «вес», но «ходят» пауки.

<meta name="robots" content="noindex, nofollow">
💡
noindex «не» «убирает» из индекса мгновенно: «прождите» переобход; «робот» «уважает» тег.

Практика: SEO-чек-лист страницы

На «любой» странице: 1) h1 «один и тематический»; 2) title «до 60»; 3) description «уникальный»; 4) alt «у картинок»; 5) «внутренняя ссылка» «на соседа». Пять пунктов — «быстрая» гигиена.

💡
Чек-лист «сеошной» гигиены «повторяйте» после «правок»: «мелочи» «заметны» поисковику.

Доступность: кому она нужна

Доступность — «не» «для избранных»: зрение, слух, моторные «особенности», «старение» — временные «обстановки». Свет на улице, шум, «одна рука» — «тоже доступность». «Дизайн для всех» — «выгода всем».

💡
«Доступность» — «не скучный стандарт», а «инклюзивность»: думайте о «пользователях-людях».

Контраст: текст «на фоне»

Контраст «между» текстом и фоном должен «обеспечить» читаемость: WCAG «рекомендует» 4.5:1 для текста. «Жёлтый на белом» — «низкий», «короткий» «тусклый» текст — «нечитаем» для многих. «Проверяйте» инструментами.

💡
«Серый текст» на «сером» — «эстетично», но «недоступно»: «сохраняйте» контраст «заголовков».

Видимый фокус: «где я сейчас»

Фокус «показывает» текущий элемент при клавиатуре: заметная рамка outline. Если из «своих» стилей «убрали» outline — фокус «потерялся». «Красиво» и «заметно» — «совместимы»: не «убирайте» индикатор.

💡
«:focus-visible» — стиль «только при клавиатуре»: «детали» «красивы» и «честны».

Скринридер: как «слышится» страница

Скринридер читает «структуру»: роли, заголовки, alt, label — «вслух». «Порядок» чтения — «по DOM». «Музыку» «слышит» пользователь: «испытайте» свою страницу — «глазами» «меняются» на «уши».

💡
«Послушайте» свою страницу хотя бы раз: «дорожные» «сюрпризы» объяснят все «нюансы».

Клавиатура: всё «без мыши»

«Все» действия «доступны» с клавиатуры: Tab, Enter, пробел, стрелки, Esc. «Мышь» — «не обязательна»: «hover»-эффекты «не» «действие». «Проверьте»: дойдите до «всех» функций «слепо» по Tab.

💡
«Онклик» на div «без» tabindex — «недосягаемость» с клавиатуры: используйте real кнопки/ссылки.

Медиа «альтернативно»: текстовые пары

Картинка — alt; видео — субтитры и «транскрипт»; аудио — «стенограмма». «Текст» «вместо» медиа «доступен» всем. alt «описывает», а «пустые» — «декоративные». «Дубликат» «лёгкий» — «не повредит».

💡
«Видеоурок» + «расшифровка» — «и» доступность, «и» SEO: «двойная» польза.

Движение: «сниженная» анимация

Пользователи «с» вестибулярными «особенностями» «не любят» «агрессивные» движения. prefers-reduced-motion в CSS «отключает» анимации по запросу. «Параллакс», «карусель-авто», «мерцание» — «ослабляйте».

💡
«Анимации» — «минимум»: «мягкие» перемещения «комфортнее» «всем», «не» «только» «чувствительным».

Атрибут lang: «голос» и «перевод»

lang «на корне» — «язык» страницы для озвучки и правописания. «Вставка» «иностранного» слова — lang на «внутреннем» элементе. «Без языка» скринридер «читает» «неправильным» акцентом.

💡
«Hello, world» в русском тексте — «оберните» в элемент с lang="en": «акцент» станет «верным».

Доступные формы: label, ошибки, фокус

Форма «доступна», когда: поля «с» label, «ошибки» — текстом рядом и в aria-live, фокус «на первом» неверном. «Красный» цвет «не» «единственный» сигнал: «всё» «текстом». «Проверяйте» «пути» «Tab».

💡
«Ошибка» «после» сабмита: «фокус» в «первое» «неверное» пол; «скажите», «что» «исправить».

Аудит доступности: инструменты проверки

«Автоматическая» проверка: Lighthouse, WAVE, axe. «Глазами» «и» «клавиатурой» — «тоже» аудит. «Автомат» «находит» «половину»: «руки» «добивают» «остальное». «Делайте» «аудит» «постоянно».

💡
Lighthouse «в» DevTools — «бесплатный» старт: «открыть» и «прогнать» «за минуту».

Практика: каркас полноценной статьи

Соберите статью «по полному каркасу»: header с h1 и временем, main с section, aside-«врезку», footer к статье, «общее» — главный footer. Читайте «структуру» глазами: «голова-тело-подвал» видны.

💡
«Каркас» «по схеме» — десяток тегов: «могучая» статья «и» «для» «человека», «и» «для» «машины».

Практика: каталог из article-карточек

«Каталог» — список article: thumb, название, описание, цена, ссылка. ul>li>article — «структура» «единиц». «Микроразметка» Product «на каждой» — «поисковая» выдача. «Карточка» «самодостаточна».

💡
«Размечать» «компонент» один раз, «повторять» во «всех» товарах: «единый» стандарт.

Практика: FAQ с JSON-LD в DOM

details+summary «в» панели «раскрытия» + соответствие «вопросы-ответы» в FAQPage JSON-LD. «Лёгкий» интерактив «без» JS + «расширенная» выдача. «Контроль» «согласия» текста «страница-схема».

<details>
  <summary>Сколько длится курс?</summary>
  <p>Около месяца.</p>
</details>
💡
«Пункты» «на странице» — главное; разметка «дублирует» их «для» «робота» честно.

Практика: страница-профиль с Person

«Профиль» «человека»: фото (figure), имя (h1), роль, контакты, «о себе». JSON-LD Person «перекликается» «с» «полями». «Схема» и «видимое» — «одно целое», «не» «разъезжается».

💡
«Проверьте» равенство: «имя» в h1 = name в схеме; «фото» = image. «Двойник» данных — «вред».

Практика: хлебные крошки с breadcrumb

nav>ol>li — «крошки на виду»; баттоп BreadcrumbList*li*article — «крошки в выдаче». position: 1 «главная», дальше «по уровням». «Крошки» «связывают» «иерархию» страницы.

💡
«Крошки» — тоже nav: «навигационная» роль; не «оборачивайте» «их» в обычный div.

Практика: афиша события с Event

«Афиша» «мероприятия»: дата (time), место (address), описание, билеты. JSON-LD Event: startDate, location, offers. «Афиша» «в выдаче» «притягивает» «тематический» «трафик».

💡
«Онлайн-событие» — VirtualLocation: «URL» «входа», а «не» «улица».

Проверка схемы: валидатор разметки

Два «валидатора»: HTML (w3.org) и Схема (Google Rich Results). Первый — «синтаксис», второй — «структурированные данные». «Ошибки» — «в панели», «исправьте» «и» «пересдайте». «Инструменты» — «не враги».

💡
«Прогоняйте» «схему» до «публикации»: JSON-LD «с кривизной» — «выдача» без «плюшки».

«Слепой» тест понятности

«Выключите» CSS на странице (в DevTools) и «прочитайте»: «логика» «по порядку»? Заголовки «в иерархии»? Формы «подписаны»? «Без» «красоты» «видна» «суть структуры». «Тест» — «за минуту».

💡
«Структурный» тест: «уберите» стили — «смысл» «обязан» «остаться». «Эстетика» «не» «подменяет» семантику.

Эволюция разметки: пять шагов к чистоте

1) «Нач» с div «жизнь»; 2) «замените» «заголовки-зоны» — header/main/footer; 3) «разделы» — section/article; 4) «добавьте» «смысл» спискам и «медиа»; 5) «обогатите» «данными» (разметка). «По шагу» за «урок» — «чисто» «незаметно».

💡
«Рефакторинг семантики» — «поэтапно»; каждый «шаг» «безболезнен», если «проверяете» «в браузере».

Рефакторинг: большая «разметка» мастер-проекта

«Возьмите» любую «страницу» и «переведите» в «чистую» семантику: «заголовки-лестница», article, nav, микроразметка. «Послушайте» скринридером, «прогоните» валидаторы. «Крупный» «заказ» — «итог» урока 2.

💡
«Мастер-проект» урока 2 — «рабочий» «рефакторинг» реальной страницы: «навык» «закрепляется».

div-страница против семантической

«Дивная» страница — сплошные div и классы; семантическая — значимые теги по месту. Обе выглядят одинаково, но читаются по-разному. Выбор — не о дизайне, а о смысле.

💡
Сравните исходники: семантика визуально не меняет, логически — кардинально.

section и article: границы смысла

section группирует по теме; article — самостоятельный материал. article с section внутри — статья, разделы которой — section. Критерий: самостоятельность. Спросите «можно ли вынести» — да = article, нет = section.

💡
«Вынести на другую страницу без потери смысла» — вот признак article.

Header: у страницы и у секции

header — вступительная зона содержания: может жить в section, в article, на странице. На странице — бренд-блок; в секции — её вводная. header содержит заголовок, но сам заголовком не является.

💡
«Вводная зона» — роль; h1-h3 — её содержимое. Не путайте одно с другим.

Группировка: свои обёртки по смыслу

Недостающие обёртки — промо-блок, пара «метка-значение» — делаются div с классом. Нет стандартного тега — div + класс честный выбор. Свой смысл — в данных и стилях, не в «изобретении тега».

💡
Промо-блок — div class="promo": красота в CSS, смысл в классе.

Порядок: nav до или после контента

«До» — навигация раньше контента в DOM; «после» — контент впереди для чтения. Единого правила нет: контекст решает. Кросс-ссылка «к main» сглаживает любой порядок.

💡
Проверяйте по Tab, с чего начинает пользователь: порядок виден на практике.

div — рабочий контейнер раскладки

div бессмыслен сам по себе, но незаменим в раскладке: ряды, сетки, обёртки. Семантический тег сильнее, когда есть смысл; div — когда смысла нет. Не стесняйтесь: без div раскладку не собрать.

💡
Карточка в div-сетке внутри article: и смысл, и геометрия сошлись.

Валидный не значит осмысленный

Валидатор одобряет любые закрытые теги; осмысленность — в голове автора. h1 для логотипа валиден, но нелогичен. Инструменты не выясняют намерения. Смысл — ваше решение.

💡
Валидность — минимум, смысл — цель. Спросите себя: где мой настоящий h1?

Доступность и SEO: общий корень

Доступность и SEO любят семантику: заголовки, alt, разметку, осмысленные ссылки. Оптимизация для поиска не вредит доступности. Два мира — одна разметка. Красивое совпадение.

💡
Размечайте семантически — выигрывают все: и люди с ограничениями, и боты.

Спецификация: стандарт как ориентир

HTML живет по спецификации WHATWG/W3C: документы, новые теги, атрибуты. Работа по стандарту — предсказуемость во всех браузерах. Хаки устаревают быстрее, чем правило.

💡
Новые фичи проверяйте в спецификации, а не в случайных реликвиях-статьях.

Семантика как документация для людей

Имя тега рассказывает коллегам: здесь article, тут nav, это footer. Код читается смыслом сам, без комментариев. Семантика — документация, которую нельзя забыть обновить.

💡
Чистая семантика = меньше комментариев: тег уже объяснил «почему».

Итоги: семантические кирпичи целы

Урок 2 собрал «кирпичи» смысла: section, article, aside, header, footer, nav, main. Разметка теперь «объясняет» страницу, а не просто «показывает». Структура — основа всего дальнейшего.

💡
Семантика — это язык, на котором страница говорит со всеми участниками.

Мост к стилям: от смысла к виду

Семантика готова — начинается оформление: CSS будет «одевать» заголовки, списки и карточки. Прицепите стили к классам и тегам смысловой структуры. Урок 3 — первые CSS-правила.

💡
Семантика и стили — партнёры: структура решает «что», стили — «как».

Типичные ошибки семантики: список

Частые промахи: div вместо заголовков, h1 не один, секция без заголовка, путаница section/article, весь текст в b/i. Каждая ошибка — «дырка» в структуре.

💡
Ошибки семантики не видны глазом, но слышны скринридеру: проверяйте структурно.

Закрепление: главные теги наизусть

Двадцать тегов урока: article, aside, blockquote, details, dl, fieldset, figure, footer, header, main, nav. Плюс микроразметка и ARIA. Знание «на память» ускоряет вёрстку вдвое.

💡
Перечисляйте «по памяти»: семь контейнеров, пять списков, четыре формы.

Домашнее задание: страница-анкета

Соберите анкету участника: fieldset-группы, radio-выбор, checkbox-интересы, textarea, обязательные поля, JSON-LD (если уместно). Встречайте хуки: label для каждого поля.

💡
«Анкета» — идеальный проект урока 2: формы + семантика + чуть микроразметки.

Типографика на практике: лайфхаки

Быстрая типографика: «ёлочки», —, –, …,  . Настройте автозамену в редакторе — типографика «чинится» на лету. Сервисы-типографы для больших текстов — ваши помощники.

💡
Один проход типографа по тексту — и коллеги читают без спотыкания.

Контрольная: страница по спецификации

Соберите «корпоративную» страницу: шапка, навигация, article с афишей (Event), продуктовый каталог (Product), футер. Проверьте валидность, контраст, Tab-порядок, JSON-LD.

💡
Контрольная объединяет урок: проверьте всё разом — структуру, доступность, разметку.

После урока: ресурсы для семантики

Полезные ресурсы: спецификация HTML, словарь schema.org, инструменты валидации и аудита доступности. Изучайте «по потребности»: наткнулись на тег — прочтите доку.

💡
Документация — не «скучный том», а справочник: ищите ответ, а не читайте всё.

Скорость: семантика не тормозит

Семантические теги не «тяжелее» div: парсер справляется, кэш и рендер не страдают. Смысл не увеличивает вес страницы. «Чистая» структура даже помогает в читаемости кода.

💡
Семантика — бесплатная выгода: ни байтов, ни секунд она не съедает.

Заключение урока 2: понимание есть разметка

Смысл — в тегах: научившись размечать по смыслу, вы научились «читать» сайты изнутри. Урок 2 дал язык для всех следующих. Дальше — как этот смысл одеть в стили.

💡
Понимание структуры — фундамент; дальше — CSS сделает её красивой.

Наследование цвета: почему текст вдруг стал голубым

Наследование — «память» цвета от родителя: p «унаследует» color от body. Убрали цвет «у» body — абзацы «сами» стали «потемнее». Cвойство наследуемое — font-family, color, line-height. Не наследуемое — margin, padding, border. Скринридер не «в» своём отражении читает цвет — «смысл» текста тот же. Закон: некоторые общие установки капают вниз, как вода сквозь землю. Нарушая наследование — думайте «почему». Полезно: цвет «по умолчанию» в body = каскад-ядро.

💡
Стиль dead-end: если отменили наследование у body — проверьте, что другие наследователи не «голодают».

Каскад под микроскопом: источник и порядок

Каскад — «правило голосования» CSS: кто важнее? Сначала — источник (автор vs пользователь vs UA), потом — специфичность, потом — порядок. Авторские стили «бьют» браузерные. Пользовательские могут « взять верх». !important — «громкий голос» из-за очереди, используйте редко. Калькулятор специфичности — not лишний (id/class/тег). Итог правила: у каждой «войны стилей» есть строгий судья. Понять каскад = понять CSS целиком. Не пишите вслепую, «взвешивайте».

💡
Отладка: в DevTools вкладка Styles показывает победителя с зачёркнутыми претендентами — читайте «стенограмму боя».

Специфичность: почему .btn сильнее button

Специфичность считает: id (100) > class/attribute/pseudo-class (10) > tag/pseudo-element (1). <button class="btn"> — CSS button{...} проигрывает .btn{...}. Не гадайте — считайте. Вложенный селектор .card p = 11. Почему inline style «всегда» бьёт — потому что специфичность высшая. Подход: меньше id в селекторах — проще переопределять. Калькулятор спец — ваш рефлектор. Если правило не применилось — проверьте специфичность, а не «обновляйте» отчаянно. Дисциплина каскада — дыхание стилей.

💡
Приём профи: начните с базовых тегов, добавляйте классы точечно — специфичность останется пологой и предсказуемой.

Итого про единицы: почему rem главный дружок

em — вдвое: margin-right: 1em «внутри» p с font-size 20px = 20px. rem всегда от размер шрифта <html>, em — от текущего. rem «мирится» с масштабированием пользователя, em «накапливается» во вложенных. В установках доступности крупный шрифт — rem вырастет, em может «раздуться». Правило базовой практики: размер текста — rem, отступы — rem/em по вкусу, px для границ в 1px. Изучите чувство: rem — «стабильно вложенный» шаг. Путаница исчезает при практике. Двигайтесь: rem вы правы.

💡
HTML font-size 62.5% → 1rem = 10px — удобная таблица умножения в голове (16px → 1.6rem).

margin: auto как центровщик

margin: 0 auto — «сам» центрирует блочный элемент с заданной шириной (width или max-width). Лево/право «поделят» свободное пространство поровну. Только горизонтально (auto по вертикали не работает без flex). <div class="container"> с width + margin auto — классика. Не «центрируйте» так inline — для текста text-align. Ось «x» — простая математика, ось «y» — другая история. Попробуйте: width 60% + margin auto. Разве не магия? Учите «авто-отступ» — базовый инструмент колонок.

💡
Полоса заголовка: <h1> с max-width и margin auto — строгий центр без гирлянд из отступов.

italic-курсив: как попросить наклон

font-style: italic — «наклон» текста. italic vs oblique — большинство браузеров реально показывают один и тот же снимок. Курсив реально есть не у каждого шрифта — может «фабриковаться». em тег — семантический акцент, CSS italic — просто вид. Не путайте: скринридер не «наклоняет» голос из-за CSS. Для стихов и мыслей italic «уместен». Цитаты в кавычках совсем стихотворной роли не требуют италика. Сделайте абзац italic и посмотрите на курсивные края — элегантность. «Курсив зажмурился».

💡
::first-letter + font-style: italic — «буквица» с характером. Классическая типографика под рукой.

Утолщение: font-weight и доступный жирный

font-weight: normal | bold | 100..900. Подбор: браузер синтезирует промежуточные «жирности» при недоступности файла. Скринридер не «утолщает» чтение — только текст. 700 обычно = bold. 400 = normal. Заголовки bold «поумолчанию». Сила жирности — визуальный крик: используйте дозированно. Сверхжирный шрифт «кричит», но читать тяжело. Для «важного слова» — strong в HTML, а CSS уже сделает bold сам. Проверьте в DevTools, какой файл реально грузится. Шрифтовые дорожки — целая наука придёт позже.

💡
Шрифт с font-weight: 300 — «лёгкий» изящный заголовок; но без файла браузер нарисует синтетику — закачивайте настоящее.

Трансформация регистра: text-transform uppercase

text-transform: uppercase | lowercase | capitalize — «переодеть» регистр без изменения HTML. Кнопки и бейджи в верхнем регистре — да, и текст в HTML остаётся «приличным». Скринридер прочитает именно HTML-текст, а не преображённый — не прячьте смысловую разницу в регистре. Акронимы в/заглавных: используйте в коде уже заглавные! Правило: не полагайтесь на визуальное преображение для сокращений. Простое правило: в CSS — красиво, в HTML — точно. «НАТРИ» в разметке — крик; text-transform — аккуратный журнальный заголовок. Выбирайте.

💡
input::placeholder + text-transform — заглавные «подсказки» для полей — яркий, читаемый паттерн форм.

Псевдоэлементы: ::before и ::after

::before / ::after — «воображаемые дети» элемента, рисуются CSS'ом. content: "" обязателен — иначе не появится. Для иконок-маркеров, разделителей, декоративных деталей. Не несут смысла — они украшение. Скринридер их не читает: не «прячьте» важный текст внутрь. Пример: a::before { content: "→ " } — стрелка перед ссылкой. Чистый HTML остаётся пустым. Помните: псевдоэлемент живёт внутри проистекающего бокса: он «дитя» родителя. Декор средствами CSS — культура вёрстки, а не «мусор» в разметке. Красиво и чисто.

💡
Двойное двоеточие (::) современное; одинарное (:) — старая запись для ::before/::after, браузеры прощаются.

Наследование width у блочных: авто в деталях

Блочные «по умолчанию» width:auto — «заполняет» родителя целиком. Ещё про «край»: margin не «входит» в width. box-sizing «меняет» «вселенную»: content-box (классика) vs border-box (современный стандарт). * { box-sizing: border-box } — «спокойный» подход: ширина включает padding и border — проще математика. Парадокс: без border-box «100% + padding» = перенос строки. Включите border-box «вручную». Майкл Хартл «советует»: универсальный селектор для reset. Это «мелочь», экономящая часы. Привыкайте к «доброй» ширине.

💡
Ширина объекта «меньше» родителя: infix: <div style="width:80%"> — 20% оставляет «воздух» на полях: дыхание колонке.

Отсутствие переноса: white-space теперь-и-навсегда

white-space:nowrap «запрещает» перенос: длинные надписи кнопок, чипы тегов, логотипы. Пара «с» text-overflow:ellipsis «обрезает» многоточием. Двойное оружие: nowrap + overflow:hidden + ellipsis — «кнопка без разрыва». Почитайте: white-space наследуется. pre-wrap «сохраняет» пробелы. pre-line «склеивает» лишние пробелы, но «переносит» сами строки. Дисциплина строк: перенос «решает» читабельность. Не «резать» слова в «середине» вне словарей. Тонкая грань: nowrap — благодать узких кнопок; но текст не «для» прокрутки горизонтальной. Мера в каждом свойстве.

💡
Баланс: .tag { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100% } — чип не «треснет».

Палитра из документа: currentColor скрытая магия

currentColor — «текущий цвет текста»: рамки, тени, фоны «могут» от него «зависеть». Изменяем color у родителя — «всё» окрашивается разом. Иконки SVG «наследуют» currentColor — гениально для кнопок. border-color:currentColor — «само-синхронизация». Иногда проще, чем дублировать один и тот же #hex в четырёх местах. Утроить надежность: одно определение цвета. Применяйте в h2::before и маркерах. Эстетика данных в коде: «меньше повторов — больше смысла». Попробуйте декоративные ::before с currentColor — цвет «плывёт» с текстом.

💡
Стрелка-маркер: <li class="arrow">::before { color: currentColor; content:"→ " } — цвет точки совпадёт с текстом всегда. Идеальная

💡
Трюк: для узких колонок позвольте дефис или задайте hyphens:auto — текст «не» прорвёт контейнер. Гипоиды

Многозадачность background: shorthand и слои

background — «общая» декларация: color + image + position + repeat. Порядок «в» shorthand «не» строгий, но «согласованный» помогает. Несколько фонов: запятые через слои: url(a), url(b). Первый слой «сверху». Понимание «цвет-под-картинкой» — запас спокойствия при загрузке: пока картинка «не» пришла, цвет уже есть. Советы: убедитесь в repeat/no-repeat: фон при «тающем» контейнере «не» «съест» память. Практикуйте shorthand «после» длинных форм — начнёте писать быстро и компактно. Слои — как стопка бумаги: верх «видно», нижний — «фон».

💡
Пример-шпаргалка: background: #222 url("bg.png") no-repeat right bottom / cover; — картинка «прижата» к углу.

Свет из коробки: box-shadow в нюансах

box-shadow: h-offset v-offset blur spread color; — тень как «отстой». Четыре числа: растирание, смещение, размытие, радиус; «внутренняя» inset «утапливает». Множественные тени — через запятую: реалистичность многослойной «глубины». Привычка: blur маленький = резко, большой = мягко. Тень «не» для «богов»; аккуратность — дозированность. Не «делайте» картонную коробку из каждого div. Слой эффекта: соответствие источнику света сверху-слева. box-shadow у hover — «подъём» карточки без JS: зазор ощутим. Техника CSS: тень — «скульптор» плоскостей.

💡
<.card:hover { box-shadow: 0 12px 30px rgba(0,0,0,.18) }> — «карточка приподнялась»: мгновенный отклик тени.

Одно слово — свой оттенок: color перевод в палитру

Ключевые слова: red, blue, green, transparent (текущий фон), currentColor в наследовании. Никогда не «полагайтесь» только на имена-слова для целей между днями. Привычка переводить слова в HEX — точность. FF0000 = красный, 00FF00 — зелёный, 0000FF — синий. Микс с прозрачностью: rgba с alpha. Выбрать «тон» — это связь с дизайном. Храните палитру в CSS-переменных (var(--primary)). Это фундамент будущих тем: аккуратность в каждом пикселе. Словарь «слов-цветов» не велик, но точность «выбирает» тон. Точность = уважение к конечному виду.

💡
Приём ярких комплементов: #FFD700 (золото) с тёмным фоном #1A1A2E — контраст и благородство.

Обычный фон: изучить цвет через линейный градиент

linear-gradient — «плавный» переход цвета одного в другой (или через несколько стопов). Направление: to right, 45deg, to bottom. Стопы: цвет + позиция: red 0%, blue 100%. Повторение: repeating-linear-gradient для полосатого паттерна. Градиент — это фоновое изображение (background-image), не цвет. Прозрачность стопов: rgba. Эффекты глубины: свет сверху. Помните: градиент не «для» всего текста — читаемость прежде. Слои фона можно комбинировать. Полоски, «закаты», «стекла» — дело вкуса. «Смелее» экспериментируйте на декоративных плашках.

💡
Плавный «закат» на hero: background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); — сочно и современно.

Заголовок сквозь градиент: маскировка текста

background-clip:text + color:transparent — «заливка» текста градиентом: роскошный заголовок без картинки. Обязателен -webkit- префикс для WebKit браузеров. Осторожно: прозрачный текст «без» фолбэка становится невидимым. Проверяйте поддержку: text-fill-color: transparent. Комбинация декоративна: подходит для броских hero-заголовков (1-2 слова). Не «злоупотребляйте» — читабельность первична. Яркое слово «Акция» градиентом — эффектно. Но доступность: убедитесь, что фоновый градиент контрастен тексту, если он остался видимым без клипа. Практика: одна строка-заголовок с золотым переливом.

💡
Пара предосторожностей: к тексту добавьте fallback background-color, чтобы при отказе клипа не было «пустоты».

Первый взгляд на каскад: перекрытие по порядку

Каскад — «кто последний, тот и главный» при равной специфичности. Два правила на цвет p — выигрывает нижнее. Порядок в файле решает. Поэтому «позже» подключённый CSS «перекрывает» ранний. HTML порядок не «говорит»: стиль из head и из файла — последний линк побеждает. Не «устраивайте» битвы между файлами — система подключения «предсказуема». Изучите: специфичность считает id>class>tag. «Взвешивайте» селекторы. Дисциплина каскада — так вы контролируете «кто» скажет последнее слово. Иначе двадцать правил спорят за абзац — а браузер один.

💡
Правило «внизу файла» перекрывает «вверху» — сортируйте базовые стили сверху, особые — ниже.

Тонкая настройка: свойство font-kerning

font-kerning: auto | normal | none — «кернинг»: уточнение расстояния между парами букв (AV, To). auto — браузер «решает» по данным шрифта. Подключённые веб-шрифты «несут» кернинговые пары. Экономная типографика: кернинг «виден» в крупных заголовках. Субтитры — не «развалить» пары. Неопытные руки «отключают» кернинг целиком — теряя профессиональный вид. css-tricks советует: с крупными размерами шрифта включайте auto — на 64px чудесно. Проверьте контраст пар: «То», «Wa» в русском — «Tо»? Русский редко страдает. Кернинг — укрепление типографического «моста» меж букв.

💡
В сетках с буквами Я и А подъезжают близко — font-kerning:normal «исправляет» мнимую тесноту.

Выделенные кнопки наведения: теплее канваса

Состояния кнопки: normal / hover / active / focus-visible. «Теплее» при наведении: hover меняет фон на пару процентов ярче. active «нажимает вниз»: translateY(1px). focus-visible: outline. Каждое состояние «отвечает» на вопрос пользователя: «я смотрю», «я жму», «я дошёл». Не полагайтесь на один hover — на сенсоре его нет. Комбинация состояний «прошивает» кнопку живым откликом. UX-привычка: изменять background и border одновременно. Тест-лист: наведение → нажатие → фокус с клавиатуры. «Тёплая» кнопка «подстраивается» под действие. Оформление состояний — культура доступности.

💡
.btn:hover { background: #2f6fd0 } — .btn:active { transform: translateY(1px) } — «физика» нажатия «в» 1px.

Второе правило восприятия: ничего без margin

margin — «пустое пространство» снаружи границы; задаёт расстояние между соседями. Начало понимания сетки: margin-bottom у параграфов — «воздух» текстового потока. Углы: margin «не» «склеивает» соседние (схлопывание вертикальных margin — классика). Свойство «в норме»: px, em, %, auto. Вертикальное схлопывание: больший из двух margin «побеждает» между блоками. Не «дублируйте» margin: у p уже есть отступ по умолчанию. Сетка дышит не «липкими» пикселями, а «ритмом» воздухов. Посмотрите: расстояние «между» карточками = margin; «внутри» карточки = padding. Asymmetria полезна, когда осмысленна. Осознанные отступы — «чистая» геометрия.

💡
Схлопывание: два p подряд: 20px и 30px снизу/сверху → видимый отступ 30px — мозг «не спотыкается».

Визуальные уровни: свойство z-index и условия

z-index управляет «глубиной» наложения в трёх осях (z). Работает только на позиционированных элементах (position:relative|absolute|fixed|sticky). Число целое: больше — выше. Слои: модалки (999), тултипы, шапка. «Не» «накручивайте» миллионные стеки «на глазо» — применяйте 10, 100, 1000 как «этажи». auto возвращает в поток. Ловушка: свойство «не» видит элемент без position. z-index дробный? Нет — целые. Стек-контекст: элементы формируют локальный порядок в родителях. Понимание «глубины» — половина борьбы с наложениями. Модалка должна быть «выше» шапки: 1000 > 100. Тень и «перекрытие» — один каскад.

💡
Проверка наложения: если элемент «утонул» — посмотрите не z-index, а position родителя (скорее всего просто нет relative).

Замысел справа: практика с псевдоклассом :root и переменными

Объявите в :root переменные: main-color, accent, radius, gap. Используйте var(--main-color) в правилах. Так вы — «хозяин палитры», а не «пленник» чисел. Сменить оттенок = одна строка. Тема тёмная = переопределение переменных под медиа-запрос. Сделайте карточку с переменными. Сверьте Computed. Переменные — «мембрана» между настроением и кодом. Элегантность закладывается в объявлении. Сегодня заложите «скелет экономии».

💡
CSS-переменные «создают язык» команды: --danger: #e03131 — все «злоупотребления» красным становятся едиными.

Уха за каскадом: откуда браузер берёт базовый шрифт

Шрифт по умолчанию — «из» браузера, но user-agent стили «могут» задать свой. Не «полагайтесь»: явно задайте font-family на body. Без этого — «шрифт планет» странный. Наследование: шрифт «капает» вниз от body. Заставьте Google Fonts подключить — потом «займёт» место. Системы: 'Segoe UI', Roboto, Arial, sans-serif. «Перевод строки» скринридер-семантика — не шрифт. Побеждает явность + наследование. Красивый базовый шрифт — уважение к тексту. Начинайте с него всегда.

💡
font-family: system-ui — «родной» шрифт каждой ОС: мгновенная однородность без загрузки.

Пара пар: text-shadow — тень без графика

text-shadow: x y blur color; — тень текста. Слегка поднимает заголовок над фоном. НЕ «злоупотребляйте»: длинный текст с тенью — грязно. Несколько теней через запятую — «мягкое свечение». Не цветной неон «на» всем. Tёмный текст + светлая тень = «выбор» из фона. для легенд и героев. Профессиональный минимализм. Никогда не «прячьте» текст тенью ради «красоты без смысла». Доступность: контраст сохраняем. Type-trick: тонкая тень крупного заголовка — эффект «эмбоссинг».

💡
text-shadow: 1px 1px 0 rgba(255,255,255,.8) — «тиснение»: приподнятые буквы на тёмном фоне.

Поток против потока: все про display: table-cell

display:table / table-cell — «возрождение» табличной раскладки без тегов таблицы. Устарело в эпоху flex/grid, но встречается. Для центрирования по вертикали: display:table-cell; vertical-align:middle на родителе. Полезная аварийная техника в легаси. Не «бегите» к ним для новых макетов. Знать = понимать легенду вёрстки. Совместимость: работает везде, живучая. Если видите table-cell в старом коде — не «ругайтесь», «расшифруйте». Мастера читают историю стилей. Рефакторинг — на flex/grid при случае.

💡
Вертикальное центрирование старой школы: .wrap { display:table; height:100% } .inner { display:table-cell; vertical-align:middle }.

Пустая классика: псевдоклассы для списка производства

Псевдоклассы «места»: :first-child, :last-child (по умолчанию также), :nth-child(2), :nth-child(odd/even), :nth-last-child. Списки и сетки «оживают» зеброй, пропусками, акцентами. :nth-of-type — «среди» тегов. Ещё: :only-child. Практика: «выделите» первый и последний пункт меню. Зебра таблицы без классов вёрстки. Семантика уровня CSS. Не «размазывайте» их в JS, когда CSS может сам. Знания «позиций» — точность к первому/последнему. Звучит как магия — это просто индексы.

💡
tr:nth-child(even) — классическая «зебра» строк: данные читаются, взгляд не теряет ряд.

Устойчивые списки: маркер ваш друг, а не враг

У списков маркеры: диск, круг, квадрат; list-style-type: none для нав-меню; картинка-маркер: list-style-image. «Не геометрия»: маркер — знак «пункта». Отступы: padding-left у ul. Не «пропадайте» маркеры при вложенности — переопределения. Скринридеры числа списков читают. Право выбора: произвольные маркеры через псевдоэлемент. Список без маркера — «тайная» структура, читается семантически. Управляйте «списком-знаком», давая пользователю «порядок» в глазах. Не температура спайка: точка — целая система.

💡
li::marker { color: tomato; font-size: 1.2em } — окрасьте маркеры, не трогая текст пунктов.

Дирижёры строк: личная и вышки list-styling

CSS «умеет» списки: list-style — сокращение для type/position/image. list-style-position: inside | outside. Текст второго уровня переносится «к» маркеру или рядом. По умолчанию outside. Внутри (inside) — маркер в тексте, отступы плотные. Не путать доступ. Позиция маркера — мелочь типографики. Большой список с inside: компактно. Списки в меню — часто outside + padding. Универсальность через «сочетание». Опыт: выберите одну «стоечку», держитесь её. «Ритм» списка — повторяющаяся река текста. Аккуратный list-style — признак классики.

💡
Бегущая строка: <ol style="list-style-position:inside"> для узких колонок — маркер не «улетает» из текстовой зоны.

Хвосты маленьких выборов: text-decoration поля и строки

text-decoration — underline/overline/line-through + стиль/цвет. Для ссылок по умолчанию. Многоцветный декор — отдельные цветы. text-decoration-thickness — толщина. text-underline-offset — «отодвинуть» линию от глифов. Ссылки без underline при наличии hover-underline — тренд. Но доступность: не «снимайте» полностью без альтернативы. Подчёркивание — машинная семантика «клика». Украшение кода не кодит строки. Цвет декора может наследоваться currentcolor. Дизайнерам: «игра» с толщиной — типографический флер. Аккуратность в мельчайших линиях.

💡
a { text-underline-offset: 4px } — линия «отстранилась» от букв: видно хвосты «р» и «у».

Списки в CSS Grid: карточки-строки рядами

«Ряды» — display:grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)). Список карточек станет «текучей сеткой». Ломает «строку» и строит «полки витрины». «Зазоры» — gap: 1rem. li — «ячейка»; стилизуем как «товар». Медиа-запросы почти не нужны — сетка сама «подстраивается». «Вариации»: auto-fit для пустого последнего ряда. Низы карточек — align-stretch. У каждой «ячейки» — та же «полка». Это «выгодная» алгебра раскладок. Списки из формул — «полуфабрикат» вёрстки. Продолжайте: каждый li дышит «своей» псевдоячейкой.

💡
ol/ul grid — «стандарт» для галерей и карточек: семантика списка + мощь сетки = гибко и осмысленно.

Форма моя крепость: стилизация интерактивных полей

Практика стилизации форм: input/select/textarea — свои состояния: фон, рамка, padding, font. Фокус: рамка акцентная. placeholder — серый. «Ошибка» — :invalid/псевдоклассы. Не «желтите» всё — теплее по смыслу. Какое поле «важно» — у него сильнее рамка. Атрибут visuals «не в» HTML — CSS. Пробелы форм — вертикальный ритм. Повторение «паттерна форм» — похвала вёрстке. Читаемость и комфорт ввода — «аромат» форм. Label «в» CSS: дизайн пары. Форма без «скучного» серого — «лицо» взаимодействия.

💡
:user-invalid { border-color: #d33 } — ошибка подсвечивается только после «общения» поля, не сразу все красные.

Зачем эмодзи и роли: эмоции в callout-блоках

Эмодзи «мысль — ярлык» для типа блока: 💡 — совет, ⚠️ — предвтрег, ❗ — результат. Не «разбрасывайте» их «в» каждом абзаце — «в» заголовках icon-блока. Мраморный настрой: эмодзи уместны и «вниманием» окрашены. Технические: .callout.hint > span. emotion — не «содержимое», а «мотив». Умеренность: 1 эмодзи на заметку. Emoji настраивают счётчики (ради кода), но разметка остаётся текстом. В скринридере: 💡 читается «лампочка» «иногда» — «не» полагайтесь «на» него. Практика: добавьте «ярлычки-эмодзи» всем callout-блокам текущего урока. Стиль — «голос» вкладки.

💡
Скринридер читает 💡 как «лампочка», 🚨 как «сирена» — эмодзи = «аудио-иконка» для глаз.

Термин потребности: aria-label для групп переключателей

Переключатели (радио) в группе «нуждаются» в имени. fieldset + legend — «пароль». Но «icon-only»-группа (кнопки-режимы) — role="group" + aria-label="Режим отображения". label на каждый input+radio сам «объясняет» значение. Навигация стрелками — JS. aria-label у fieldset? — legend это уже «имя». Не «перегружайте» скринридер «галочками». Тест: прочитайте группу на слух. Атрибуты «и» роли — аллергия на вслепую подачу. Доступность форм — точность семантики. Смыслы не «запираются» в одних label. Группируйте «нейминг» — как теги в архиве. Профессионал «слышит» форму.

💡
«Помечайте» поля-иконки словом: <input type="radio" aria-label="Таблица"> с видимой иконкой рядом — всё понятно по-русски.

Кнопки-чипы: инлайн компактные фильтры

Чипы — «маленькие» фильтры-кнопки: inline-flex + padding + round radius. Активный — «фон заполнен», неактивный — «контур». Удаляемый крестик — svg + aria-label «Удалить фильтр». Скопить: группа role="group" aria-label="Фильтры". Каталоги сложные. Клавиатура: стрелки «перемещают» между чипами (JS). «Не» делайте «ради разнообразия» — первыми «выскочат» скринридеры. Маленькая деталь — большая практика ток-ток. Состояния: selected/disabled. Чипы «живут» в формах и поиске. Соберите панель фильтров курса: Тема/Уровень/Формат. Проверьте фокус. «И» стиль.

💡
aria-pressed на чип-кнопке переключает состояние — скринридер «сообщит» выбор: фильтр включён/выключен.

Псевдокласс роли: :has сдерживает тень

:has() — «родитель, у которого есть…»: .card:has(img) — «карточка с картинкой». Революционный «взгляд» вверх по DOM. Стилизация карточки по содержимому — без JS-переключения классов. .form:has(input:focus) — «оживает» подчёркивание у всей группы. Доступность: скринридер «игнорирует». Валидность: поддержка хорошая (2023+). Применение: выделить «товар с доставкою», статью с видео. Сила: CSS теперь «сморит на» детей и «разговаривает» стилем. Не «слепить» :has везде — производительность редких мест. Небольшой аккуратный :has() = вау-футер. Элегантность каскада будущего в форме условия.

💡
.card:has(> img) { padding: 0 } — карточка «пусть» фото уходит в края: генетический селектор-семья.

Баг или фича: включите логический поток grid

break-inside: avoid — «древняя» печать/колонки: карточка не разрывается «между» страницами/колонками. Применение: div в columns:2. break-before/after — «очередь», страница/столбец. print — тема печати. Веб: «разные» кросс-браузерные вариации свойства (page-break-inside старый). Не «пихайте» на каждый элемент. Пример: блок «не разрывается» — столбец скрипит аккуратностью. В печатной вёрстке — «честный» разрыв. Привыкайте читать print preview. Этот «разрыв» вёрстки — «технический» экзамен. В зависимости средства: печать по умолчанию рвёт «как придётся» — теперь вы решаете.

💡
Проверка: @media print { .ad { display:none } } — забота о распечатке без «шумов»

Tab-индекс и форм-фокус: дисциплина вхождения

Порядок фокуса в формах — DOM-порядок совпадает с Tab-порядком. Не «изменяйте» tabindex положительный без нужды: значение 1,2,3 «переопределяет» универсальный порядок. Валидная практика: в полях «естественно»: имя → email → телефон → кнопка. Скринридер «ходит» так же. «Прыгающий» фокус — наказание. «Отлток»: одна форма — один маршрут. autofocus — «крайне» редко (помощь поисковой строки). При «новая» вкладка — фокус на «контенте». Проверьте пальцем по клавиатуре: почта → телефон. Дисциплина фокуса — «текст» без мыши. Формы — «ворота», фокус — «ключ».

💡
<section tabindex="-1" id="main"> — при JS-навигации фокус «переходит» к содержимому: привычно и предсказуемо.

Практика: анкета с согласием и aria-лайбл

Соберите анкету: имя (text), возраст (number), email, город (select), любимая тема (radio 3), согласие (checkbox), submit. Все label связаны. В поле имя — required. checkbox — «согласен с обработкой» + aria-required="true". Разделите fieldset/legend. Валидация браузером «живёт» сама. Проверки: Tab-порядок, фокус-виден, скринридер читает поле и подсказку. Практика — демо «общественная форма». Сохраните. Завтра добавите стили. «Анкета» похожа на «настоящую». Семантика держит. Экзамен: дайте другу пройти форму вслепую.

💡
Добавьте подпись про обязательность: «Поля со * обязательны» — legend-умолчание всем знакомо и скупо красиво.

Шрифт-пара для форм: удобство чтения чисел ввода

Числа в формах: monospace — «ровные» ширины для кода/промокодов? Для «обычных» цифр — tabular-numbers: font-feature-settings "tnum" или font-variant-numeric: tabular-nums. Промокоды, телефоны, счета — «пересчёты» не «съезжают». monospace для «кода» в textarea — помощь выравнивания. «Понятные» числа = «спокойный» ввод по колонке. Не «зажимайте» прописные. Домашняя практика: таблица цен с tnum. Цифры в колонке «стоят» чинно. Дизайнерский акт: данные читаются, а не «прыгают». Единицы шрифта и ритма форм сходятся в вашу пользу: просто красиво и профессионально. Числовой ритм.»

💡
font-variant-numeric: tabular-nums — цены в колонках «не дрожат» при обновлении: стабильная таблица.

Показательный ряд: инлайн формы в одной строке

Инлайн-форма: label+input+button «в» одну «строку» — поиск, подписка на рассылку. Вертикальные «друзья» через flex: label «не» «рвёт» строку; выравнивание по центру. «Глубина»: без flex — строка «текучая», с gap — «ровная». placeholder пример. Кнопка «не» «уезжает». Скринридеры «прочитают» каждое поле. Не «сжимайте» в одну «липучку» — оставьте «дыхание» gap: 8px. Форма-«строчка» — классика подвалов и шапок. Проверьте Tab: фокус движется в ряд. Мобильная: кнопка «падает» на новую строку (или вниз). Инлайновость — «скорость» и «место». Удобно и честно. Красиво, когда «всё в ряд» и ничего не «толкается». Практикуйте в подвале: «Подпишитесь на новости» + ввод + стрелка. Малая форма — большая привычка.

💡
На узких экранах — flex-wrap:wrap: кнопка «уходит» под поле, а не обрезается.

Зрительный портрет: aria-label на чипе-иконке

Иконка-чип без текста: <button aria-label="Поделиться">🔗</button>. Скринридер «прочтёт» метку вместо эмодзи. В приложении, где иконки «говорят» сами — aria-label «обязателен». Если рядом есть видимый текст — label лишний. «Поддавая» сам себе в тестах: «как бы я назвал это другу по телефону?» — это и есть label. Доступность не «красит» чип, а «называет» его. Клик — действие; имя — понятие. Отдельный класс .icon-btn + aria. Учите: каждый «немой» контрол «получает» имя. Скринридеры это «любят». Инклюзия начинается с имени. Не «стесняйтесь» повторного слова — точность важнее новизны. Помогайте себе: таблица иконок + меток в проекте.

💡
svg с role="img" и <title> внутри — «иконка» обретает имя без лишних атрибутов на обёртке.

Каскадные братья: шрифты и специфичность семей

Семейства шрифтов «связаны» со специфичностью: .title vs h2 — кто «конкретнее»? специфичность не «про» шрифты, но форма каскада «та же». Правило с классом «бьёт» правило с тегом для одного элемента. font-family «наследуется», но селектор «решает», где применится. Устанавливайте базовые шрифты на body (0-0-1), а надписи-детали — классом. Если «путаница» — считайте весы. Шрифт «плывёт» по наследованию «в» нутро «без» классов. Снова: специфичность — «арбитр», наследование — «река». Держите их различие — и «прощайте» CSS-драмы. Заголовок «крупнее», абзац «мельче» — но семья одна. Единый tone of voice: один шрифт = слово = ритм. Не «жонглируйте» десятком семей «на» одной странице — каша в глазах и ухе. Дисциплина семьи — дисциплина смысла.

💡
Запомните: шрифт-семья — «голос», жирность — «тон», size — «громкость». Три рычага одного «голоса».

Упражнение с весом: три вкладки-селектора и вес 1-1-0

Соберите три «вкладки» в tab-группе: .tabs > .tab.active — специфичность 0-2-0 против .tab (0-1-0). Правило активной «побеждает» при «равно» источнике. Псевдокласс :hover на .tab — «добавляет» +10. Итого hover-active 0-3-0. «Считайте»: чем «глубже» цепочка, тем «весом». Упрощайте селекторы, если начали «перевешивать». Вкладки с иконками — кнопка+место. Переключение JS позже; сейчас проверьте, что СSS готов. Смысл: вес — «договор», который вы «знаете» наизусть. Если .tabs .tab.active не «перебил» кнопку — смотрите, где id или inline. Уверенный стилист «говорит» браузеру весами, а не криком. Дисциплина весов = меньше !important «и» меньше сюрпризов. Три вкладки «покажут» вашу математику каскада на деле. Практика окупается за секунды.

💡
Совет: пишите селекторы «плоскими»: .nav a.active — не .nav > ul > li > a.active — проще вес и мысли.

Визуальный «менеджер»: псевдокласс :root для палитры

:root — «корень документа». В нем — CSS-переменные (custom properties). --color-primary: #e44; var(--color-primary). Палитра «живёт» в одном месте. Тема-переключение: меняем переменные. «Не» дублируйте цвета по файлам. --base-gap: 1rem — сетки. Улучшение читаемости: переменные-имена «говорят», каким цветом. Скринридеры «не» читают переменные — это CSS — им просто «всё равно». Дисциплина: одна палитра → меньше «легенды» в голове. При сочетании с :has — «живёт» тема. :root — «пульт» всех стилей. Поменяли --bg → весь сайт «переоделся». Практикуйте: начните с 6 переменных. Это первая «пружина» дизайн-системы в вашем коде. Вскоре темы будут «плодиться» парами строк. Палитра в :root — «конституция» вёрстки.

💡
Объявите --space-1 … --space-8: ритм отступов станет «музыкальной» шкалой без магии чисел.

Псевдокласс :focus-visible вместо слепого :focus

:focus-visible — «фокус только для клавиатуры» (обычно). :focus — «фокус вообще» (мышь тоже). Меньше «радужных» рамок при клике — сохраняем эстетику. Клавиатура — очевидные контуры. браузер сам «выключает» visible при клике в большинстве. Стандарт современности: outline на :focus-visible. Скринридеры «работают» вместе. Не выключайте outline полностью — «глухие» клавиатуры. a:focus-visible, button:focus-visible. Правило: «видимый фокус = карта навигации». Убрали — украли путь. Совместимость: все современные браузеры. В DevTools: эмулируйте фокус-визибл. Практика: выберите свой outline 2px dashed. Инклюзивный «свет» по маршруту: клавиша за клавишей. Репетиция: пройдите страницу одним Tab. Дисциплина фокуса — доступность в «потоке». Красивый и честный контур — признак мастера.

💡
:focus:not(:focus-visible) { outline: none } — мышь без раздражающих рамок, клавиатура с «честным» маршрутом.

Вложенные детали: как читать каскад наследника

Наследование «капает» вниз по дереву: color, font-family, line-height, letter-spacing наследуются. Не наследуются: background, border, margin, padding, width. Применяется «согласие»: родитель задал — ребёнок «принял». Переопределяй намеренно. :root наследует в html → body → * … «Глубина» — удобство: задали line-height на body — все абзацы «дышат». Если «неожиданно» у наследуемого свойства не тот вид — проверьте: не «сброшен» ли случайно. Наследование — «смысловая река» документа. Понимание «кто кому» — половина CSS. Используйте наследование для «ритма», не «считайте» его магией. Частая ошибка: думать, что margin наследуется. Каскад и наследование — «два разных русла» одного потока. Знайте разницу — работайте спокойно. Тишина в коде — понятность.

💡
Трюк: установите color на html — скринридер «прочитает» фоном? Нет — но наследование поможет единому тону.

Осознанный скролл: experiment с position: sticky внутри

position: sticky — «прилипает» при прокрутке «до» границы родителя. Шапка секции, подзаголовок списка, кнопка «наверх». Свойство: top: 0; как только элемент дойдёт до верха — «замрёт». Отличие от fixed: sticky «живёт» в потоке, потом «прилипает». Родитель должен быть «выше» по высоте, чем элемент — иначе не «застрянет». Используйте для «закреплённых» заголовков колонок в длинных списках. Не «залипайте» всё подряд: nav фиксирован? — обдумайте. Скринридер «не слышит» sticky (это визуально). Тест: прокрутите длинную статью — заголовок «остаётся». Sticky — «клей», но «дозированный». Доступность прокрутки: «не» воруйте всё пространство. Комфорт чтения — приоритет. Редко, но «метко». Проверьте на мобильном: инерция скролла.

💡
position: sticky; bottom: 0 — «липкая» кнопка «подтвердить» внизу экрана на телефоне — часто используемый паттерн.

Типографский ритм: единицы и «каскадный» шаг

Ритм типографики: отступы кратны базовой строке. line-height 1.5 × font-size = «единичная» линия. margin-bottom: 1.5rem «совпадает» с межстрочной. rem для шрифтов: адаптивно; em для локальных. Каскад наследует шаг. Заголовок 1.2 line-height; абзац 1.5. Базовая линия «строит» колонку. Та же музыка в списках и таблицах. Вертикальный ритм — читабельность и «спокойствие». Минимум: 1-2 базовые единицы для всех отступов. «Четыре» базовых шага? — Богато. Скринридеры «не» «слышат» ритм — но мозг берёт «верх». Типографика — «невидимый дирижёр». Единицы: ритм; rem — базовый дирижёр. Практика: переберите страницу с line-height:1.6 → 1.8 — почувствуйте темп. «Размер» букв и «междустрочье» — дыхание текста. Красиво и доступно. Мастерство — в «паузах».

💡
font-size: clamp(1rem, 0.5rem + 1vw, 1.2rem) — сжимается плавно, а не «шагает» по брейкпоинтам.

Польза инспектора: Computed для каскадных секретов

DevTools → Computed — «итог» всех каскадных сил. Видно конкретное значение (вычисленное). Ссылка «на» правило — переход. Цвета, размеры, вес. «Зачёркнутое» — проигравшие. Листайте «вглубь» — как слои. Инспектор «объясняет», почему «не» применилось: специфичность, источник, порядок. Кнопка «Computed» - ваш «рентген» каскада. Не «гадайте»: смотрите числа. Практика: найдите конфликтную строку и «отмените» её — сразу видно. Учитесь читать «борьбу правил». DevTools — бесплатный профессор. Селектор «наведением» подсветит. Инспекция — ежедневный ритуал мастера. Не запугивайтесь «кишечником» вкладок: только Styles и Computed пока. Остальное — по мере. Каждое «почему?» теперь — клик, а не поиск. Быстрее и честнее. Диагностика каскада — ваша новая суперсила. Практикуйте чаще.

💡
Щёлкните «стрелку» рядом со значением — покажет все правила, влияющие на свойство (даже инлайновые).

Свойство writing-mode и вертикальный текст бренда

writing-mode: vertical-rl — текст «снизу вверх» (как японские). Для «бренда», бирок, обложек. Горизонтальный-по умолчанию; «туда-сюда». Ось строк меняется: width/height «меняются местами». Скринридер читает по строкам текста (вертикально создаёт «колонку»). letter-spacing эффект. «Не» делайте весь сайт вертикальным — экстремизм. Кейс: бейдж «Назад в топ», витрина. Многие браузеры — поддержка хорошая. Для «режима письма» и языков — важно. Text-orientation: upright/mixed — поворот букв. Бренд-вертикаль — «тихая» изюминка макета. Проверяйте на разных шрифтах: некоторым не хватает глифов? «Вертикально»: осторожно с кириллицей — буквы не «ложатся» на бок. Комбинируйте смело, но деликатно. Дисциплина письма = уважение к языку. Практикуйте на брошюре-флаере. Vertical — «трюк-вишенка».

💡
Для иероглифики — writing-mode; для бейджа «РУС» — rotate() в CSS безопаснее и читаемо.

Обвязка деталей: аттрибут dir для встроенного RTL

<bdi> — «изолированный» кусок текста, направление которого может «выбиться»: имена, номера. Скринридер и браузер «не путаются». Атрибут dir="rtl" на контейнере: для арабского/иврита. Встроенные числа в русском: «не» переворачиваются. <bdo dir="rtl"> — принудительный разворот (редкость). При смешении языков — валидность и чтение. Не «прячьте» направление в CSS. Семантика направления — атрибут, не стиль. Тестируйте: текст с арабским именем внутри русской строки. Unicode bidi — сложно; тег bdi «снимает» боль. Проверка поддержки: все современные браузеры. Скринридеры «слышат» правильный порядок. Приятный бонус: «nofollow» направление остаётся. Для форм с именами — bdi вокруг значений. Меньше «сюрпризов» в UX разных культур. Инклюзивный и понятный. Уважайте двунаправленность мира — размечайте аккуратно.

💡
<p>Привет, <bdi>أحمد</bdi>!</p> — имя не «выпрыгнет» из порядка предложения.

Домашнее задание: мини-хранилище переменных темы

Соберите «настройщик темы» на CSS-переменных: :root с --bg, --text, --accent, --radius, --shadow. Три варианта пресета через классы на body: .theme-dark, .theme-light, .theme-solar. Переключение JS — позже; сейчас просто классы. Проверьте: смена класса на html меняет фон/цвет. Значение «каскада»: переменные переопределяются «селектором», а не «местом». card «использует» var() — «реагирует» на тему. Практическое зерно: дизайн-токены в переменных — «фундамент» системы. Сделайте кнопку «Тема» (без JS, просто демо). Скринридер «не видит» тем — это визуальное. Проверка: контраст текста в каждом пресете. Адаптив: одна переменная — «одна» замена. Выполнено — значит, вы поняли суть тем и роли :root. Чистый CSS — чистая архитектура. Тренируйте грамотно.

💡
Аккуратно: color-scheme: dark переопределяет и «нативные» поля формы под тёмный фон — бесценно.

Инспектор и счётчики: считать поля жизни списка

Сила списков в таблицах счёта: start, value, reversed. <ol reversed start="10"> — обратный отсчёт. value на li — «переопределить» номер: список «шагов с пропусками». CSS counters — через ::marker? номера — часть контента, а не CSS. «Значение» — данные: шаги, главы, позиции. Дебаг в DevTools покажет «вычисленный» номер. Скринридеры считают элементы списка. Не «полагайтесь» на видимые номера — они из order HTML. start="5" для продолжения главы. Для рейтингов reversed + value. Списки выглядят «по-настоящему» живые: «пропуски» объясняют. Дисциплина: order-атрибуты — часть данных. Убедитесь: валидатор «не ругается». Практикуйте список-конспект с begin 1,2,3… «живая» нумерация без JS. Счёт — «скелет» повторяющегося. Узрите: нумерация «несёт» порядок, а порядок — обещание. Значении для разных языков — числа. «Считайте» уверенно.

💡
Метод: в навигации-нумерации глав — ol + start: читатель «видит», сколько глав прошёл и что впереди.

Тихий показ: свойство opacity и игра со слоями

opacity — «прозрачность» элемента целиком: 0 скрывает, 1 — непрозрачный. Влияет на весь элемент + потомков (пигмент). Не путать с visibility:hidden (место остаётся) и display:none (выпадает из потока). content в opacity? — «весь блок тускнеет». Переходы opacity — «плавное» исчезновение: популярно в UI. Про то, что «не» наследуется. Применение: водяные знаки, лёгкие оверлеи. Скринридеры: opacity:0 элемент «всё ещё» в дереве (читается!) если не display:none. «Трюк»: opacity — «дешёвая» анимация (GPU-friendly). Чередование в тостах. Аккуратно: 0.5 на текст — снижает читаемость. Та же «муть» для фоновых подложек — отлично. Плавность: transition: opacity .3s. Fade-эффекты «живут» здесь. Вершина простых анимаций — opacity + scale. Тихая палитра — сила. Практикуйте on-hover: 0.7 → 1. Деликатно.

💡
Скелет-заглушка: .skeleton { opacity:.5; animation:pulse } — «мёртвая» загрузка «оживает» без JS.

Зачем нужен overflow: контейнер шире разговора

overflow — «как себя вести», когда контента больше, чем бокс: visible (вылезает), hidden (обрезает), scroll (полосы), auto (полосы при необходимости). overflow-x и overflow-y отдельно. Скрытие «побочных» детей через hidden — классика слайдера. В сочетании: белое пространство — «не» утечка. Проверяйте: у caret-hidden может «выпасть» тень. Скринридеры: overflow:hidden не «убирает» из DOM — контент читается (для форм-карусель это важно?). Делайте любые «тоннели» аккуратно: не живите «в» прокутке внутри прокрутки. «Орлиный» глаз: если скролл-полоса не нужна — auto. Горизонтальный скролл — признак тесноты: пересмотрите сетку. Практика: обрезайте «длинную» строку многоточием: overflow:hidden + text-overflow:ellipsis + nowrap. Это «не» калечит, а «причёсывает». Overflow — «ножницы» бокса: видите, чего не хотите показывать. Управляйте потоком с достоинством.

💡
Для «съехавшей» карточки: overflow:hidden на .card — «закруглённый» угол сочетается с фото.

Блочные родные: не только p — универсальная боль childhood

Блочные элементы: div, p, h1-h6, ul/ol, li, section, article, header, footer, main, blockquote, figure, form. Все «прижимают» соседей вниз. Каждый — «новая строка». Ширина — вся доступная (блок). height — по контенту. «Правило-детство»: блочность — не «злодей», это «порядок по умолчанию». Меняет display — CSS. Не «выпрямляй» руками — поток «сам». Строку вытащил строчно-блочным? Подумай. Смысловая иерархия часто идёт «блоками». Список из article — блоки. Цитата — блок. Форма — блок. «Не» «стыдись» блочности — на ней стоит весь веб. Блочная модель — «стержень» CSS. Практикуйте мысленно: «это строка или блок?» — отвечайте разметкой. Даже если CSS «позволяет» иначе — поток «не устаёт». Управляйте правильно. Диаграмма потока — лучший наставник. Спокойный поток — спокойная вёрстка. Дисциплина бокса — ежедневная гимнастика ящиков.

💡
Трюк отладки: * { outline: 1px solid } — мгновенная «карта» всех блочных ящиков страницы.

Строчные в потоке: когда text-align мать порядка

Строчные элементы (span, a, em, strong, img inline) — «текут» по строке. text-align: left|right|center|justify — «выравнивание» строковых боксов. Применимо к блочному контейнеру. Left по умолчанию. Center — заголовки. Justify — «растягивает» между полями — может дать «реки». Строчные «не» принимают width/height, margin по вертикали «не работает». Для «центровки» строчной картинки внутри блока — text-align:center. Скринридеры: выравнивание CSS «не» слышно — только смысл. «Приёмы»: почините «дышащий» текст через text-align. Многострочные строки внутри inline-block. Горизонтальный ритм: выравнивание задаёт «берег» колонки. Длинные цитаты — центр? — только заголовок. Соблюдайте читаемость: justify на узких колонках — риск «дыр». text-align — «дирижёр строкового оркестра». Понимание «строк/блоков» — фундамент. Играйте: «центр» против «левого» — почувствуйте. Мера — ваш шаг.

💡
Для кода: text-align:left обязателен — `code` блок остаётся «по левому», иначе отступы «поплывут».

Формы-братья: инпут против textarea против select

Однострочное — input; многострочное — textarea; выбор из списка — select/option. textarea rows/cols + resize: vertical. select collapsed + optgroup. input «для» коротких значений; textarea — «пространные». Семантика: каждая роль «своя». Не «злоупотребляйте» textarea для «пароля» (это input type=password). Скринридер: select «через» стрелки «открывается». maxlength автоматически — у textarea «есть». placeholder — пример. label «связан». Пара: <textarea name="comment" rows="4">. Форма-«текст» отличается от формы-«выбора» — читается. Валидация браузером минимальна; JS — глубже позже. «Гнусность» сценария: input для длинных абзацев — потеря «потолка». Проверяйте, что поля правдоподобны по типу. Многострочность — доступность для «развёрнутого» ответа. Дисциплина выбора поля — часть UX. Форма «моя» и «твоя» — правильно разложенная. Практикуйте педантично. Поток данных чист.

💡
<select multiple> — «мультивыбор» списком: для тегов/категорий с Ctrl — компактно и понятно.

Гнездо колонок: table в центре fluid-страницы

Таблица «внутри» fluid-макета: width:100% + max-width; «дышит» вместе со страницей. table-layout:fixed — столбцы «по указанным» ширинам (предсказуемо). Быстрее рендер больших таблиц. Нужен явный width у col/th. Строгие «высоты»: white-space:nowrap может разорвать. Для больших данных — horizontal scroll-обёртка или sticky th. Адаптив таблицы: на мобильном превращается в «карточки» (display:block + data-label). Скринридер: карточка-таблица «читается» построчно? Используйте th scope=col. Контраст строк — уют глаз. Не «запихивайте» таблицу в карточку любой ценой: иногда это «список». Соотнесите: данные-рядки → таблица; данные-пары → dl. Пропорции: соотношение сторон таблицы — чувство. Практика: расписание в две колонки, затем мобильное «переложение». Гибкость данных — искусство выбора контейнера. Сетка + таблица — «сплав» правил. Держите фокус на смысле.

💡
Совет: class="table-responsive" + overflow-x:auto — «прокрутка» на телефоне вместо поломанных колонок.

Псевдо-таблицы: grid против table для данных

Современный выбор: CSS Grid «рисует» сетку данных без table-тегов? Но скринридер «не» увидит «связь» строк/столбцов, как в настоящей таблице. Для «табличных» данных остаётся table (row/column семантика). Grid — для «макетных» ячеек (карточки, галереи). Не «меняйте» table на grid ради «красоты» — потеряете данные. Комбинируйте: table внутри grid-области? — да. А если «только» выглядит как таблица (прайс в 3 колонки) — честно решите: это «список» (ul) или «таблица» (данные). Вопрос «соотношения»: смысл данных диктует. Сетка — «город», таблица — «кадастр». Скринридеры читают таблицы заголовками. Обучение: превратите простую прайс-таблицу в grid? — и спросите себя о смысле. Частая ошибка: «весь» grid ради «незначительных» строк. Мудрость: выберите инструмент по данным, не по моде. Данные «любят» колонки родом «th». Уважение к структуре — инклюзия. Пишите семантику честно.

💡
Смешение: таблица с «колонкой-действий» (button) — таблица остаётся, стиль кнопки внутри td.

Интерактив без JS: details-аккордеон в списке тем

<details> — «раскрывающийся» блок без JavaScript: click — toggles. <summary> — «видимый» заголовок. Атрибут open — раскрыт. Скринридер «заявит» state (свёрнуто/развёрнуто). Соберите FAQ «нативные» — пятёрка вопросов. Внутри: div/p «содержимое». Хорошо: свёрнуто по умолчанию = компактно; «открытое» open — «вещь» важная. Не «вкладывайте» аккордеон «в» аккордеон глубоко. Group подробностей: details frame=добро. Доступность: summary — «button-like»: Enter/Space переключает. Стилизация: margin, border, ::marker. details/ul — аккуратная семантика. Держите логику «внутри» блока. Практика-мини: «Вопросы и ответы» урока без JS. «Новости»-спойлер. Немного усилий — «живой» паттерн. Поняв details — первая «интерактивность» без сценария. Проверьте в браузере и скринридером: state озвучен. Стили можно «нарастить» позже. Настоящий HTML «одушевляется» простотой.

💡
<details><summary>Что такое семантика?</summary><p>… — FAQ «какой надо»: четыре пары — «экран не шумит».

Детали фокуса: tabindex без боли амулета

tabindex="0" — добавить элемент «в» порядок Tab-навигации (карточка, кастомный контрол). tabindex="-1" — «убрать» из Tab, но «оставить» фокус для JS (скрытые контейнеры). Положительные (1,2,5) — «ломают» естественный порядок: избегайте. «Одна» страница = «естественный» DOM-порядок + 0 для интерактива. Скринридер «не» «спотыкается» о tabindex. «Хирургия»: «свои» виджеты (вкладки, слайдеры) — управление стрелками (roving tabindex) — продвинутая практика. Не «вешай» tabindex на каждый текст. Если элемент «не» для клика — «не» делай фокусируемым. Проверьте: кликнули, потом Tab-порядок «чист». SKILL: DevTools → панель a11y «видит» порядок. Дисциплина фокуса — «невидимая» доступность. Практикуйте на навигации: focus visible никогда не «пропадает». Не «срезай» outline мышью — лечи селекторы. Фокус — «маршрут» для рук без мыши. Чистый tab-поток — профессионализм, ощутимый слепым и зрячим. Уважение к клавиатуре.

💡
Приём: <main tabindex="-1"> + JS focus на переходе страницы — скринридер «не потеряет» точку старта.

Куратор концовок: footer в разных гранях каскада

footer — «хвостовая» информация: копирайт, контакты, мини-навигация. Внутри article — «подвал статьи» (автор, лицензия). Полный деликатный «хвост». Каскад: стилизуйте footer один раз на странице. Скринридер читает footer «в конце». address в footer — «контакты владельца». Не «дублируй» навигацию главного меню в подвал; у подвала — «вторичные» ссылки. Семантика: footer «не» «прилипает» — он «в потоке». Для «липкого» — flex min-height. Слои: нём и «повторяющиеся» данные. Используйте <time> в copyright. Стилизуйте аккуратно: отсутствие «суеты» внизу «успокаивает» завершение страницы. Инклюзия: ссылки footer «доступны» из любой точки. Каскад: «последний» блок — «точка» затишья. Формы-мини (подписка) — тоже житель footer. «Пункт» ритма. Повторите: footer — «подпись» документа. Профессиональная, честная, не «кричащая». Дисциплина подвала — финал симфонии.

💡
а href="mailto:info@…" в footer с aria-label — «заметка-контакт» без лишней формы: быстро и доступно.

Псевдокласс :empty и аккуратные пустые блоки

:empty — «выборка» элементов без детей и текста. Отличный инструмент: скрыть пустую корзину («is-empty»). .cart:empty::after { content:"Пока пусто" } — «занятие» пустоты. Точность: пробел/комментарий в HTML — элемент «не пуст»!). «Одна» ловушка: <div>   </div> — «не» пустой. Скринридер: :empty «не» слышит; контент-подсказку «сложите» в текст. CSS управляет «пустотой» визуально. Применение: пустые состояния в списках/таблицах. Не «добавляй» вручную классы is-empty руками JS — CSS сам. Каскад: :empty ниже «классов» — смотрите порядок. Гигиена: не оставляй «мёртвых» пустых div — удаляй. Если блок «пуст» по дизайну — подумай: нужно ли «семантически»? Можно просто опустить. CSS :empty — «умный нож». Меньше «манекенов» в дереве = чище чтение. Прайс «в» сети: пустая область «получает» фразу. Проверьте: загадка «один пробел ≠ пусто». Аромат аккуратности — в деталях. Доступный и минималистичный «вэб» любит пустоту, наполненную смыслом.

💡
Чистка: :empty { display:none } — прогоняйте «зомби»-блоки после CMS-редактирования.

Овладеваем величиной: размеры и высоты шрифтовой гаммы

Сила шрифтовой шкалы: font-size 6-8 размеров (10→48px); modular scale (1.25) — «музыкальная» лестница. Заголовки 2,1.7,1.4 абзаца. line-height: заголовки «теснее» (1.1-1.3), текст «свободнее» (1.5-1.7). Эм/рем/пиксель: выбор. Отступ только по вертикали: margin-bottom 1.5em. Абзац «дышит». Не «добавляй» межбуквенный у огромного заголовка слишком. Weak: систематика размеров — читаемая иерархия. Скринридеры «не» слышат размер — зато мозг «иерархией» дирижирует. Количество чтание: 45-75 символов на строку. Ширина текста: measure. Проверьте: крупные абзацы «бегут» на всю ширину? Исправь. Сетка: базовая линия в 1.5 крат. Каскад наследует line-height. Практика: выберите модуль (1.25), расчертите страницу. Результат: типографика «поёт», цифры совпадают с чувством. Дисциплина шкалы — «молчаливый» профессионализм. Ритм-управление — приятное мастерство. Строки согласованы, глаза не устают. Оформите правило: «один модуль на сайт» — элегантность и порядок. Читаемость — король.

💡
Шпаргалка: 16px = база; заголовки: 28/24/20px; caption 13px — классическая лестница блога.

Повторение диаграммы: соседи-боксы это просто

Бокс-модель «на пальцах»: content — «содержимое», padding — «внутренний воздух», border — «граница», margin — «внешний воздух». Ширина: content + padding + border (без margin). alt text? — не про бокс. Разные display — «раскладка» боксов. Блочный занимает свою строку. Схлопывание margin — «вертикальные соседи». Для точной ширины: box-sizing:border-box — «помещение» padding в width. В DevTools виден «синий»=content, «зелёный»=padding, «жёлтый»=border, «оранжевый»=margin: смотрите. «Отладка»: квадратик-подсветка. Не «гадай» где «лишние» пиксели — считай. Каскад: размеры из правил. Скринридер: box-model «невидима» — это визуально. Практика: поставьте border на все элементы — «увидите» границы. Понимание «ящика» — 90% вёрстки. Соседи дружат ритмами. Оформляйте «дышащие» карточки: 16px padding, 1px border, margin 8. Бокс-модель — «грамматика» CSS. Изучайте на чужих макетах: «отступ где?» — мгновенно. Ваши ящики под контролем. Мастерство — в числах.

💡
Кликните элемент в DevTools — цветная «трёхмерная» диаграмма боксов внизу: изучайте на реальных сайтах.

Имя в тени: тёмная тема и контраст в деталях

Тёмная тема — не «инверсия»: меняйте «светлоту» фона и «тусклость» текста. Красные «не» превращайте в «кричащие». Контраст — WCAG: 4.5:1 для текста, 3:1 для крупного/UI. Проверка contrast checker (WebAIM). В тёмном: яркие акценты «мягчить». background #121212, текст #eee. Не «чистый» чёрный (#000) — «неестественно» и «ореол» на OLED. box-shadow «тонет». Скринридер «не видит» тему — семантика неизменна. Медиа prefers-color-scheme: dark. Почитайте: «тёмная» тема для ночного чтения. Проверяйте гармонию: тень vs фон, разделители чуть светлее. Доступность — «мудрость»: не «тёмный фон = модно», а «комфорт глазам». Внимание: формы «нативные» — color-scheme. Каскад медиазапросов. Сделайте демо-карточку на тёмном фоне и проверьте контрасты. Практика: палитра Night mode для урока. Инклюзивность — выбор «и» для «ночных сов». Ваша страница теперь живет и «после заката». Разумная и «тёмная» красота — доступна всем. Светите акцентами, не «слепите» текстом.

💡
Растворяйте «яркий» акцент: #e33 на тёмном — до хирургии ровный, 4.5:1 держите через затемнение фона.

Шрифтовая пара: system-ui без скачивания — скорость

System-ui — «родной» шрифт устройства: font-family: system-ui, -apple-system, «Segoe UI», Roboto. Ноль запросов за файлом — «мгновенная» отрисовка. Скринридер не поёт о гарнитуре, но «читабельно» важно. Для «веб-шрифта» вешайте «display: swap». Практика: body { font-family: system-ui }. Заголовки — «семейство» родное, жирнее. Не «тяните» 5 начертаний — «вес» страницы. Современный минимализм: system в основе. Производительность — часть доступности. Настройки юзера: ему виднее. «Быстро» = «уважение». Проверьте мобильный. Дисциплина шрифтов — профессионализм.

💡
Акцент «в» заголовках через font-weight: 700 — файлы не грузим, контраст смысла есть.

Типографика строки: line-height и ритм чтения

line-height задаёт «высоту» строки: норма 1.4–1.6 для текста. Короткие строки — диапазон шире; длинные — ближе. Скринридер не о пропорциях «поёт», но глазам важна. Практика: body { line-height: 1.6 }. Заголовки — плотнее (1.2). Отступы между абзацами — отступ. «Воздух» вертикальный — ритм страницы. Слишком «сильный» интервал рвёт связку строк. Соотношение: 30–45 символов в строке идеально. Выравнивание текста: left, не justify (дыры). Проверьте на мобильном зум. Читабельность — забота о пользователе.

💡
line-height 1.6 + 60–75 символов шириной — «золотая» полоса для длинного чтения.

Живая типографика: clamp() — размер без брейкпоинта

clamp(min, prefer, max) «резинит» размер: font-size: clamp(1rem, 1rem+1vw, 1.5rem). Между минимумом и максимумом — плавно. Скринридер не замечает, но «зум» корректен. Практика: заголовки через clamp — меньше media-запросов. Не «фетиш» на clamp: база rem, потом clamp у крупных. Ограничение: слишком «широкий» диапазон — крик. Для текста тела оставьте читаемый размер. «Быстрый» сайт + «живые» заголовки. Проверьте на десктопе и телефоне. Плавность — признак зрелости. Сдержанно и точно.

💡
clamp(1.5rem, 1rem+2vw, 3rem) для h1 — заголовок «дышит» на любом экране.

Пробел по-русски: nbsp и правильная типографика

Неразрывный пробел &nbsp; «держит» слово и число вместе: «10&nbsp;кг». Скринридер читает как пробел. «Висячие» предлоги «не» красивы: перенос «на» строку режет смысл. Практика: «№&nbsp;5», «2025 год» с nbsp. Кавычки «ёлочки» для русского: «текст» (не «лапки»). Тире длинное «—», без пробелов? — по правилам. «Пробельная» типографика — признаки культуры. Сквозь строки: «не переносите» наречия. Проверка зрения: текст «не плачет» краями. Аккуратность с пробелами — уважение к читателю. Форматирование языка = манера письма.

💡
Используйте «“» и «”» или «» (Alt+» в раскладке) — «елочки» родные для русского.

Смысл через цвет: кнопка не только красная

Цвет «несёт» информацию: ошибка — красная, успех — зелёная. Скринридер не «озвучит» оттенок: дайте текст «и» иконку. Не «только» цветовой сигнал (WCAG 1.4.1). Практика: у сообщения ошибки — красная рамка «и» слово «Ошибка». Контраст: текст на фоне — проверяйте WebAIM. Дальтоники «видят» иначе. Цвет + символ + текст = надёжный сигнал. Доступность цвета — про смысл, не про «красоту». Проверка оттенков серой шкалой. Инклюзивность — решает отношение. Дисциплина контраста.

💡
Проверьте скриншот в оттенках серого: если смысл «потерян», добавьте текст/иконку.

Единицы rem: масштаб и доступность зума

rem — «корень» (root), em — «родитель». rem «уважает» настройки масштаба браузера: увеличение «растёт» и текст. Скринридер не о единицах, но «зум» — доступность зрения. Практика: размеры/отступы в rem, em для «относительных» сущностей. Пиксели допустимы для «тонких» элементов — рамок. Осторожно: em «цепляется» — измените родителя, всё «едет». «Ритм» решётки держите в rem. Проверьте Ctrl+/Ctrl-: страница «не ломается» на 200%. Согласованный масштаб — здоровье раскладки. Доступность начинается с единиц.

💡
html { font-size: 100% } — не «ломайте» базу; rem пляшет от настроек пользователя.

Выравнивание форм: label в ряд под капотом

Горизонтальная форма (label «слева») — плотная, «табличная». Vertical — «дыхание с воздуха». Скринридер: связь label+input важнее геометрии. Практика: короткие поля (имя, город) — в ряд; длинный текст — столбик. Label «неразделим» с контролом. for/id — жёсткая связь. Группа radio/checkbox — fieldset. Выравнивание чисел справа в таблицах: text-align: right. Вертикальный ритм формы — сетка. Проверка: таб идет по порядку. Гибкость раскладки — уважение. Читайте, как «поток» движется. Аккуратность связей — семантика.

💡
При горизонтальных label держите «лук»: колонки выровнены, пробелы одинаковы.

Пароль с глазами: шоу/хид и атрибут autocomplete

Поле пароля: type=password •••. Кнопка «показать» переключает type в JS. Скринридер: не сообщать тип «без» нужды. autocomplete=current-password/new-password — менеджер паролей поможет. Не «просите» пароль «по-глупому»: подсказка силы рядом. Практика: форма входа с «глазом». aria-label кнопке «Показать пароль». Тумблер визуальный + текст. Никогда «не» логируйте пароль. Связь label+input. Но UI: иконка «глаз» кликабельна. Новый пароль: minlength, required. Скринридер «прочтёт» подсказку. UX формы — безопасность без барьеров. Интуитивный контроль.

💡
Включите aria-pressed на кнопке «показать»: скринридер сообщит состояние переключения.

Ховер только на десктопе: media (hover: hover)

На сенсорных экранах «ховера» нет: касание «тап» вместо hover. @media (hover: hover) — стили для мыши, (hover: none) — для касаний. Скринридеру не «о чём» наводиться. Практика: меню на hover + фокус для клавиатуры; сворачивание на тач — по «тапу». Не «прячьте» контент только за hover — потеря на мобильном. Кнопки: min 44px для пальца. «Тонкие» состояния — декорация. Сделайте: и hover, и focus:visible. Проверьте на планшете. Адаптивные состояния — нервы интеракции. Доступность времени реакции.

💡
hover+focus одновременно: держите фокус видимым даже когда есть мышь (focus-visible).

Псевдокласс :focus-visible — умное кольцо

:focus-visible «показывает» кольцо только при клавиатуре (Tab), не при мыши. Это «память» стилей. Практика: кнопки с :focus-visible outline — клавиатурная навигация видна. Мышь не «мельтешит» рамкой. Не «убивайте» outline: он признак фокуса. focus (безусловный) тоже нужен, но… Для полей — видимый фокус всегда. Скринридер «услышит» переход фокуса. Компромисс: эстетика + доступность. Проверка: Tab по странице, Enter — работает. Дисциплина фокуса — вежливость. Псевдокласс современных браузеров. Включите в «базу».

💡
a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px } — заметно и не кричит.

Ссылка в «кнопочном» виде: роль в подвохе

Ссылка для перехода, кнопка для действия. Визуально можно «стилизовать» любую. Но роль aria «для» скринридера не «обманывайте»: a с onClick не «кнопка». Практика: «Подробнее» — cсылка, «Отправить» — button. Если у «кнопки» нет действия кроме навигации — . Роль role=button на a — «костыль», избегайте. Не «вешайте» обработчик на div — семантика страдает. Скринридер «встречает» по . Принудительный tabindex отрицательный — «не». Аккуратность сущностей. Разделение «маршрут/действие» — ясность. Проверка: Enter и пробел. Семантика — дисциплина.

💡
Правило: есть href и переходим — ссылка; инициируем действие — button.

Состояние disabled: не только серость кнопки

disabled «вырубает» контрол: клик, фокус, ввод — недоступны. Скринридер «сообщит» disabled. Практика: submit заблокирован до валидации. Но: disabled «не» в фокусе — пользователь не «узнает» почему. Лучше aria-disabled=true на «живой» кнопке + подсказка. Не скрывайте «что» требуется: сообщение рядом. Стили disabled — сниженный контраст легальны, но «заметность» важна. Форма с disabled полем: объясните причину. Проверка: фокус, Tab, Enter. Милосердие UX: нельзя — скажите «почему». Состояния — словарь интерфейса. Доступность состояний.

💡
Для «почему нельзя» держите текст подсказки рядом, а не только серый цвет.

Тег picture: арт-дирекшн изображений

<picture> выбирает <source> по условиям (media, type) + <img> запасной. Практика: разные кадры для десктопа/мобильного (широкий vs вертикальный). Скринридер «смотрит» на img alt — picture «не» мешает. Alt «у» img обязателен. Форматы: source type=image/webp/avif с фолбэком img/jpg. «Не» «перегружайте» picture: только если кадр реально другой. Быстродействие: подходящий размер. Проверка: DevTools — какой выбран. Атрибут loading=lazy на img. Адаптивные картинки — современный стандарт. Меньше байт, лучше опыт. Арт-дирекшн в чистом HTML.

💡
<source media=«(min-width:800px)» srcset=«wide.webp»> — кадр под экран, не «каша».

Закругление и тень: CSS для «карточного» юмора

border-radius + box-shadow «взбивают» «карточный» стиль. Практика: карточка курса со скруглением и мягкой тенью. Скринридер «не видит» красоту, но «плоскость» не мешает. Не «злоупотребляйте» тенью: лёгкая, смещение вниз. border-radius: 8-16px «дружелюбно». Внутренние элементы: и radius наследования. Сетка карточек — gap. Ховер: поднять transform: translateY(-4px). Balance: тень «глубина». Семантика: article в карточке. Проверка контраста текста на фоне. Аккуратные тени — признак знания. Разделяйте «смысл» и «декор». Уют интерфейса.

💡
box-shadow: 0 2px 8px rgba(0,0,0,.08) — тень «мягкая», карточка «дышит» над фоном.

Тень-фокус: outline-offset для чёткой границы

outline-offset «отодвигает» кольцо от контента: outline + offset 3px — видимость на любом фоне. Практика: фокус на карточках-кнопках. Скринридер «показывает» фокус не visual, но порядок важен. outline «вне» бордера не «режется» скруглением — но «снимается» с extent. offset «даёт» зазор под тенью. Комбинация: «кольцо» + тень — современно. Кастомный фокус через box-shadow «адаптируется» к радиусу. Проверка: Tab — видно ли на белом/тёмном. Фокус — «дорожный знак» пользователя. Не «стирайте» его. Обрамление уважения. Точность доступности.

💡
Используя box-shadow вместо outline — помните про радиус: shadow копирует border-radius.

Тег abbr с title: расшифровка сокращений

<abbr title=«полное»>сокр</abbr> — расшифровка по наведению/фокусу. Скринридер «прочтёт» title (частично). Практика: «HTML», «CSS», «API» в тексте — оберните. Кавычки «не» вокруг. Для «массовых» аббревиатур — первый раз расшифруйте. title дублирует содержимое — «не» «пустой». У первого: <abbr title=«HyperText Markup Language»>HTML</abbr>. Скринридер: название читается. Не злоупотребляйте — шум. Доступность терминов: знание читателя. Проверка hover: всплывает. Точность: регистр большой. Сокращение без расшифровки — барьер. Забота о языке.

💡
Расшифруйте аббревиатуру в тексте при первом появлении «и» в abbr title — двойная страховка.

Метаописание: description — анонс в выдаче

meta name=description — «анонс» в результатах поиска: 150-160 символов, суть. Скринридер на странице не «слышит» (это для роботов), но клик решает. Практика: 1–2 предложения, ключевые слова, призыв. Не «пишите» кликбейт-ложь. Каждая страница — своё описание. Кнопка «Подробнее» — не «для описания». В «выдаче» Google дополняет/обрезает. Проверка: у всех страниц description. SEO + пользователь: ясно, чем счёт. Доверие в 160 символах. Точность продвижения. Доступность смысла «до» клика. Компромисс «краткости».

💡
Уникальное описание на страницу: каталог, продукт, контакты — разные «анонсы» в выдаче.

Поле с подсказкой: helper-text и aria-describedby

Подсказка под полем «объясняет» требования: aria-describedby=«id» связывает. Скринридер «прочтёт» подсказку после ввода. Практика: поле пароля с требованием «8+ символов». Не путать с label: label — название, help — разъяснение. id уникален. Множественные подсказки — «два» id через пробел. Стиль подсказки: мельче, серо. Проверка: фокус — подсказка озвучена? (JAWS/NVDA). Ошибки: aria-describedby указывает на сообщение об ошибке. Динамика: JS обновляет. Дисциплина: у сложных полей — помощь. Доступность «почему» всегда. Ясность форм — забота.

💡
Одна форма — подсказки не «перегружайте»: только там, где пользователь сомневается.

Сегодня: input type=date и «стрелки» календаря

<input type=date> — нативный календарь: picker в браузере. Скринридер «построчно» читает день/месяц/год. Практика: поле «Дата рождения». Атрибуты: min, max, value. Формат доставки ISO (yyyy-mm-dd) — сервер рад. Стилизация picker ограничена — c «регулярным» дизайном. «Тач» — удобно. «Десктоп» — ввод вручную. Валидация встроена. Не «изобретайте» календарь с нуля — нативный доступен. Проверка: скринридер + клавиатура. Региональный формат — locale браузера. Простота календаря. Меньше кода — надёжнее. Формы будущего.

💡
Для «от»/«до» используйте min/max: связь полей «в» два атрибута без JS.

Карточка с полями: сгруппированная форма внутри

Форма может жить «в» карточке: логическая группа полей. Практика: «Доставка», «Оплата» — карточки-секции. Скринридер «поймёт» по legend/заголовку. Не «плодите» формы: одна на страницу лучше (иногда 2). Каждая секция — fieldset+legend. Поля связаны c label. Контекст «сверху» в заголовке. Осмысленные подписи. Кнопки действия — по месту. Проверка: tab по всей группе. Адаптив: карточки в столбик. Сгруппированный смысл — доступность. Ясная структура форм. Профессиональная сборка. Интуитивность по группам.

💡
Заголовок секции + fieldset: naming группы — «не» «прячьте» под контент.

Ширина полей: max-width и «дышащая» форма

Не «растягивайте» поле до конца экрана: input { max-width: 480px }. Практика: форма авторизации по центру, поле не «печатает» на века. Скринридер не «видит» ширину, но «взгляд» читателя расслаблен. Короткие поля (номер карты) — «не» «размахивайте». Поле с 1 символом — унизительно. Баланс: форма по центру, метки слева. Проверка на «огромных» мониторах: не «ширится» на всё. Адаптивность: max-width спасает. Минимализм доступа. Для «длинных» комментариев — textarea шириной. Интерактив «воздух». Уважение пропорций. Центрирование — эстетика.

💡
Поля «не» длиннее 480–600px — иначе строка «растягивается» и взгляд теряет начало.

Невидимые label: скрытый, но доступный текст

Если визуально метки нет (иконка поиска), скройте label «по-хуже»: .visually-hidden (не display:none!). Скринридер «прочтёт», зрение — чисто. Практика: иконка-лупа с hidden-меткой «Поиск». display:none убивает доступность. Класс «скрытый» — позиционирование с клипом. aria-label дублирует? — «один» источник. Запасной вариант: placeholder — «не» замена! placeholder растворяется. Проверка: скринридер слышит метку «Поиск». Соответствие: имя у поля всегда. Скрытые метки — когда «умышленно» скрыто. «Скринридерный» минимум. Точность доступности форм.

💡
.visually-hidden { position:absolute; clip:rect(0 0 0 0); } — «виден» только скринридеру.

Сетка из «двух» полей: имя и фамилия в ряд

Пары полей (имя/фамилия) в grid: две колонки, gap. Практика: регистрация с половинками. Скринридер «по порядку»: label, поле, label, поле. Каждая метка — своя (for/id). Не «одна» метка на «две» ячейки. Адаптив: на узком — в столбик (grid-template 1fr). Veritcal stacking на мобильном. Заполнение: автокомплит. Проверка: нет ли «перепутанных» подписей. Горизонтальные пары экономят место, но… «дыхание» чтения. Дисциплина: этикетки не «рвутся». Формы-двойни — аккуратно. Комфорт ввода. Место и смысл.

💡
grid-template-columns: 1fr 1fr; @media (max-width:600px){ grid-template-columns: 1fr }.

Свежий взгляд: предзаполненное поле с placeholder

placeholder «подсказывает» пример («Иван Петров»), но «не» заменяет label. Различие: label всегда, placeholder исчезает при вводе. Практика: пример как placeholder + видимая метка. placeholder не имеет «родного» for. Скринридер «слышит» label. Не «пишите» в placeholder «Введите…» (label уже говорит). Ошибка: placeholder вместо label — провал валидации при пустом. Проверка: пусть placeholder будет подсказкой-примером, не «именем». Стиль «плейсхолдера»: серый, курсив — отличие. Чем «меньше» когнитивной «нагрузки» — тем лучше. Примеры в помощь. Ясность ввода.

💡
Используйте placeholder для «формата», а «не» «вместо»: label + пустой placeholder — идёт.

Интерактивность: hover-подсказка через title на ссылке

title на элементе «всплывает» подсказкой при наведении/фокусе. Скринридер «прочтёт» (не всегда). Практика: у неоднозначной ссылки title=«детали». Не «дублируйте» текст: title повторяет link text — шум. Для «скринридера» лучше текст ссылки понятен сам. Когда title уместен: уточнение, формат файла (PDF), открытие в новом окне. Не «срывайте» доступность. Проверка: фокус — всплывает? (мышь фокус нет). «Точечные» подсказки — тонкость. Читаемость ссылок — base. Краткость и польза. Аккуратность подсказок. Не «наращивайте» всплывашки везде — «крик». Значение точности.

💡
При «PDF» — title=«откроется в PDF»; а текст ссылки: «Загрузить отчёт».

Группа-мольберт: fieldset вокруг опций даты

Дата «в» группе: день/месяц/год select — fieldset+legend. Практика: «Дата рождения» тремя селектами. Скринридер «встретит» legend — место «входа». Каждый select — label (for/id). Не «плодите» третий select когда можно date input. Но «очень» специфичные комбинации — так. Вертикальный порядок важен. Нюанс: удаление лишних — good. Проверка: фокус в группе в порядке. Автокомплит даты. Доступность группы — через legend. Объединение смысла. Раздельный ввод сложных полей. Ментальная модель: «всё про дату». Ясność сгруппирована.

💡
Legend = «имя» группы: скринридер «зачитает» до входа в опции. Делайте осмысленным.

Одна форма, два энтерпойнта: первое поле в фокусе

Автофокус (autofocus) на главном поле ускоряет: пользователь сразу печатает. Осторожно: autofocus «крадёт» старт у скринридера? — избегайте на больших страницах. Практика: поиск в шапке — autofocus уместен? Для «мобильного» — «не». Скринридерная навигация: автофокус дезориентирует. Методы: первая ссылка контента. Лучше «таб» в контент. Не «перебивайте» пользователя. Проверка: скринридер встречает форму сразу? Нежелательно. Критерий: важность поля. Тонкость: не автозаполняться без нужды. Баланс «удобства». Уважение к темпу. Автофокус — «инструмент» с мерой.

💡
Для поиска — autofocus отлично; для длинных форм — «не» «навязывайте» скринридеру.

Случайный порядок: tabindex положительный — осторожно

Положительный tabindex «перемешивает» поток таба: tabindex=1 идёт первым. Это «сшибка» источника: документ порядок ломается. Практика: почти никогда не нужен. Скринридер «идёт» по tabindex — бессистемный скачок дезориентирует. Правило: нулевой/отрицательный tabindex — да; положительный — «красный флаг». Порядок = порядок документа. Перестановка визуальная не «порт» читается. flex/grid могут «перерисовать» отображение — используйте «source order». accessibility tabindex: -1 для программного фокуса (JS-модалки). Дисциплина: сохраняйте логику чтения. Проверка: Tab последователен. Простота — добродетель.

💡
Вместо tabindex=1 исправьте порядок в разметке: источник — король табов.

Ссылка внутри параграфа: интерактивный акцент

Ссылка в тексте «сливается» с предложением: контекст понятен. Скринридер «прочтёт» имя ссылки в контексте. Практика: «Подробнее в справочнике». Не «ссылайтесь» на «здесь»/«тут» — плохое имя. anchor text = цель ссылки («справочник»). Не «накручивайте» длинный текст. Глазу: подчёркивание (дефолт) vs кастом (hover-подчёркивание). Контраст ссылки — 3:1 min. Отличие от текста «не» только цветом. Практика: осмысленные короткие ссылки в абзацах. Проверка: скринридер-список ссылок — нормальные имена. Ясность «выходов». Читабельность инлайн-интерактива.

💡
Ссылка «в» предложении: имя = «что будет» («каталог курсов»), не «нажми сюда».

Приятные мелочи: transition на полях форм

Анимация на фокусе input «успокаивает»: border-color плавно. transition: border-color .2s. Скринридер не видит, но «гладкость» радует глаз. Практика: фокус поля — мягкое выделение. Не «разгоняйте» на всё: transform/opacity безопасны. Умеренность: 150-300ms. Кастом цвет фокуса вместо резкого. Не «мелькайте» — утомление. prefers-reduced-motion: отключить. Проверка: «дышит» ли интерфейс. Плавные формы — молодость интерфейса. Дисциплина анимации. Простота переходов. Комфорт восприятия.

💡
input { transition: border-color .2s, box-shadow .2s } — фокус «не» «щёлкает», а «мягко» приходит.

Тень удачи: карточка с border и фоном-подкладкой

Карточка «стоит» на фоне секции: section { background:#f8f9fa } + card белая. Практика: сетка курсов на сером полотне. Скринридер «не» различает, но «иерархия» визуальна. Контраст тени на фоне. Border-radius: 12px. Внутренние отступы: padding. Тень «там, где карточка» отделяется от фона. Грид-гэпы. Вложенные поля — аккуратно. Проверка контраста текста. Пространственная иерархия — сигнал. Аккуратные границы — профессионализм. Воздушная композиция. Семантика: article в карточке. Функциональная эстетика.

💡
Фон секции + тень карточки «подъёмает» её «над» полотном — читаются уровни.

Слово «и» в заголовке: заглавные — не «криком»

Заголовки «не» «кричат», а «говорят». ЗАГЛАВНЫЕ в заголовке — крик, скринридер «прочтёт» буквы как слово? — да, но стиль… Практика: «нормальный» регистр с «правильным» акцентом. Шрифты: вес/размер разрешают «тихо» выделить. Слова «с» заглавной — не «используйте» безмерно. КАПС для акцента «одного» слова — ок «в» малом. Проверка: длинный капс труден для чтения (дислексия). Типографика: smaller caps для иронии. Дисциплина «тишины» в тексте. Уважение читателю. «Величавость» — через интервалы. Аккуратный регистр. Читаемость = доступность.

💡
Вместо КАПС используйте font-weight/размер/курсив — «прочитается» легче и красивее.

Отступ «уютный»: margin для сгруппированных блоков

Вертикальные отступы «устанавливают» ритм. margin-bottom «разделяет» абзацы; «margin-top» «void» — кроме перв. Скринридер «не оgap», но «темп» глаз понимает. Практика: p { margin: 0 0 1rem }. Последовательность отступов — повторяемость. Не «собирайте» мусор из марджинов в одну кучу. Используйте flow-отступы (margin к следующему). «Не» обязателен «одинаковый» напр. ВАЖНО: марджин «сливается» (схлопывание) — знание. Проверка: глазами «дышится». Дисциплина ритма. Отступ «внутри» — padding, «между» — margin. Пространство — тишина кода. Единый язык вертикали.

💡
margin: 0 0 1.5rem «к» следующему — «минуса» верхнего margin не «надо» почти никогда.

Центрирование по-взрослому: flex и логика

Центрирование «блока» внутри секции: body «полоса» flex? Практика: центрируем карточку, форму, логотип. display:flex; justify-content:center; align-items:center — и высоты. Скринридер не «видит» геометрию, но «порядок» читается. Не «мучайте» margin:auto «без» нужды? — но это тоже способ. Вертикальное центрирование — flexbest. Для «одной» строки — line-height трюк. Проверка: на разной высоте окна — стабильно. Дисциплина: центрируем «правильно», с пониманием. «Выравнивание» = «гармония». Сетка — структура. Но «центр» не всегда «лучше» (текст — left). Осознанный выбор.

💡
Секция-герой: display:grid; place-items:center; min-height:60vh — центр «готов».

Фон и текст: контраст «не» жертва декора

Фон «красивый» (градиент, фото) «может» съесть текст. Скринридер «не» о фоне, но «читаемость» страдает. Практика: текст на фото — с плашкой/градиентом поверх. Контраст 4.5:1 (текст), 3:1 (крупный). «Overlay»: rgba(0,0,0,.45) под текст. Не «полагайтесь» на «светлый» фон. Проверка: WebAIM contrast checker. Обход: светлая полоса. Бизнес: текст читается всегда. Эстетика в рамках доступности. Затемнение «разумно». Аккуратный баланс «красоты» и «смысла». Контраст — право читателя. Дисциплина оформления.

💡
Тёмная плашка rgba(0,0,0,.45) «под» текст на фото — контраст «в» кармане без вреда виду.

Поля форм: свежий взгляд на высоту

Клик по полю «попадает»: «зона касания» 44px min. Практика: input { height: 44px }. Загадка «тонких» полей: промах мизинцем. Скринридер не «вплотную», но «большой палец» благодарен. У кнопок — то же. «Не» «микросайт» в 20px. Мobile-friendly — это удобство. Высоты едины в форме — ритм. Поля «рядом» друг с другом: без «лишнего» gap. Проверка на сенсоре пальцем. Дисциплина размеров. Когда «мелкие» уместны (десктоп-утилиты) — компромисс. Доступность точности касаний. Уважение к рукам.

💡
Мишень 44×44px — WCAG 2.2: промах «прощает» сенсор. Поля — не «исключение».

Позиционирование: sticky-шапка поверх контента

position: sticky; top:0 — шапка «прилипает» при скролле. Скринридер «не» о «залипании», но «навигация» всегда видна. Практика: меню-шапка sticky. Учесть: фон непрозрачный (чтобы текст «не» просвечивал). Отступ сверху у контента. Проверка: контент «не» прячется под шапку. Sticky «в» пределах родителя. Не «ploди» sticky-в-столбик. На мобильном «меню-бургер» в sticky. Адаптив сочетает. Вертикальный баланс. Ссылки доступны всегда. «Закрепление» = польза. Но «не» «крадите» ~60px у контента разумно. Дисциплина окна.

💡
.header { position:sticky; top:0; background:#fff } — фон «обязателен», иначе текст «плывёт». .resum

Заголовок внутри figure: подпись и семантика

figure+figcaption «паспорт» иллюстрации. Можно ли «внутрь» заголовок? — «не» «обязательно»; figcaption уже «имя». Практика: img+figcaption «График 1». Скринридер: figcaption «как» подпись. Не «дублируйте» h3 «над» figcaption — шум в навигации. «Заголовок» фигуры = figcaption. Для «раздела» с фигурами — секция с h2. Структура: figure самодостаточен. Рисунок «смысловой» в статье. Проверка: порядок оглавления чист. Семантика «рисования». Краткая подпись. Осмысленная. Каждая фигура «представлена». Не «взвешивайте» лишними h. Чистота списка заголовков.

💡
Подпись «рисунок 1» в figcaption — «а» отдельный h заголовок секции — «руководит» списком.

Разделители «элегантно»: hr и его значение

<hr> — «тематический» разрыв между разделами (не «линейка-декор»!). Скринридер «пауза» между темами. Практика: hr между «Интро» и «Глава». Не «пользуйтесь» hr для простой линий декора — use border. WAI-ARIA: hr — «разделитель». Стиль: тонкая линия, отступы. «Не» «встаньте» hr «в» середине логической связи. Проверка: скринридер слышит «прерывание». Простота: .separator может заменить. Семантический разрыв контента. Доступность «пауз». Аккуратность структуры. Не злоупотребляйте «линеатурами». Осмысленный «воздух» глав.

💡
hr — тематический сдвиг; для «декоративной» линии — border-bottom у элемента.

Выделение в тексте: mark корректно

<mark> «подсвечивает» релевантное: совпадение поиска, акцент. Скринридер «прочтёт» без особой интонации? — «да». Практика: в результатах поиска выделить совпадение mark. Не «сортируйте» mark «для» цвета — эм не для того. mark «жёлтый» по умолчанию сменен кастом. Много mark = «крик». Проверка: mark в «прогрессе» чтения. Семантика: маркировка «важности» (скринридер голосом?). Для «эм»/«strong» — различие: strong — важность, em — ударение, mark — соответствие. Аккуратное применение. Фон mark не «убивает» контраст. Доступность выделений. Точность значения.

💡
Для «поиска»: <mark>текст</mark> — читается и подсвечено. Для «эмоции» — em, «важности» — strong.

Списки «сложные»: ol вложенный нумерация

Вложенный ol «нумерует» иерархию: шаги с под-шагами. Скринридер «прочитает» уровни. Практика: инструкция «с» подпунктами. start= задаёт старт: start=2 «продолжает». reversed — обратный счёт. Не «смешивайте» уровни «случайно». Не «ломайте» нумерацию визуально, если семантика — ol. Каждый li — элемент. Листинги упорядоченные — «когда» важна последовательность. Не «переделывайте» 1. на «—» «вручную». Проверка: Nested ol валиден? — да. Знак «иерархии» — глубина. Семантика «умных» списков. Диапазоны «просты». Аккуратность структуры «данных».

💡
Вложенный список «продолжает» нумерацию родителя: ol внутри li — «подшаги» смысла.

Текст-обёртка: first-letter и стили «кап»

::first-letter «украшает» первую букву абзаца (буквица). Практика: роман-зачин с большой буквой. Скринридер «не» об этом — но «чтение» элегантно. Не «переусердствуйте»: буквица «в» правовой странице? — нет. ::first-line — первая строка. CSS-псевдо — декорация, «не» смысл. Проверка: contrast «буквицы». Здоровая мера приёма. Буквица крупная, float. Ограничение: only block. Осознанная «красивость» глав. Дизайн и читабельность «вместе». Не «засоряйте» текст. Эстетика первой буквы — деталь мастера. Сохранность доступности.

💡
p::first-letter { font-size:3em; float:left; line-height:1 } — «классика» детской книжки.

Выделение мышью: ::selection и фирменный цвет

::selection задаёт цвет «фона/текста» при выделении. Практика: маркер-акцент под бренд. Скринридер не «озвучит» цвет, но «ритм» глаза важен. Не «ломайте» контраст: текст+фон в паре. Не «убирайте» выделение вовсе — сложно копировать. Практикуйте: кастом «выделения» в статьях. Каскад: ::selection «наследуется» с body. Доступность: «не» «сливайте» bg с текстом. Проверка: кисть по тексту — читаемо ли. Эстетика «аккуратного» маркера. Мера: одна «тёплая» подложка. Осмысленное акцентирование. Глаз любит порядок. Скорость чтения при выделении. Уважение к жесту. Тонкость деталей типографики. Дисциплина «спокойных» атрибутов.

💡
::selection { background:#ffe08a; color:#222 } — «жёлтый маркер» как в бумажном учебнике.

Хлебные крошки: путь навигации по сайту

Хлебные крошки показывают «где» вы в иерархии: Главная / Каталог / Кроссовки. Практика: страница товара с тремя уровнями. Скринридер «прочтёт» список ссылок; навигация aria-label=«Хлебные крошки». Разделитель «/» » — семантически лишний, скройте (aria-hidden или CSS). Не «разбивайте» текущий пункт ссылкой — просто текст. Практика: nav + ol + li. Каждый уровень — ссылка «назад». Проверка: порядок от «корня» к «листу». Доступность: «полный» путь без кликов. Удобство «возврата». Иерархия «ясна». Не «плодите» крошки где «без » 2 уровней. Дисциплина навигации. Простота ориентиров.

💡
<nav aria-label=«Крошки»><ol>… — «список» упорядочен — читается как «путь».

Пограничный случай: перенос длинного URL в тексте

Длинный URL «ломает» верстку: overflow-wrap:anywhere / word-break:break-word мнут строки. Практика: ссылка-адрес в письме/статье. Скринридер «прочтёт» весь URL — «не» «режьте» его aria- «не». Стиль: overflow-wrap:anywhere на a в контенте. Гиперссылка «не» «выплескивается» за блок. Мобильный: «не» «едут» колонки. Желание™: разбить по «/»? — CSS. Проверка: узкая колонка — ссылка влезает. Доступность: «куда» ведёт — видно «до» клика (title/текст). Дисциплина: сокращайте видимый текст, но «сохраняйте» href полный. Комфорт «длинных» ссылок. Читабельность адреса. Аккуратный перенос. Уважение к строке. Простота контента.

💡
overflow-wrap:anywhere — слова «ломаются» везде, где нужно, без JS-обрезок.

Числа и таблицы: выравнивание вправо

Числовые данные в таблицах выравниваются вправо — «визуальная» колонка сумм. Скринридер «знаком» с числами; выравнивание гармония. Практика: бюджет, ведомость. th — заголовок колонки; числа td правым краем. Десятичные точки выровнены (tabular-nums). Скринридер не «дергается» о выравнивании, но «взгляд» сравнивает. Проверка: alignment «в» колонке единый. Summing вниз — line. Доступность: контраст цифр. Не «центрируйте» числа в таблицах — «теряется» сравнение. Дисциплина чисел. Аккуратная колонка данных. Мера: join с «отчетами». Читаемость цифр — уважение. Простота финансов. Осмысленная сетка таблицы.

💡
font-variant-numeric: tabular-nums — цифры «одинаковой» ширины, колонка «не» прыгает.

Один такой: :only-child для «единственного»

:only-child — единственный ребёнок родителя. Практика: «пустая» строка таблицы, пустое состояние списка. Скринридер «не» знает CSS-селектор, но «контент» читается. Практика: уведомление «без» соседей. Не «навешивайте» :only-child для декора. Данные динамичны — состояние важно. Псевдокласс «экономит» классы в DOM. Не «путать» с :first-child/:last-child. Скринридер: читает естественно. Проверка: визуально один — стиль. Меньше «мусора» в разметке. Доступность «пустоты». Ясные пустые состояния. Осознанный CSS-выбор. Чистота селекторов. Профессиональный минимализм. Семантичные псевдо.

💡
li:only-child { list-style:none } — пункт без пары «не» рисует маркер вдалеке.

Горизонтальные табы: семантика вкладок без JS

Табы из чистого HTML «без» JS сложны. Практика: скорее «аккордеон» details или «якорные» секции. Скринридер: настоящие вкладки — role=tablist/tab/tabpanel с активным состоянием (ARIA). Не «стройте» «псевдо-табы» на click без ARIA — обман. Проще: вкладки как «якорные ссылки» к секциям. Tab-клавиша «не» «входит» в «роль» правильно без tabindex=-1 (JS). Реализм: «без» JS держитесь кнопок-гиперссылок и «видимой» секции-выбранной. Проверка: скринридер «читает» активную. Доступность вкладок — дело ARIA-дисциплины. Компромисс: аккордеон. Осознанная семантика. Простота vs «эффект». Честность состояний.

💡
Пока нет JS — вкладки «как» якорные ссылки + :target-стиль текущей секции справятся.

Смеси блока: padding против gap внутри карточки

Внутри карточки: padding «дышит» от края; gap — между дочерними. Практика: карточка статьи: заголовок, отступ, текст. Скринридер не видит пробел, но «композиция» ясна. Не «путать» margin (снаружи) и padding (внутри). Практика: два способа сделать «воздух» внутри. Вертикальный ритм: margin-bottom элементов. Проверка: переполнение при росте контента. flex/grid gap позволяет «не» «вешать» margin на первый элемент. Скринридер «не» о gap. Доступность: контент не «слипается». Дисциплина отступов. Чистый ритм карточки. Осмысленное пространство. Экономия CSS. Гармония блока. Профессионализм в деталях.

💡
В column-flex лучше gap, чем «margin-top» на каждый элемент «кроме» первого.

Заголовок и время: тег time в статье

<time datetime=«2025-03-14»>14 марта</time> — машиночитаемая дата. Скринридер «прочтёт» текст; machine — datetime. Практика: дата публикации в блоге. «Не» «прячьте» время в текст. Формат ISO для машины, человеческий — для глаз. time <time> — только дата/время, не «длительность» события без времени? — можно. Проверка: datetime корректен, парсер поймёт. Скринридер «не» «путает». Доступность «свежести». Практика: публикация+обновление. Метаданные в потоке. Точность даты. Дисциплина времени. Профессионал «подписывает» момент. Место: в шапке статьи. Ясность «когда» для всех. Аккуратная мета.

💡
<time datetime=«2025-03-14T09:00»> — время ± пояс хранить можно как полный ISO 8601.

Заголовок как кнопка: подвох в деталях

Заголовок accordion-секции обычно <button> внутри заголовка — «не» заменяет h. Практика: details>summary — нативный аккордеон, где summary «спрятан»? Нет. summary — заголовок «виден». Реальность: h внутри button? — «не» валидно (button flow content). Практика: summary с CSS. Скринридер читает summary как «раскрыватель» (aria-expanded). Не «плодите» «кликабельные» заголовки без состояния. Проверка: клавиша Space «раскрывает». Больше — details/summary «без» JS. Доступность аккордеона. Осмысленный заголовок-интерактив. Гибкость семантики. Честный интерактив. Дисциплина структурных тегов. Простота открытия.

💡
<summary> — это и «заголовок», и «переключатель»: семантика уже есть, стилизуйте.

Команда margin: горизонтальное выравнивание

margin: 0 auto — центрирует блочный элемент с шириной. Практика: форма, колонка, логотип. Скринридер не о геометрии, но «пустое» поле по бокам гармонично. Не «запирайте» автора. Скринридер «не» «более» равноправен. Практика: max-width + auto — «мягкий» центр. Проверка: только при явной ширине. Переполнение: box-sizing. Доступность центров «не» влияет на чтение. Дисциплина: margin auto для «одного» центрируемого. Полная ширина? — «auto» «0». Вложенные — аккуратно. Вертикальное центрирование иначе (flex). Простота «резины». Осмысленная композиция. Уважение к полям. Гармония страницы. Чистый CSS-жест.

💡
max-width: 40rem; margin-inline: auto — центр с «дыханием» по краям на «больших» экранах.

Переключатель света: тёмная тема через CSS

Тёмная тема: media (prefers-color-scheme: dark) задаёт другие переменные. Практика: :root — свет, @media dark — тёмный. Скринридер не «о теме», но «глазу» легче ночью. Не «жгите» глаза белым. Переменные + prefers-color-scheme. Проверка: переключить тему ОС — сайт «отзовётся». Контраст в тёмной теме: чёрный фон + тёмный текст? — «нет», #111+#eee. Аккуратно с тенями (в тёмной — «светлее»). Скринридер ничего. Доступность выбора. «Не» только «авто» — дайте кнопку. Дисциплина палитры. Осмысленная тьма. Комфорт чтения. Современный стандарт. Уважение к режиму пользователя. Гармония фона.

💡
Цвета в CSS-переменных — там и «тёмная» панель: поменяли значения — сайт «переобулся».

Выравнивание по сетке: baseline у списков и текста

align-items: baseline — элементы «опорной» линией текста. Практика: label «рядом» с инпутом выровнены по тексту. Скринридер не о CSS, но «взгляд» приятен. Не «теряйте» ось текста — baseline гармонирует. Практика: списки курсов с ценой и названием. Проверка: старт «в» строке. flex/grid align-items. Скринридер не заметит — «база» восприятия. Доступность ритма: нет «скачков». Дисциплина выравнивания. Профессиональная композиция. Осмысленная ось. Простота глаза. Читабельная сетка. Уважение типографики. Точность верстки.

💡
.row { display:flex; align-items:baseline } — текст «стоит» на одной линии даже у заголовков разного размера.

Между заголовком и абзацем: lead-параграф

• Лидирующий абзац — «вступление»: крупнее, ослаблен весом, сразу суть. Практика: статья с первым-более-заметным абзацем. Скринридер «чист» — но «взгляд» ловит смысл. Не «увлекайтесь»: lead — 1 абзац, не «5». Класс .lead со стилем. «Не» «вздувайте» размер до заголовка. Мораль: подпис-интро. Проверка: контраст текста. Доступность «начала». Практика длинных статей. Простой приём «входа» в материал. Дисциплина визуальной иерархии. Осмысленный акцент абзаца. Читатель сразу «в теме». Осознанная типографика. Уважение к читателю. Краткое «зерно» статьи.

💡
.lead { font-size:1.15em; color:#333 } — первый абзац словно «говорит» громче остальных.

Курсор-помощник: pointer на интерактиве

cursor: pointer на кликабельном — «сигнал» руки. Практика: кнопки, ссылки, переключатели. Скринридер не «видит» курсор, но «мотив» ясен. Не «вешайте» pointer на не-интерактив. Проверка: div с onclick — нужен role/таб. Cursor default на тексте. Не «злоупотребляйте»: pointer только где «жмётся». Тонкость: на дизейбл-кнопке cursor: not-allowed. Каскад переходов. Практика: кнопка-ссылка. Скринридер «не» о курсоре. Доступность: кликабельность «понятна». Дисциплина курсора. Интерфейс «отвечает» на движения мыши. Визуальный намёк интерактива. Простота сигналов. Уважение к жесту. Честная кнопка. Гармония UI.

💡
Там, где «не» можно кликнуть — cursor: not-allowed честно «скажет» об этом до клика.

Видимость рамок: border и radius вокруг полей

border поля виден «полем» формы; border-radius скругляет. Практика: input с мягким радиусом + спокойной рамкой. Скринридер не о декору, но «поле» распознаётся по label. Не «убирайте» рамку вовсе — граница «говорит». Не «спорьте» с требованием вводе. Проверка: контраст рамки. focus — меняет цвет рамки. Практика: серая рамка → акцентная при фокусе. Доступность: видимое «поле ввода». Дисциплина границ. Осмысленная рамка. Мягкий радиус (4–8px). Тонкость стилизации. Профессиональная форма. Уважение к деталям. Гармония ввода. Чистый контур.

💡
input { border:1px solid #ccc; border-radius:6px; transition:border-color .2s } — дефолт-порядок.

Скорость чтения: колонки и ширина текста

Оптимальная ширина текста — 60–75 символов на строку. Практика: статья с max-width контента. Скринридер не «не» „заснул“, но длина строки «играет» для глаз. Не «растягивайте» абзацы на весь монитор. Проверка: слишком длинные строки «устали» взгляд. Доступность «линии». Скринридер «не» о средстве. Практика: max-width: 65ch на секции. Дисциплина «ширины» чтения. Уважение к движению глаз. Мерное насыщение. Осмысленный простор. Осознанное «поле» для текста. Читаемость вне зависимости от монитора. Комфорт абзаца. Профессионализм типографики.

💡
max-width: 65ch — международный «коридор» чтения; ch = ширина «0» шрифта.

Определённый хлеб: дефиниции через dl

<dl> (список определений) — термины + определения: dt + dd. Практика: глоссарий, параметры товара. Скринридер свяжет? — «да», порядок чтения. Каждый dt имеет dd. Не «путайте» с ul/ol (они «списки», dl — «пары»). Практика: «Диагональ» — dt, «15.6″» — dd. Доступность: скринридер «прочтёт» пару. Не «вставляйте» dl внутрь текста «для» декора. Проверка: ассоциация пары. Множество: несколько dd к одному dt — можно. Дисциплина «определений». Осмысленный глоссарий. Чистая семантика. Уважение терминов. Простота структуры. Профессиональный словарь. Ясность близнецов-пар.

💡
<dl><dt>Цвет</dt><dd>графит</dd></dl> — скринридер скажет «цвет — графит» как пару.

Ссылка целиком: stretched-link с фокусом

Ссылка «растягивается» на всю карточку: позиционируем «псевдослой» поверх. Практика: карточка товара, вся «кликабельна». Скринридер увидит «настоящую» ссылку (не спан). Не «дублируйте» ссылок вокруг — одна. Проверка: фокус попадает на ссылку. Практика: article>a.stretched. Доступность: одна цель клика. Не «разбивайте» клик по «зонам». Дисциплина: контент карточки не «должен» перекрываться ссылкой-псевдо? — используйте z-index на тексте. Скринридер: порядок чтения. Простота «большой» цели — удобство. Осознанная ссылочная область. Профессиональный паттерн. Гармония клика. Чистая разметка.

💡
.card a.stretched::after { content:»»; position:absolute; inset:0 } — «оболочка»-ссылка без <a> вокруг всего.

Поля label: связка «нажал на слово»

label с текстом — клик по слову переводит фокус в поле. Практика: чекбоксы с крупными подписями. Скринридер «читает» label как имя поля. Не «разрывайте» связь: for=id. Практика: radio «Настроение». Проверка: клик по тексту выбирает. Доступность: большая зона для касания. label.as-block для макета. Дисциплина: у каждого контрола — label. Скринридер: имя «прежде» ввода. Без label — «безымянное» поле. Осмысленная метка. Простой таргет-«между». Осознанная зона клика. Уважение к пальцу и клавиатуре. Профессиональная форма. Гармония подписей.

💡
Чекбокс-поля: label большой, живой «регион» — «не» только квадрат 20px для пальца.

Маленький экран: стоп-кадр media-запросов

@media (max-width:600px) меняет макет под узкий экран. Практика: колонки в столбик, шрифт не меньше 16px. Скринридер «не» о пикселях, но «поток» чтения сохраняется автоматически (DOM-порядок). Не «ломайте» порядок визуальным переразмещением. Проверка: просмотр на 360px. Практика: «меню-бургер» на малом, полное на большом. Доступность: фокус не «прыгает». Дисциплина брейкпоинтов: раз, плавно. Осмысленная адаптация. Сохранение смысла. Простота мобильного «жеста». Осознанный сброс размеров. Уважение к многообразию экранов. Гибкая сетка. Профессиональный responsive. Гармония вида.

💡
Стартуйте с мобильного вида («mobile-first») — большие экраны «расширяют» базу.

Псевдокласс empty: пустая строка без «хвоста»

:empty — элемент без дочерних узлов (даже «пробела»!). Практика: ячейка/маркер/«без» текста. Скринридер «не» особенно, но «пустоту» контролирует визуал. Не «оставляйте» лишние пробелы — :empty «не» сработает. Редкий случай: «точка»-разделитель. Проверка: «без» whitespace. Практика: пустое состояние списка.. Доступность: пространство «не» сбивает чтение. Дисциплина: не «мусорить» DOM. Осмысленная пустота. Чистая разметка. Простота селектора. Продвинутый CSS. Осознанная степень абстракции. Уважение к коду. Меньше «лишнего». Профессиональная точность.

💡
div:empty::before { content:»Нет данных»; } — «пустой» блок сам «попросит» подсказку.

Цвет ссылки: наследование и унаследованный вид

Ссылки по умолчанию — синие и подчёркнутые; «не» «теряйте» этот сигнал. Практика: смена цвета ссылок под палитру, но с контрастом и отличием от текста. Скринридер «прочтёт»; визуально «не» путайте с обычным текстом. Не «убирайте» подчёркивание без замены (hov/focus). Проверка: 3:1 к фону для link. Доступность: «понятно», что это ссылка. Практика: nav без подчёркивания, но с hover/focus. Дисциплина отличий. Не «нагибайте» весь текст в ссылки. Простая деталь. Осмысленный акцент. Гармония линка. Профессиональная стилизация. Уважение к привычке чтения. Чистота ссылок.

💡
Ссылка в тексте: отличается цветом + подчёркиванием/жирностью — не «только» цветом (WCAG 1.4.1).

Кнопки-соседи: порядок в форме

Порядок кнопок: «основной» слева/первый в DOM? — для «жителей» LTR первичный слева, для валидности — логика. Практика: «Отмена» `Сохранить`? Скринридер читает по DOM. Осторожно с «везде-привычкой». Проверка: Tab — последовательно. Не «переставляйте» визуально (flex-order) против чтения. Доступность: фокус-порядок предсказуем. Практика: форма «Сохранить|Отменить». Дисциплина: первичное действие — первое «в» DOM/взгляде. Не «плодите» лишних кнопок. Осмысленный порядок. Уважение к сценарию. Простота действий. Профессиональный выбор. Гармония кнопок. Чистая логика формы.

💡
Форма с двумя действиями: «не» «хаотичные» кнопки — «осмысленный» порядок и Tab-id.

Подпись к полю: «невидимый» label для поиска

Где визуальная метка не помещается (иконка-лупа) — «скрытый» label: класс visually-hidden, сохраняет доступность. Практика: поле поиска с aria-label. Скринридер «прочтёт» скрытую метку. Не «выключайте» label. Проверка: «лупа» с aria-label="Поиск". Доступность: поле имеет имя. Практика: .sr-only. Не «путайте» display:none (скрытая от скринридера). Дисциплина: метка «есть» всегда. Визуально — иконка/placeholder. Осмысленное имя. Простота доступа. Уважение к незрячему. Профессиональная форма. Гармония поиска. Чистая семантика. Лёгкость ввода.

💡
<input aria-label="Поиск по сайту"> — без «видимого» текста, но имя есть для скринридера.

Типографика списков: маркеры и отступы

У списков — свои «отступы»: padding-left у ul/ol рисует маркеры. Скринридер «не» о CSS-маркере, но «список» семантичен. Практика: list-style-position: outside. Не «убирайте» маркеры без причины (list-style:none где меню). Проверка: вложенность читается. Практика: читаемый список определений. Доступность «перечня». Дисциплина: маркеры помогают «глазу». Осмысленный список. Уважение к структуре. Простота перечня. Гармония пунктов. Чистый текст. Профессиональная разметка. Осознанный вид маркера. Лёгкость сканирования. Ясность списка.

💡
ol { list-style: decimal; padding-left } — нумерация «естественная»; вложенные — свой счёт.

Крайние поля: авто отступы и «воздух»

Отступы между соседями: margin-bottom вместо «margin-top у каждого». Практика: стопка статей, абзацев. Скринридер «не» о пробеле, но «ритм» глазом. Не «плодите» margin сверху и снизу — схлопывание сбивает. Проверка: одинаковый «шаг» по вертикали. Практика: gap для flex/grid колонок. Доступность «пространства». Дисциплина ритма. Единый «интервал» в композиции. Осмысленный поток. Простота макета. Уважение к чтению. Гармония «тишины». Профессиональный порядок. Чистые отступы. Лёгкость восприятия. Осознанная коллекция пробелов.

💡
p + p { margin-top:0 } — «та же» кучка абзацев: один отступ между ними, не два.

Ссылка-«Х» «в» конце индекса: архив-ряд из чисел

Ряд «страниц»: «1 2 3 … 12» + «Предыдущая/Следующая» <nav>. Практика: каталог с постраничкой. Скринридер «найдёт» nav-ориентир; relative-ссылки — «заголовки» осмысления. «Не» «разрывайте» ряд: red&-числа не «выпадают», если «не» ссылки — «span» с aria-current=page. Проверка: «Текущая» явно отмечена текстом/состоянием. Доступность «пагинации». Дисциплина «границ» ряда. Осмысленная «страница 1 из 12». Практика: «…» как span. Уважение к «дальней» навигации. Профессиональный «огрызок» чисел. Гармония «стрелок». Чистая «полка» страниц. Ясный «край» пагинации.

💡
<a aria-current="page">2</a> — скринридер «прочтёт: «страница 2, текущая». Точный «флажок» позиции.

CSS-порядок в DOM: «поток» через source order

Визуальный flex/grid может «переставлять», но «чтение» идёт DOM-порядком. Практика: карточка: заголовок, текст, кнопка — «уже» в DOM «правильно». Скринридер «не» «прыгнет» по визуалу. Не «перестраивайте» markup ради «красоты» flex’а — сохраняйте «поток». Проверка: линейное «прочтение» без скачков. Доступность «порядка». Практика: «действие» последним в DOM. Дисциплина «семантического» потока. Осмысленная «очередь» блоков. Уважение к чтению. Профессиональная «центровка» без «ломания» смысла. Ясная последовательность секций. Гармония «источника».

💡
Не «злоупотребляйте» <div style="order"> для визуала — Tab «забудет» направление.

Якорные «прыжки»: ссылка на секцию страницы

<a href="#code">К коду</a> + <section id="code">: якорь по странице. Практика: «оглавление» лонгрида. Скринридер «Tab» «не» о якоре? — «нет», но «ссылка» имя — цель. Не «ломайте» id (уникален). Проверка: клик — вниз к секции; фокус? — «должен» уйти к цели! Не «прячьте» target на странице. Практика: «К началу» в конце. Доступность «прыжков». Дисциплина «уникальности» id. Осмысленный «горизонт» лонгрида. Профессиональная «навигация по секциям». Уважение к длине. Лёгкость возврата.

💡
Для «фокуса на цель»: у секции tabindex="-1" и JS .focus() после клика.

Тег picture «не» «всегда»: просто img с srcset

srcset на img «сам» «выберет» размер по плотности/ширине: <img srcset="a.jpg 1x, b.jpg 2x">. Практика: retina. Скринридер «не» о плотности, но «контент» тот же. Не «тяните» picture «где» хватает srcset. Проверка: на retina берётся 2x. Доступность «резкости». Практика: декоративная замена. Дисциплина «весов» изображения. Осмысленный «ретина-режим». Профессиональная «чёткость». Уважение к экрану. Лёгкость кэша. Гармония «density».

💡
srcset с w-дескрипторами: "a.svg 480w, b.svg 960w" + sizes — «подлинная» респонсивность.

Скриншот-«превью» «в» карточке: img + figcaption «с» alt

Скриншот интерфейса в карточке-портфолио: figure+figcaption, alt «описывает» «что» на скрине (если значимо) или aria-hidden+подпись (декор). Практика: кейс с превью. Скринридер «прочтёт» alt/подпись — «не» «огромный» текст. Практика: alt="Скриншот формы регистрации". Доступность «витрины» работ. Дисциплина «честного» alt. Осмысленный «кейс». Профессиональное «превью». Уважение к детали. Гармония «портфолио».

💡
Если скриншот — «иллюстрация», а не «данные»: alt="" + подпись под ним — «без» «бессмысленного» описания.

Переключатель темы: role=switch «настоящий»

Тумблер темы «светлая/тёмная»: button role="switch" aria-checked. Практика: header-контрол. Скринридер «прочтёт» состояние. Не «имитируйте» switch div-ом «без» роли. Проверка: Space — переключение, aria-checked меняется. Доступность «выбора». Дисциплина «двух состояний». Осмысленная «тема». Профессиональный «тумблер». Уважение к предпочтениям. Гармония «переключателей». Честное «вкл/выкл».

💡
<button role="switch" aria-checked="false">Тёмная тема</button> — «имя» ясно, состояние «слышно».

Субтитры: track внутри <video> для «речи»

<track kind="captions" src="ru.vtt"> внутри <video> — субтитры/тифлокомментарий. Практика: урок-видео с ВТТ. Скринридер «прочтёт» текст? — «не» всегда; дайте транскрипт рядом. Не «прячьте» «смысл» только в звуке. Проверка: кнопка CC. Доступность «медиа». Дисциплина «надписей». Осмысленная «речь» в тексте. Практика: kind="descriptions". Уважение к глухоте. Профессиональный «плеер». Гармония «звук+текст».

💡
aria-label на <video> или текст-описание: «Демо: как собрать форму» — контекст без кадров.

Группа radio «как» фильтр: имя у каждого пункта

Фильтр-радио (по цене, по дате) — fieldset+legend «Фильтр», каждый radio с label. Практика: сортировка каталога. Скринридер «прочтёт» легенду и опции. Не «заменяйте» radio «внешним» div-стилем «без» семантики. Проверка: стрелки переключают. Доступность «фильтра». Дисциплина «одного» выбора. Осмысленная «опция». Профессиональная «сортировка». Уважение к выбору. Гармония «рядов-filters». Честный «один-ответ».

💡
<fieldset><legend>Сортировка</legend> — «группа» названа; radio внутри — «список» значений.

Валидация «на лету»: aria-live для сообщения под полем

Сообщение об ошибке появляется — aria-live="assertive" на контейнере подсказки. Практика: пароль валидируется при вводе. Скринридер «озвучит» сразу (assertive прерывает). Не «кричите» на «каждый» ввод — polite для нененавязчивого. Проверка: message под полем прочлось. Доступность «мгновенной» обратной связи. Дисциплина «живой» области. Осмысленный «момент» подсказки. Профессиональная форма. Уважение к темпу. Гармония валидации. Честное «сообщение».

💡
aria-live=polite при «нормальных» подсказках; assertive — только «критичные» ошибки (редко).

Видео-заставка: poster-кадр без «спойлера»

<video poster="cover.jpg"> — первый «кадр» до «плэя». Практика: курс-превью с фирменным «кадром». Скринридер «не» видит poster — нужен текст/транскрипт рядом. Не «прячьте» «смысл» за видео. Проверка: controls + poster комфортно. Доступность «медиа»-заставок. Дисциплина «первого» кадра. Осмысленная «обложка». Профессиональный «тизер». Уважение к «до-клика». Гармония кадров. Честная «история» на постере.

💡
poster + <p>текст-описание</p> рядом — «два» канала: глаз (кадр) и ухо (смысл).

Список «с аудио»: ссылки на треки с длительностью

Плейлист-список: <ul><li><a>Урок 1 — 12 мин</a></li>… — каждая ссылка «не» форма. Практика: подкаст-серия. Скринридер «прочтёт» название и длительность. Не «вставляйте» <audio> в каждый li «без» контролов. Проверка: имя ссылки осмысленно. Доступность «медиа-ряда». Дисциплина «листа» треков. Осмысленная «длина» в имени. Профессиональный «подкаст». Уважение к времени. Гармония списка. Честная «минута».

💡
aria-label="Скачать аудио Урок 1" у иконки <a> — «раздельно» скачивание и «слушание».

Аудио-контролы «свои»: кнопка play с aria-live статусом

Кастомный плеер: кнопка play/pause + <div aria-live=polite> «Статус: воспроизведение». Практика: радиоплеер в шапке. Скринридер «озвучит» переход. Не «вешайте» только иконку (меняется фон) — aria-label меняется с состоянием. Проверка: Space — play/pause. Доступность «плеера». Дисциплина «статуса». Осмысленный «текст». Профессиональный «контрол». Уважение к прослушиванию. Гармония «звука».

💡
Кнопка aria-label="Пауза" при «играет» и "Играть" при «стоит» — «имя» честно меняется.

Длинный контент: видимая «ссылка-якорь» для tabs через id

«Tabs» «через» якоря (без JS): <nav> ссылки #tab1…, <section id="tab1">. Практика: описание/характеристики товара. Скринридер «прочтёт» ссылки; нажатие «едет» по странице. Не «моделируйте» aria-tab без JS-поведения ролей. Проверка: секции «видимы» (не aria-hidden «навсегда»). Доступность «якорных» вкладок. Дисциплина «простого» таба. Осмысленные секции. Профессиональный «компромисс». Уважение к потоку. Гармония секций. Чистая «навигация». Честный «переход».

💡
Якорные табы «не» «скрывают» контент — «всё» в DOM, скринридер прочтёт подряд.

Заголовок «с» числом «в» series: h2+маленький «порядковый»

«Часть 3» как h2 + подзаголовок — <hgroup> или «обычный» h2 + p. Практика: серия уроков «Часть III: сетка». Скринридер «прочтёт» как «имя» пары. Не «дублируйте» «порядковый» в двух заголовках. Проверка: имя «вкладки» осмысленно. Доступность «серии». Дисциплина «частей». Осмысленный «номер». Профессиональная «нумерация» глав. Уважение к «эпосу». Гармония «порядка». Честная «часть».

💡
<h2><span class="muted">Часть 3:</span> Сетка и таблицы</h2> — «и» ряд, «и» имя.