Адаптивный дизайн и медиазапросы

Адаптивный дизайн предполагает построение интерфейса, который корректно отображается на устройствах с различными размерами экранов. В Preact, как и в React, для реализации адаптивного поведения используется комбинация CSS, медиазапросов и реактивных JavaScript-решений.

Ключевая цель — обеспечить динамическую подстройку компонентов под доступное пространство, сохраняя при этом производительность и удобство поддержки кода.


Использование медиазапросов в CSS

Медиазапросы позволяют изменять стили в зависимости от характеристик устройства: ширины экрана, ориентации, плотности пикселей и других. Базовый синтаксис:

.container {
  display: flex;
  flex-direction: row;
  gap: 16px;
}

@media (max-width: 768px) {
  .container {
    flex-direction: column;
    gap: 8px;
  }
}

В данном примере изменяется направление элементов и промежутки между ними на узких экранах, что делает интерфейс более читаемым на мобильных устройствах.

Ключевые моменты:

  • max-width — применяется, если ширина экрана меньше указанного значения.
  • min-width — применяется, если ширина экрана больше указанного значения.
  • Медиазапросы могут быть комбинированы с различными CSS-свойствами для создания гибкой сетки и адаптивной типографики.

Адаптивные компоненты через Preact

В 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).
  • Позволяет полностью контролировать отображение элементов в зависимости от ширины экрана.

Интеграция медиазапросов в JS через 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-сетку, поэтому можно применять:

  • Flexbox для линейных компоновок.
  • CSS Grid для сложных раскладок.
  • Процентные значения и 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="Адаптивное изображение">
  • В Preact можно динамически менять изображение через пропсы, основываясь на ширине экрана, используя ранее описанные хук useMediaQuery.

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

Часто используется комбинация подходов:

  1. CSS-медиазапросы для простых изменений стилей.
  2. JS и хуки для логики отображения компонентов.
  3. Адаптивная типографика и изображения для улучшения UX и оптимизации загрузки.

Такой подход позволяет создавать интерфейсы, которые остаются удобными и быстрыми на любых устройствах, снижая вероятность багов при изменении размеров экрана.