Fresh — это современный фреймворк на базе Deno, ориентированный на высокую производительность и минимальное использование JavaScript на клиенте. Основой его подхода является рендеринг на стороне сервера (SSR) с автоматической гидратацией компонентов. В контексте Fresh правильное использование семантического HTML становится критически важным для структуры, доступности и SEO.
Семантический HTML — это использование тегов в соответствии с их смыслом, а не только для визуального оформления. В Fresh это напрямую влияет на:
Примеры ключевых семантических элементов:
<header> — верхняя часть страницы или секции,
содержит логотип, навигацию.<nav> — основной блок навигации.<main> — основное содержимое страницы.<article> — автономный блок контента, например,
пост блога.<section> — тематический раздел, объединяющий
связанные элементы.<aside> — дополнительная информация или боковая
панель.<footer> — нижняя часть страницы или секции с
контактами, копирайтом и ссылками.В Fresh компоненты создаются как функции, возвращающие JSX. При этом использование семантических тегов в JSX идентично стандартному HTML:
export default function BlogPost(props: { title: string; content: string }) {
return (
<article>
<header>
<h1>{props.title}</h1>
</header>
<section>
<p>{props.content}</p>
</section>
<footer>
<p>Опубликовано: {new Date().toLocaleDateString()}</p>
</footer>
</article>
);
}
Ключевые моменты:
<article> оборачивает автономный контент, который
может быть повторно использован или отдельно индексирован.<header> и <footer> внутри
<article> содержат информацию, специфичную для этой
записи.<section> делит контент на логические блоки без
потери семантики.Семантический HTML усиливается использованием ARIA-атрибутов для динамического контента:
<button aria-expanded="false" aria-controls="menu" id="menu-button">
Меню
</button>
<nav id="menu" hidden>
<ul>
<li><a href="/about">О нас</a></li>
<li><a href="/contact">Контакты</a></li>
</ul>
</nav>
aria-expanded показывает состояние раскрывающегося
элемента.aria-controls связывает кнопку с навигационной
панелью.hidden скрывает элемент от визуального
рендеринга, но семантика сохраняется.Fresh поддерживает SSR, поэтому ARIA-атрибуты применяются на сервере, что делает интерфейсы доступными даже до гидратации на клиенте.
Корректная структура страницы в Fresh обычно выглядит так:
export default function Page() {
return (
<html lang="ru">
<head>
<title>Пример страницы</title>
</head>
<body>
<header>
<h1>Заголовок сайта</h1>
<nav>
<ul>
<li><a href="/">Главная</a></li>
<li><a href="/blog">Блог</a></li>
</ul>
</nav>
</header>
<main>
<section>
<h2>Раздел контента</h2>
<p>Текст раздела с подробным описанием темы.</p>
</section>
<aside>
<h3>Сайдбар</h3>
<p>Дополнительная информация или ссылки.</p>
</aside>
</main>
<footer>
<p>© 2025 Компания Fresh</p>
</footer>
</body>
</html>
);
}
Особенности:
<main> присутствует только один раз на
странице.<aside> используется для второстепенного
контента.Fresh позволяет создавать интерактивные элементы без потери семантики:
import { useState } from "preact/hooks";
export default function FAQItem(props: { question: string; answer: string }) {
const [open, setOpen] = useState(false);
return (
<section>
<button
aria-expanded={open}
onCl ick={() => setOpen(!open)}
>
{props.question}
</button>
{open && <p>{props.answer}</p>}
</section>
);
}
<section> вокруг вопроса и ответа
сохраняет логическую структуру.<button> с aria-expanded делает
компонент доступным.<main> и корректно
вложенные <header> и
<footer>.<section>
или <article>, а не <div> без
смысла.<nav>, а не
произвольные списки <div>.Соблюдение этих принципов обеспечивает корректную работу SSR, улучшает SEO и делает интерфейсы доступными для всех пользователей.