Адаптивный дизайн предполагает построение интерфейса, который корректно отображается на устройствах с различными размерами экранов. В Preact, как и в React, для реализации адаптивного поведения используется комбинация CSS, медиазапросов и реактивных JavaScript-решений.
Ключевая цель — обеспечить динамическую подстройку компонентов под доступное пространство, сохраняя при этом производительность и удобство поддержки кода.
Медиазапросы позволяют изменять стили в зависимости от характеристик устройства: ширины экрана, ориентации, плотности пикселей и других. Базовый синтаксис:
.container {
display: flex;
flex-direction: row;
gap: 16px;
}
@media (max-width: 768px) {
.container {
flex-direction: column;
gap: 8px;
}
}
В данном примере изменяется направление элементов и промежутки между ними на узких экранах, что делает интерфейс более читаемым на мобильных устройствах.
Ключевые моменты:
max-width — применяется, если ширина экрана меньше
указанного значения.min-width — применяется, если ширина экрана больше
указанного значения.В Preact компоненты можно делать адаптивными не только через CSS, но и с использованием JavaScript, отслеживая размер окна и изменяя состояние компонента.
Пример реактивного компонента, который меняет отображение в зависимости от ширины экрана:
import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
function ResponsiveMenu() {
const [isMobile, setIsMobile] = useState(window.innerWidth <= 768);
useEffect(() => {
const handleResize = () => setIsMobile(window.innerWidth <= 768);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return (
<nav>
{isMobile ? (
<button>Меню</button>
) : (
<ul>
<li>Главная</li>
<li>О нас</li>
<li>Контакты</li>
</ul>
)}
</nav>
);
}
Особенности подхода:
useEffect обеспечивает корректное добавление и удаление
слушателя событий.useState хранит текущее состояние устройства
(isMobile).matchMediaДля более гибкого контроля можно использовать API
window.matchMedia. Оно позволяет подписываться на
изменения состояния медиазапроса без постоянного отслеживания
resize события.
Пример:
import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
function useMediaQuery(query) {
const [matches, setMatches] = useState(window.matchMedia(query).matches);
useEffect(() => {
const mediaQueryList = window.matchMedia(query);
const listener = (event) => setMatches(event.matches);
mediaQueryList.addEventListener('change', listener);
return () => mediaQueryList.removeEventListener('change', listener);
}, [query]);
return matches;
}
function ResponsiveSidebar() {
const isDesktop = useMediaQuery('(min-width: 1024px)');
return isDesktop ? <aside>Боковая панель</aside> : null;
}
Преимущества использования
matchMedia:
resize.Для построения адаптивных интерфейсов важно использовать гибкие сетки. Preact не накладывает ограничений на CSS-сетку, поэтому можно применять:
minmax() для динамических
размеров.Пример адаптивной сетки с Grid:
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
@media (max-width: 1024px) {
.grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 600px) {
.grid {
grid-template-columns: 1fr;
}
}
Комбинирование сеток с реактивными компонентами позволяет строить интерфейсы, которые меняются плавно, без перезагрузки страницы.
clamp()
позволяет задавать размер шрифта, который адаптируется под ширину
экрана:h1 {
font-size: clamp(1.5rem, 2vw, 3rem);
}
srcset и sizes, чтобы браузер подбирал
оптимальный размер картинки:<img src="small.jpg"
srcset="medium.jpg 768w, large.jpg 1200w"
sizes="(max-width: 768px) 100vw, 50vw"
alt="Адаптивное изображение">
useMediaQuery.Часто используется комбинация подходов:
Такой подход позволяет создавать интерфейсы, которые остаются удобными и быстрыми на любых устройствах, снижая вероятность багов при изменении размеров экрана.