Сказ о двух вьюпортах — часть первая

Решил попрактиковаться в переводе статей. Выбор пал на quirksmode.org и статью A tale of two viewports — part one. Перевод второй части про мобильные браузеры — планируется ;) Далее, собственно, перевод.

В этом мини-цикле статей я объясню, как работают вьюпорт и ширина различных важных элементов страницы, к примеру, таких как <html> элемент, а также, как они соотносятся с окном браузера и экраном монитора.

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

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

Понятие пикселей и CSS-пикселей

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

Пиксели устройств — вид пикселей, которые мы считаем «реальными» или «правильными».

Эти пиксели означают реальное или номинальное разрешение любого устройства и могут быть считаны (в большинстве случаев) с помощью свойства screen.width/height.

Если вы выставите элементу ширину в 128 пикселей: width: 128px и развернете окно браузера на весь экран вашего монитора с разрешением в 1024 пикселя по ширине, то элемент поместится в окне браузера восемь раз (грубо конечно, но давайте в данный момент опустим «хитрые биты»).

Однако, если пользователь увеличит масштаб в браузере — наши расчеты изменятся. Если пользователь увеличит масштаб до 200%, ваш элемент с шириной 128 пикселей уместится на мониторе разрешением в 1024 пикселя только четыре раза

Масштабирование в современных браузерах есть ни что иное, как просте «растягивание» пикселей. Это означает, что ширина нашего элемента не изменяется от 128-ми до 256-ти пикселей, вместо этого пиксели элемента удваиваются в размере. Формально ширина элемента все еще составляет 128 CSS-пикселей даже если и кажется, что элемент занимает 256 пикселей устройства.

Другими словами, увеличение масштаба до 200% делает размер CSS-пикселей в четыре раза больше, чем размер пикселей устройства. (Два раза в ширину и два раза в высоту в сумме дают увеличение в четыре раза).

Несколько изображений прояснят ситуацию. На изображении ниже показаны четыре пиксела в масштабе 100%. Ничего особенного вы здесь не увидите; CSS-пиксели полностью совпадают с пикселями устройства.

Четыре пикселя в масштабе 100%

Теперь давайте немного уменьшим масштаб. CSS-пиксели начнут сжиматься и теперь один пиксель устройства частично перекрывает несколько CSS-пикселей.

Четыре пикселя в масштабе меньше 100%

Если вы сделаете масштаб больше 100%, произойдет обратное. CSS-пиксели начнут увеличиваться и один CSS-пиксель будет частично перекрывать несколько пикселей устройства.

Четыре пикселя в масштабе больше 100%

Дело в том, что вам важны только CSS-пиксели. Именно эти пиксели будут определять как браузерам нужно отображать раскладку страницы в соответствии с вашей таблицей стилей.

В этом случае пиксели устройства для вас совершенно бесполезны. Но не для пользователя. Пользователь будет до тех пор увеличивать или уменьшать масштаб страницы, пока не установит удобный масштаб для ее чтения. Однако этот масштаб вас также совершенно не должен волновать. Браузер сам позаботится о том, чтобы ваша раскладка страницы соответствующим образом растянулась или уменьшилась.

Масштаб в 100%

В примерах я использовал понятие масштаба в 100%. Пришло время определить его немного точнее:

При масштабе в 100%, один CSS-пиксель точно равен одному пикселю устройства.

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

Размер экрана

Давайте взглянем на некоторые практические измерения. Начнем со screen.width и screen.height. Эти свойства определяют точную ширину и высоту экрана монитора пользователя. Эти размеры определены в пикселях устройства, потому что они неизменны, так как являются особенностью монитора, а не браузера.

Свойства screen.width/height

  • Значение: точный размер монитора пользователя
  • Измеряется в: пиксели устройства
  • Ошибки браузеров: IE8 измеряет в CSS-пикселях, как в режиме IE7 так и в режиме IE8

Размеры экрана монитора

Весело! Но что мы будем делать с этой информацией?

В основном ничего. Размер монитора пользователя для нас малозначим, если вы конечно не собираете базу данных разрешений мониторов пользователей для какой-нибудь веб-статистики.

Размер окна

То, что вам действительно нужно знать — это внутренние размеры окна браузера. Они точно подскажут вам, сколько в данный момент места имеется в окне браузера у пользователя для вашей раскладки. Вы можете определить эти размеры с помощью свойств window.innerWidth и window.innerHeight.

