Gridstack.js — библиотека для построения динамических сеточных интерфейсов с возможностью перетаскивания и изменения размеров виджетов. Несмотря на то что основная логика библиотеки связана с JavaScript-поведением и управлением координатами элементов, структура HTML остаётся фундаментом, на котором строится вся система.
Семантическая разметка в контексте Gridstack.js выполняет несколько задач:
Семантика HTML помогает отделить структуру интерфейса от поведения и визуального оформления, что особенно важно при работе с интерактивными дашбордами и панелями управления.
Любой интерфейс Gridstack строится вокруг контейнера сетки и вложенных элементов-виджетов.
Минимальная структура выглядит следующим образом:
<div class="grid-stack">
<div class="grid-stack-item">
<div class="grid-stack-item-content">
Контент
</div>
</div>
</div>
Контейнер сетки
<div class="grid-stack"></div>
Этот элемент является корневым контейнером для всех виджетов. Библиотека инициализирует на нём сеточную систему, управляет позициями элементов и отслеживает взаимодействие пользователя.
Элемент сетки (виджет)
<div class="grid-stack-item"></div>
Каждый такой элемент представляет отдельный блок интерфейса, который можно перемещать и масштабировать.
Контент виджета
<div class="grid-stack-item-content"></div>
Этот контейнер содержит реальное содержимое виджета: графики, таблицы, формы, панели управления и другие компоненты интерфейса.
Gridstack управляет только контейнерами виджетов. Содержимое внутри
grid-stack-item-content может использовать полноценную
семантическую HTML-структуру.
Пример:
<div class="grid-stack">
<div class="grid-stack-item">
<div class="grid-stack-item-content">
<article class="widget">
<header class="widget-header">
<h2>Статистика продаж</h2>
</header>
<section class="widget-body">
<canvas id="sales-chart"></canvas>
</section>
<footer class="widget-footer">
Обновлено: сегодня
</footer>
</article>
</div>
</div>
</div>
Такой подход обеспечивает:
Каждый виджет в сетке может иметь стандартную внутреннюю структуру.
<header class="widget-header">
<h3>Заголовок виджета</h3>
</header>
Заголовок обычно содержит:
Пример:
<header class="widget-header">
<h3>Активные пользователи</h3>
<div class="widget-controls">
<button>Обновить</button>
<button>Настройки</button>
</div>
</header>
<section class="widget-body">
</section>
В основной области располагается основной контент:
Пример:
<section class="widget-body">
<ul class="stats">
<li>Сегодня: 1543</li>
<li>Вчера: 1489</li>
<li>Неделя: 10234</li>
</ul>
</section>
<footer class="widget-footer">
</footer>
Используется для:
Пример:
<footer class="widget-footer">
Последнее обновление: 12:40
</footer>
Семантика структуры дополняется атрибутами позиционирования, которые определяют положение элементов в сетке.
Основные атрибуты:
| Атрибут | Назначение |
|---|---|
gs-x |
позиция по горизонтали |
gs-y |
позиция по вертикали |
gs-w |
ширина |
gs-h |
высота |
Пример:
<div class="grid-stack">
<div class="grid-stack-item"
gs-x="0"
gs-y="0"
gs-w="4"
gs-h="2">
<div class="grid-stack-item-content">
Контент виджета
</div>
</div>
</div>
Такая структура позволяет описывать положение элементов прямо в HTML, что удобно для:
Для расширения семантики элементов часто применяются
data-* атрибуты.
Пример:
<div class="grid-stack-item"
gs-x="2"
gs-y="1"
gs-w="3"
gs-h="2"
data-widget-type="chart"
data-widget-id="sales">
Назначение таких атрибутов:
Пример использования:
const widgets = document.querySelectorAll('.grid-stack-item');
widgets.forEach(widget => {
const type = widget.dataset.widgetType;
const id = widget.dataset.widgetId;
console.log(type, id);
});
В сложных интерфейсах сетка может находиться внутри более крупных структур.
Пример панели управления:
<main class="dashboard">
<header class="dashboard-header">
<h1>Панель аналитики</h1>
</header>
<section class="dashboard-grid">
<div class="grid-stack">
<div class="grid-stack-item" gs-w="4" gs-h="2">
<div class="grid-stack-item-content">
Виджет
</div>
</div>
</div>
</section>
</main>
Семантические элементы помогают определить:
main)section)header, footer)Внутри виджетов часто располагаются элементы управления.
Правильная семантика:
<button class="refresh-btn">
Обновить
</button>
Вместо:
<div class="refresh-btn">Обновить</div>
Использование корректных HTML-элементов обеспечивает:
Если виджет отображает структурированные данные, полезно применять соответствующие HTML-элементы.
<table class="data-table">
<thead>
<tr>
<th>Страна</th>
<th>Пользователи</th>
</tr>
</thead>
<tbody>
<tr>
<td>Казахстан</td>
<td>1200</td>
</tr>
</tbody>
</table>
<ul class="activity-list">
<li>Пользователь зарегистрирован</li>
<li>Обновление профиля</li>
<li>Создание отчёта</li>
</ul>
<section class="metrics">
<article class="metric">
<h4>Доход</h4>
<p>$12 430</p>
</article>
<article class="metric">
<h4>Пользователи</h4>
<p>5 203</p>
</article>
</section>
Gridstack позволяет создавать сетки внутри виджетов.
Семантическая структура:
<div class="grid-stack">
<div class="grid-stack-item" gs-w="6" gs-h="4">
<div class="grid-stack-item-content">
<section class="nested-dashboard">
<div class="grid-stack nested-grid">
<div class="grid-stack-item" gs-w="3" gs-h="2">
<div class="grid-stack-item-content">
Внутренний виджет
</div>
</div>
</div>
</section>
</div>
</div>
</div>
Это позволяет строить сложные многоуровневые интерфейсы.
Семантическая разметка играет ключевую роль в обеспечении доступности.
Для сложных интерфейсов применяются дополнительные атрибуты.
Пример:
<div class="grid-stack-item"
role="region"
aria-labelledby="widget-title-1">
<div class="grid-stack-item-content">
<h3 id="widget-title-1">
График продаж
</h3>
</div>
</div>
Это позволяет экранным читалкам правильно интерпретировать структуру страницы.
Для элементов управления важно использовать правильные HTML-теги.
Пример:
<button aria-label="Закрыть виджет">
×
</button>
Семантическая разметка должна описывать структуру интерфейса, а не поведение.
Правильный подход:
<button class="widget-refresh">
Обновить
</button>
Jav * aScript:
document
.querySelector('.widget-refresh')
.addEventListener('click', refreshWidget);
Неправильный подход:
<button oncl ick="refreshWidget()">
Обновить
</button>
Такое разделение:
Семантическая структура облегчает масштабирование интерфейса.
Пример расширяемого виджета:
<article class="widget widget-chart">
<header class="widget-header">
<h3>Трафик сайта</h3>
</header>
<section class="widget-body">
<canvas></canvas>
</section>
<footer class="widget-footer">
<button class="details-btn">
Подробнее
</button>
</footer>
</article>
В дальнейшем можно добавить:
Структура остаётся понятной и легко расширяется.
Типовой шаблон:
<div class="grid-stack-item"
gs-x="0"
gs-y="0"
gs-w="4"
gs-h="2">
<div class="grid-stack-item-content">
<article class="widget">
<header class="widget-header">
<h3>Название виджета</h3>
</header>
<section class="widget-body">
Основной контент
</section>
<footer class="widget-footer">
Дополнительная информация
</footer>
</article>
</div>
</div>
Такая структура: