Семантическая разметка в JSX

Семантическая разметка описывает смысл и назначение элементов интерфейса, а не их внешний вид. В контексте JSX это означает осознанный выбор HTML-тегов, которые корректно передают структуру документа, и сохранение этой структуры при компонентном подходе. Preact не изменяет правила HTML-семантики: JSX компилируется в обычные DOM-узлы, поэтому все принципы нативной разметки остаются актуальными.

Корректная семантика влияет на:

  • доступность для скринридеров и вспомогательных технологий;
  • корректную навигацию с клавиатуры;
  • интерпретацию контента поисковыми системами;
  • поддержку и масштабируемость кода.

Семантические HTML-элементы в JSX

JSX позволяет использовать стандартные HTML-теги без ограничений. Семантические элементы применяются так же, как в обычной разметке:

const Layout = () => (
  <div>
    <header>
      <h1>Заголовок страницы</h1>
    </header>

    <main>
      <article>
        <section>
          <h2>Раздел</h2>
          <p>Основной контент</p>
        </section>
      </article>
    </main>

    <footer>
      <small>© 2025</small>
    </footer>
  </div>
);

Ключевые элементы семантической структуры:

  • <header> — вводная часть страницы или раздела;
  • <nav> — навигационные блоки;
  • <main> — основной уникальный контент документа;
  • <section> — логически объединённый фрагмент;
  • <article> — самостоятельная единица контента;
  • <aside> — побочный, вспомогательный контент;
  • <footer> — завершающая информация.

Использование <div> оправдано только при отсутствии подходящего семантического тега.

Семантика и компоненты Preact

Компонентный подход не отменяет требований к структуре HTML. Каждый компонент должен сохранять смысловую роль.

Пример семантически корректного компонента списка:

const Menu = () => (
  <nav>
    <ul>
      <li><a href="/">Главная</a></li>
      <li><a href="/blog">Блог</a></li>
      <li><a href="/about">О проекте</a></li>
    </ul>
  </nav>
);

Нарушение семантики часто возникает при оборачивании всего в универсальные контейнеры:

// плохая практика
const Menu = () => (
  <div>
    <div>Главная</div>
    <div>Блог</div>
  </div>
);

JSX не навязывает структуру, поэтому ответственность за семантику лежит на архитектуре компонентов.

Fragment и сохранение структуры

Preact поддерживает Fragment, позволяющий избежать лишних DOM-узлов без потери семантики:

import { Fragment } from 'preact';

const Article = () => (
  <article>
    <>
      <h2>Заголовок</h2>
      <p>Текст статьи</p>
    </>
  </article>
);

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

Заголовки и иерархия

Иерархия <h1><h6> формирует логическую структуру документа. JSX не проверяет корректность уровней, поэтому важно соблюдать последовательность:

<main>
  <h1>Документация</h1>
  <section>
    <h2>Установка</h2>
    <h3>Через npm</h3>
  </section>
</main>

Пропуски уровней (h1h4) затрудняют навигацию для скринридеров, даже если визуально всё выглядит корректно.

Формы и элементы управления

Семантика форм особенно критична для доступности. JSX требует явного связывания <label> и <input>:

const LoginForm = () => (
  <form>
    <label htmlFor="email">Email</label>
    <input id="email" type="email" />

    <button type="submit">Войти</button>
  </form>
);

В JSX используется htmlFor вместо for, так как for является зарезервированным словом JavaScript.

Кнопки должны оставаться <button>, а не <div> с обработчиком клика. Это обеспечивает:

  • поддержку клавиатуры;
  • корректные роли и состояния;
  • ожидаемое поведение в браузере.

Семантика списков и таблиц

Списки применяются для перечислений, навигации и групп данных:

<ul>
  <li>Элемент</li>
  <li>Элемент</li>
</ul>

Таблицы используются только для табличных данных, а не для верстки:

<table>
  <thead>
    <tr>
      <th>Имя</th>
      <th>Возраст</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Анна</td>
      <td>28</td>
    </tr>
  </tbody>
</table>

Использование <div> вместо <table> лишает данные смысловой структуры и ухудшает восприятие вспомогательными технологиями.

ARIA-атрибуты и JSX

ARIA применяется только при отсутствии нативного семантического элемента. JSX позволяет задавать ARIA-атрибуты напрямую:

<div role="dialog" aria-labelledby="title">
  <h2 id="title">Окно</h2>
</div>

При наличии семантического аналога предпочтение отдаётся HTML-тегу:

<dialog open>
  <h2>Окно</h2>
</dialog>

Избыточное использование ARIA ухудшает доступность, а не улучшает её.

Условный рендеринг и семантика

При условном выводе важно сохранять структуру документа:

{isAuthorized && (
  <nav>
    <a href="/profile">Профиль</a>
  </nav>
)}

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

Семантика и производительность в Preact

Preact оптимизирован для минимального DOM-дерева. Семантическая разметка способствует этому, так как:

  • сокращает количество лишних узлов;
  • уменьшает вложенность;
  • упрощает диффинг виртуального DOM.

Правильный выбор тегов снижает потребность в дополнительных атрибутах и обработчиках.

Типичные ошибки

Распространённые нарушения семантики в JSX:

  • использование <div> и <span> вместо <button>, <a>, <section>;
  • кликабельные элементы без фокуса и клавиатурной поддержки;
  • отсутствие <main> на странице;
  • дублирование <h1> без необходимости;
  • вложение интерактивных элементов друг в друга.

JSX не предотвращает эти ошибки, поэтому контроль семантики является частью ответственности при разработке компонентов.

Семантическая разметка как часть архитектуры

В Preact семантика закладывается на уровне проектирования компонентов. Компонент должен описывать не только поведение и внешний вид, но и смысловую роль в документе. Такой подход упрощает повторное использование, улучшает доступность и делает код ближе к стандартам веб-платформы.