Свойства window.innerWidth/Height

  • Значение: точный размер окна браузера, включая полосы прокрутки
  • Измеряется в: CSS-пиксели
  • Ошибки браузеров: Не поддерживается IE. Опера измеряет в пикселях устройства

Размеры окна браузера

Очевидно, что внутренняя ширина окна измеряется в CSS-пикселях. Вам необходимо знать какую часть раскладки вы можете уместить в окне браузера и до какой степени этот размер сократится при увеличении масштаба пользователем. Таким образом, если пользователь увеличивает масштаб, то в окне остается меньше места для отображения страницы и значение window.innerWidth/Height уменьшается, отражая это изменение.

(Исключением является браузер Opera, где значения window.innerWidth/Height не уменьшаются при увеличении масштаба, так как они измеряются в пикселях устройства. Этот факт немного раздражает при разработке под десктопные браузеры и совершенно губительно сказывается в мобильных браузерах, как, увидим в следующей статье.)

Размеры окна браузера после увеличения масштаба меньше

Обратите внимание, что расчитанные ширина и высота включают размеры полос прокрутки. Они считаются частью внутренней области окна браузера (так сложилось исторически).

Величина смещения прокручиваемой области страницы

Свойства window.pageXOffset и window.pageYOffset возвращают величину горизонтального и вертикального смещения прокручиваемой области страницы. С помощью этих свойств вы можете определить размер области страницы прокрученной пользователем.

window.pageX/YOffset

  • Значение: размер прокрученной области страницы
  • Измеряется в: CSS-пиксели
  • Ошибки браузеров: не обнаружены

Размер прокрученной области страницы

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

В теории, если пользователь прокручивает страницу вверх, а затем увеличивает масштаб, window.pageX/YOffset изменится. Однако браузеры пытаются сохранить прежний вид страницы при увеличении масштаба, сохраняя положение верхнего края видимой области страницы. Это не всегда работает идеально, но всетаки означает, что на практике window.pageX/YOffset не изменяется (количество прокрученных CSS-пикселей примерно остается тем же, что и до изменения масштаба)

Размер прокрученной области страницы после увеличения масштаба

Понятие о вьюпорте (области просмотра браузера)

Прежде чем мы продолжим рассматривать следующие JavaScript свойства, введем еще одно понятие: вьюпорт (viewport) или область просмотра браузера.

Функция вьюпорта — ограничить <html> элемент — самый внешний блок вашего сайта.

Возможно, это звучит немного неопределенно, поэтому вот вам практический пример. Предположим у вас имеется резиновая раскладка с одной из колонок шириной 10%. Когда вы изменяете окно браузера, колонка соответствующим образом аккуратно уменьшается или увеличивается по ширине. Но как именно это работает?

Технически колонка высчитывает 10% относительно ширины ее родителя. Скажем родителем для нее является тег <body> и вы не задали ему ширину. Здесь, напрашивается вопрос: какая тогда ширина у <body>?

Как правило все блочные элементы занимают 100% ширины их родителей (конечно существуют исключения, но давайте на этот раз их проигнорируем). Получается, что ширина <body> равна ширине его родителя — <html> элемента.

Какой же ширины тогда <html> элемент? Ширина <html> элемента равна ширине окна браузера. Поэтому ваша колонка шириной в 10% будет занимать 10% ширины окна браузера. Все веб-разработчики знают и используют это обстоятельство.

Вы можете и не знать как это работает в теории. Теоретически, ширина <html> элемента ограничена шириной области просмотра браузера. <html> элемент занимает 100% ширины этой области.

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

Последствия

Такое положение дел приводит к возникновению любопытных последствий. Увидеть одно из них вы можете прямо на этом сайте (имеется ввиду quirksmode.org, прим. перевод.). Прокрутите страницу до самого верха и увеличте масштаб на два-три шага, чтобы некоторая часть контента сайта скрылась за пределами окна браузера.

Теперь с помощью горизонтальной полосы прокрутки, прокрутите страницу вправо и вы увидите, что синяя панель больше не прилегает должным образом к правой границе сайта.

Последствия неверного определения вьюпорта при увеличении масштаба

Подобное поведение является следствием того, как определяется в данном случае область просмотра. Я определил синей панели ширину в 100%. 100% чего? 100% <html> элемента, ширина которого равна ширине области просмотра, которая, в свою очередь, равна ширине окна браузера.

