Размер имеет значение: почему скрипты "ломают" вёрстку
Представьте: вы пишете идеальный адаптивный сайт, проверяете на своём ноутбуке — всё летает. Запускаете на планшете клиента — баг. Элементы наезжают друг на друга, модальное окно уезжает за границу экрана, а какая-то галерея вообще отказывается открываться. Знакомо?
Чаще всего корень зла — неправильное получение размеров экрана, окна браузера или самой страницы. Вопрос "Get the size of the screen, current web page and browser window" на Stack Overflow набрал сотни тысяч просмотров. И это не случайно: даже опытные разработчики путают screen.width, window.innerWidth и document.documentElement.clientWidth.
В этой статье мы разберём 5 самых частых ошибок, которые допускают новички (и не только) при работе с размерами в JavaScript. Вы получите не только теорию, но и готовые, проверенные решения для реальных задач.
Топ-5 ошибок при работе с размерами в JavaScript
Ошибка №1: Использовать screen.width вместо window.innerWidth
Это классика. Разработчик хочет узнать ширину области просмотра (viewport) и пишет:
// ❌ Неправильно
const viewportWidth = screen.width;
console.log(viewportWidth); // 1920 (но это не viewport!)
В чём подвох? screen.width возвращает физическую ширину монитора в пикселях. Она не меняется, если вы уменьшите окно браузера или откроете инструменты разработчика. А window.innerWidth — это ширина области просмотра (viewport), то есть той части окна, где отображается контент.
Когда это ломает сайт: Если вы рассчитываете адаптивные блоки по screen.width, при открытии DevTools или уменьшении окна сайт не перестраивается. Пользователь видит либо пустоту, либо наложение элементов.
// ✅ Правильно
const viewportWidth = window.innerWidth;
console.log(viewportWidth); // Текущая ширина видимой области
Ошибка №2: Забывать про прокрутку (scrollbar)
Вторая по популярности ловушка. Разработчик получает высоту окна и пытается разместить элемент ровно посередине:
// ❌ Неправильно
const windowHeight = window.innerHeight;
element.style.top = windowHeight / 2 + 'px';
На первый взгляд всё верно. Но если контент длиннее экрана и есть полоса прокрутки, window.innerHeight включает её высоту. В результате элемент может "уехать" за нижнюю границу видимой области.
Решение: Используйте document.documentElement.clientHeight — он возвращает высоту viewport без учёта полосы прокрутки.
// ✅ Правильно для позиционирования в видимой области
const viewportHeight = document.documentElement.clientHeight;
element.style.top = viewportHeight / 2 + 'px';
Запомните правило:
window.innerWidth/innerHeight— с учётом скроллбара.document.documentElement.clientWidth/clientHeight— без учёта скроллбара. Выбирайте по задаче.
Ошибка №3: Путать размер окна и размер страницы
Вы хотите узнать, как далеко прокрутился пользователь, и вычисляете общую высоту страницы:
// ❌ Неправильно
const pageHeight = window.innerHeight;
console.log(pageHeight); // Это не высота страницы!
window.innerHeight — это высота окна, а не документа. Чтобы получить полную высоту страницы (включая прокрученную часть), нужно использовать document.documentElement.scrollHeight.
Реальный пример: Вы делаете бесконечную ленту (infinite scroll). Если использовать window.innerHeight для определения момента подгрузки новых постов, скрипт сработает один раз и больше никогда не вызовет подгрузку.
// ✅ Правильно: полная высота документа
const fullPageHeight = document.documentElement.scrollHeight;
console.log(fullPageHeight); // Высота всего контента
Ошибка №4: Не обновлять размеры при ресайзе окна
Разработчик получает размеры один раз при загрузке страницы и использует их статично:
// ❌ Неправильно
const width = window.innerWidth;
// ... весь код использует width
// Пользователь разворачивает окно на весь экран — код не реагирует
Это приводит к тому, что при изменении размера окна (ресайзе, повороте устройства) вёрстка "застывает". Особенно критично для мобильных устройств, где ориентация меняется часто.
Решение: Подписывайтесь на событие resize и обновляйте значения.
// ✅ Правильно
let currentWidth = window.innerWidth;
window.addEventListener('resize', () => {
currentWidth = window.innerWidth;
console.log('Новая ширина:', currentWidth);
// Здесь можно вызвать функцию пересчёта вёрстки
});
Совет: Для производительности используйте debounce или requestAnimationFrame, чтобы не перегружать браузер частыми вызовами.
Ошибка №5: Игнорировать разницу между DOM-свойствами
Новички часто копируют код из интернета, не понимая, какое свойство что возвращает. Вот краткий справочник, который спасёт вас от путаницы:
| Свойство | Что возвращает | Когда использовать |
|---|---|---|
screen.width |
Ширина монитора (физическая) | Почти никогда для вёрстки. Только для спецэффектов. |
window.innerWidth |
Ширина viewport + скроллбар | Анимации, расчёты с учётом скролла. |
document.documentElement.clientWidth |
Ширина viewport без скроллбара | Позиционирование элементов, адаптивная вёрстка. |
document.documentElement.scrollHeight |
Полная высота документа | Бесконечная лента, прогресс-бары чтения. |
window.scrollY |
Количество прокрученных пикселей по вертикали | Параллакс, фиксация шапки. |