Урок 31. Теория: Проблемы разных экранов: viewport и DPR

📁 Раздел: Адаптивная вёрстка ⏱️ Время изучения: ~65 мин 🎯 Сложность: Средняя
#meta #viewport #image-set

⚡ Кратко

Один макет выглядит по-разному на телефоне, ноутбуке и ретина-экране. Три понятия объясняют почему:

  • viewport — видимая рабочая ширина страницы в CSS-пикселях; в ней работают width, %, media queries.
  • meta viewport — строка <meta name="viewport" content="width=device-width, initial-scale=1">. Без неё мобильный браузер «притворяется» десктопом шириной ~980px и уменьшает всю страницу.
  • DPR (device pixel ratio) — сколько физических точек экрана приходится на 1 CSS-пиксель. На retina DPR = 2 или 3, поэтому картинку нужно отдавать в 2–3× разрешении.
  • vw / vh — 1vw = 1% ширины viewport, 1vh = 1% высоты. width: 50vw — половина окна.
  • breakpoint — не модель телефона, а ширина, на которой ломается конкретный блок.

Главная идея

Один и тот же сайт нужно показать на телефоне 360px шириной, на планшете, на ноутбуке и на ретина-мониторе. Чтобы это работало предсказуемо, нужно различать три вещи: viewport (сколько места есть для раскладки), CSS-пиксели против физических пикселей (что такое «пиксель» на самом деле) и breakpoint (где менять раскладку). Без этого «лишние» полосы прокрутки, размытые картинки и съехавшая вёрстка кажутся магией.

Viewport — это иллюминатор корабля. Страница — огромный океан за бортом. Вы видите океан не целиком, а через окошко-иллюминатор: его размер и есть viewport. На телефоне иллюминатор узкий, на мониторе — широкий, но сам океан (страница) один и тот же. vw/vh — это «доли иллюминатора»: 50vw = половина ширины окошка, независимо от того, насколько велик океан за ним.

DPR — это плотность точек при печати. Один и тот же логотип можно напечатать «крупными точками» (DPR 1) или «мелкими, плотными точками» (DPR 2–3, как фотопечать). Размер логотипа на бумаге одинаковый, но во втором случае точек вдвое-втрое больше на тот же сантиметр — и картинка выглядит чётче. Поэтому для retina исходник нужен в большем разрешении.

Viewport: одно устройство — разные окна

Viewport — это область, в которой браузер раскладывает страницу, измеряемая в CSS-пикселях. Именно к ней привязаны проценты, media queries и единицы vw/vh. Разные устройства дают разный viewport:

Телефон ~360px Планшет ~768px Десктоп ~1280px
Контент один, но ширина viewport разная — поэтому раскладка перестраивается с 1 колонки на 2 и на 3.

Различают layout viewport (область, в которой считается раскладка) и visual viewport (то, что реально видно при зумe или появлении экранной клавиатуры). В большинстве задач достаточно работать с layout viewport.

meta viewport — обязательная строка

Без тега <meta name="viewport"> мобильный браузер «притворяется» широким десктопом (обычно ~980 CSS-пикселей) и уменьшает всю страницу так, чтобы она влезла. Текст становится крошечным, а media queries срабатывают неверно. Строка width=device-width, initial-scale=1 говорит браузеру: «ширина viewport = ширине устройства, масштаб 1:1».

<meta name="viewport" content="width=device-width, initial-scale=1">

CSS-пиксели против физических пикселей (DPR)

CSS-пиксель — это логическая единица раскладки, а не физическая точка экрана. DPR (window.devicePixelRatio) показывает, сколько физических точек приходится на один CSS-пиксель. На обычном экране DPR = 1, на retina = 2 или 3.

DPR 1: 1 CSS-px = 1 точка DPR 2: 1 CSS-px = 4 точки Один и тот же CSS-квадрат — разное число физических точек
При DPR 2 каждый CSS-пиксель закрашивается 2×2 = 4 физическими точками. Растровая картинка 200×200 CSS-px должна быть файлом 400×400, иначе размыта.

Единицы vw и vh

1vw — это 1% ширины viewport, 1vh — 1% его высоты. Они считаются от размеров окна, а не от родительского блока (этим отличаются от %). width: 50vw — всегда половина ширины окна, как бы глубоко элемент ни был вложен.

.hero {
  width: 50vw;   /* половина ширины окна */
  height: 30vh;  /* 30% высоты окна */
}

Когда применять и частая ошибка

Breakpoint — это момент, когда конкретный блок перестаёт удобно помещаться: строка становится слишком длинной, карточки сжимаются, меню ломается. Ставьте breakpoint по содержимому, а не по моделям телефонов.

Частая ошибка: 100vw на блоке внутри страницы со скроллбаром даёт горизонтальную прокрутку — vw включает ширину вертикального скроллбара, а доступная для контента область уже. Чаще нужен width: 100%.
Проверка себя: открой консоль (F12) и введи window.devicePixelRatio и window.innerWidth — увидишь DPR и ширину viewport своего экрана прямо сейчас.

Навигация