Дело в том, что пока масштаб составлял 100% — все было замечательно, но когда мы его увеличили, область просмотра стала меньше общей ширины моего сайта. Само по себе это не очень важно, содержимое сейчас вылезает за рамки <html> элемента, но так как у <html> элемента по-умолчанию сейчас overflow: visible — не умещающийся в нем контент не будет обрезан и будет виден всегда.

Но синяя панель не вылезает за рамки <html> как остальное содержимое. В конце концов, я установил ей ширину в 100% и браузер точно выполняет указание, устанавливая этой панели ширину области просмотра. Браузеру плевать на то, что теперь эта ширина меньше ширины сайта.

100% от ширины области просмотра

Ширина документа?

Что я действительно хочу выяснить, так это то, какова общая ширина содержимого страницы, включая те ее части, которых не видно в области просмотра. На сколько мне известно, найти это значение невозможно (конечно если вы не займетесь подсчетом ширины и отступов каждого элемента на странице, но это, мягко говоря, ненадежный способ).

Я думаю нам понадобится пара JavaScript свойств, с помощью которых можно будет определить, то, что я называю «шириной документа» (в CSS-пикселях, естетсвенно).

Ширина документа

И если подумать, то почему бы не внедрить это значение в CSS? Я был бы рад, если бы у меня появилась возможность задать моей синей панельке 100% ширины документа, а не <html> элемента. (Это должно быть не так просто сделать, я даже не удевлюсь если это вовсе невозможно.)

А что думаете вы, производители браузеров?

Измерение области просмотра

Возможно вам понадобится определить размеры области просмотра. Их можно найти с помощью document.documentElement.clientWidth и -Height

document. documentElement. clientWidth/Height

  • Значение: размеры области просмотра
  • Измеряется в: CSS-пиксели
  • Ошибки браузеров: не обнаружены

Размер области просмотра

Если вы знакомы с объектной моделью документа (DOM), вам известно, что document.documentElement — это, фактически, <html> элемент — корневой элемент любого HTML-документа. Однако вьюпорт на один уровень выше, это, так скажем, элемент, который содержит в себе <html> элемент. Может так случится, что вы зададите <html> элементу ширину, я бы не рекомендовал этого делать, но это, кстати, возможно.

В подобной ситуации document.documentElement.clientWidth и -Height будут возвращать размеры области просмотра, а никак не <html> элемента. (Это специфичное правило распространяется только на эту ситуацию и только на эту пару JavaScript свойств. Во всех остальных случаях используется реальная ширина элемента.)

«Ошибочное» определение размеров области просмотра

Таким образом, document.documentElement.clientWidth и -Height всегда возвращают размеры области просмотра, без учета размеров <html> элемента.

Две пары свойств

Но ведь размеры области просмотра окна браузера можно узнать также с помощью window.innerWidth/Height? И да и нет.

Существует определенная разница между этими двумя парами свойств: document.documentElement.clientWidth и -Height — не включают размеры полос прокрутки, в отличие от window.innerWidth/Height. Хотя, по большому счету, это уже мелочи.

Тот факт, что у нас сейчас имеется две пары свойств  — пережиток прошлого со времен Войны браузеров. В то время браузер от Netscape поддерживал только window.innerWidth/Height, а IE только document.documentElement.clientWidth и -Height. С тех пор все остальные браузеры начали поддерживать clientWidth/Height, но IE так и не стал понимать window.innerWidth/Height.

Наличие двух пар свойств причиняет лишь мелкие неудобства при разработке под десктопные браузеры, но в мире мобильных браузеров оказывается хорошим подспорьем, как будет видно в следующей статье.

Измерение <html> элемента

Мы выяснили, что clientWidth/Height в любом случае возвращает размеры области просмотра окна браузера. Но как нам узнать размеры самого <html> элемента? Они хранятся в document.documentElement.offsetWidth и -Height.

document. documentElement. offsetWidth/Height

  • Значение: размеры <html> элемента (а значит и всей страницы)
  • Измеряется в: CSS-пиксели
  • Ошибки браузеров: IE измеряет область просмотра, а не <html> элемент

Размер <html> элемента

Эти свойства действительно дадут вам доступ к размерам <html> элемента как блочного элемента, если вы установите ширину, offsetWidth ее отразит в своем значении.

Размер <html> элемента с заранее заданной шириной

