Как реализовать responsive-дизайн в CSS?

MiddleCSS #css #responsive

Вопрос

Как устроен адаптивный (responsive) дизайн в CSS: что такое медиазапросы, чем отличается mobile-first подход от desktop-first, и какие единицы измерения для этого используются?

Короткий ответ

Responsive-дизайн строится на медиазапросах (@media), которые применяют разные стили в зависимости от характеристик viewport, и на относительных единицах измерения, которые сами масштабируются под контекст. Mobile-first означает, что базовые стили пишутся под маленький экран, а медиазапросы min-width добавляют/переопределяют стили для больших экранов.

Подробный ответ

Медиазапросы (@media) позволяют применять блок CSS-правил только при выполнении условий: ширина viewport, ориентация, тип устройства, prefers-color-scheme и т.д. Чаще всего используются брейкпоинты по ширине: @media (min-width: 768px) { ... }.

Mobile-first vs desktop-first:

  • Mobile-first — базовые (не обёрнутые в медиазапрос) стили пишутся для самого маленького экрана, а дальше через min-width добавляются стили для больших экранов, постепенно "достраивая" макет. Это соответствует принципу прогрессивного улучшения: мобильный CSS проще и легче, а сложные многоколоночные раскладки — это надстройка поверх базы.
  • Desktop-first — обратный подход: базовые стили под десктоп, а max-width медиазапросы упрощают макет для меньших экранов. Часто приводит к более тяжёлому и запутанному CSS, так как приходится "отменять" десктопные стили.

В современной практике mobile-first считается предпочтительным: он лучше соответствует приоритету производительности на мобильных устройствах и естественному потоку блочных элементов (которые по умолчанию складываются в колонку, что и нужно на маленьком экране).

Относительные единицы для адаптивности:

  • % — относительно родителя.
  • em — относительно font-size текущего элемента (или родителя для не-font свойств).
  • rem — относительно font-size корневого элемента (html), удобен тем, что не накапливает эффект вложенности как em.
  • vw/vh — относительно ширины/высоты viewport.
  • clamp() — функция, задающая значение с минимумом, предпочтительным (обычно во vw) и максимумом, что позволяет плавно масштабировать без медиазапросов вовсе.

Пример

/* mobile-first: базовые стили под маленький экран */
.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  padding: 16px;
}

.title {
  font-size: clamp(1.25rem, 4vw + 0.5rem, 2.5rem);
}

/* планшет и выше */
@media (min-width: 768px) {
  .grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
  }
}

/* десктоп и выше */
@media (min-width: 1200px) {
  .grid {
    grid-template-columns: repeat(3, 1fr);
    padding: 32px;
  }
}

Дополнительные вопросы

  • Почему mobile-first обычно даёт более компактный итоговый CSS?
  • Чем clamp() может заменить набор медиазапросов для типографики?
  • Как container queries (@container) меняют подход к адаптивности по сравнению с @media?