Координаты событий

pageX/Y, clientX/Y, screenX/Y

  • Значение: см. текст статьи
  • Измеряется в: см. текст статьи
  • Ошибки браузеров: IE не поддерживает pageX/Y; IE и Opera расчитывают screenX/Y в CSS-пикселях

Существуют также координаты событий. Когда просиходит событие мыши, в не менее пять пар свойств записываются значения, чтобы дать вам как можно более точную информацию о месте на странице в котором оно произошло. Для нашего повествования наиболее важны три из них:

  1. pageX/Y содержит координаты относительно <html> элемента в CSS-пикселях;
  2. clientX/Y содержит координаты относительно области просмотра страницы в CSS-пикселях;
  3. screenX/Y содержит координаты относительно экрана устройства в пикселях устройства.

pageX/Y
pageX/Y
clientX/Y
clientX/Y
screenX/Y
screenX/Y

В 90% случаев в разработке вы будете использовать pageX/Y. В большинстве случаев вам будет необходимо узнать место возникновения события относительно документа. В остальных 10% случаев вы будете использовать clientX/Y. И вам никогда не понадобится знать координаты события относительно экрана монитора пользователя.

Медиа-запросы

И на последок, пару слов о медиа-запросах (media queries). Идея очень проста: вы определяете специальные CSS-правила, которые выполняются только если ширина страницы больше чем, равна или меньше определенной величины. Например:


div.sidebar {
	width: 300px;
}

@media all and (max-width: 400px) {
	// стили, которые должны выполниться, когда ширина станет меньше 400px;
	div.sidebar {
		width: 100px;
	}

}

Сейчас ширина колонки составляет 300 пикселей, за исключением тех случаев, когда ширина меньше 400 пикселей, в этих случаях ширина колонки будет изменена до 100 пикселей.

Здесь конечно же напрашивается вопрос: относительно ширины чего изменяется ширина колонки?

Существует два характерных медиа-запроса: width/height и device-width/device-height.

  1. width/height работает с теми же значениями, что и documentElement.clientWidth/Height (другими словами: размерами области просмотра). Все расчеты просиходят в CSS-пикселях.
  2. device-width/device-height использует те же значения, что и screen.width/height (другими словами: экрана монитора пользователя). Все расчеты просиходят в пикселях устройства.

width/height и device-width/device-height

Media queries

  • Значение: см. текст статьи;
  • Измеряется в: см. текст статьи;
  • Ошибки браузеров:
    • IE их не поддерживает.
    • Для device-width/height Firefox использует значения screen.width/height как если бы они рассчитывались в CSS-пикселях.
    • Для width/height Safari и Chrome используют значения documentElement.clientWidth/Height как если бы они рассчитывались в пикселях устройства.

Какой же тип медиазапросов вы должны использовать? Это очевидно, конечно же width. Веб-разработчиков не интересует ширина экрана, важна ширина окна браузера пользователя.

Поэтому при разработке под десктопные браузеры используйте width и забудте о device-width. Как мы узнаем из следующей статьи, ситуация с мобильными браузерами намного более запутанная.

Заключение

Этим завершим наше быстрое знакомство с поведением десктопных браузеров. Во второй статье спроецируем концепции и понятия рассмотренные здесь на мобильные браузеры и выделим некоторые существенные различия.

Комментарии

  1. Максим Усачёв
    30 декабря 2011 в 17:04
    1

    Здорово! Спасибо за перевод. Переводи ещё, с удовольствием будем читать :)

    • Евгений Бескровный
      30 декабря 2011 в 17:32
      2

      Пожалуйста, обязательно буду, если свободное время будет позволять ;)

  2. 29 января 2012 в 16:04
    3

    Спасибо! Проясняет много неясных моментов.
    Есть поправка по терминологии: screen.width/height, window.innerWidth/Height и т.д. – это свойства, а не методы.

  3. яяя
    3 сентября 2012 в 14:16
    5

    width/height работает с теми же значениями, что и documentElement.clientWidth/Height

    Что-то у меня получается, что медиа запросы используют скорее window.innerWidth / window.innerHeight т.е. с учётом полос прокрутки.

    • Евгений Бескровный
      3 сентября 2012 в 19:59
      6

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

  4. Всеволод
    8 декабря 2012 в 12:36
    7

    я даже не удИвлюсь если это вовсе невозможно.)

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*

Правила форматирования