Проблема масштабирования адаптивной верстки на мобильных браузерах
Взялся за верстку своего первого адаптивного сайта. Все шло хорошо: размеры блоков в процентах, использование медиа-запросов и т.д. При экспериментировании с размером браузера все растягивается, сжимается, перестраивается как надо. Загрузил сайт на сервер, зашел со своего смартфона (android) и столкнулся с проблемой. Но тема даже не об этой проблеме, а о другой, которую породило решение первой. Об этом ниже…
Наверное, все кто занимался адаптивной версткой (да и не только адаптивной), знают, что при отображении сайта на мобильной версии браузера (скажем, на размере экрана в ширину 480 точек), сайт не отображается в масштабе 1:1, а «ужимается» под размер окна браузера. Т.е. браузер уменьшает сайт до такого размера, чтобы он целиком уместился в окно браузера. Элементы сайта становятся мелкими, шрифты не читабельными. И пользователю приходится увеличивать (масштабировать) его вручную. Но меня то не устраивает такая ситуация. Я то делал адаптивную верстку с надеждой, что она отобразится в браузере в своем реальном размере и сожмется не за счет масштабирования страницы под размер окна, а именно за счет резиновости блоков. Внешний блок () сайта имеет максимальную ширину 900 пикс, с возможностью сжиматься до 320. Блоки внутри так же сжимаются, перестраиваются и т.д. – это не важно, т.к. речь не об этом. Так вот при сжатии окна браузера на ПК, при размере окна меньше 900 пикс, сайт начинает успешно сжиматься за счет прописанных в css размерах в процентах, медиа-запросов и т.д… А при открытии его на мобильном устройстве он остается в своих реальных размерах и пропорциях, но просто масштабируется до такой степени, чтобы уместиться в окно браузера.
Еще раз повторюсь, что проблема не нова, и возможно многим верстальщикам знакома и может я зря так разжевываю, но все же на всякий случай постарался описать подробно.
И на хабре уже упоминалось решение этой проблемы, и нагуглить не составляет труда. Используем мета тег viewport
который говорит браузеру, что сайт должен отображаться как есть, не масштабироваться автоматически при первоначальной загрузке (потом пальцами, конечно, можно масштабировать, если не запретить это в том же мета-теге). И если, например, это не адаптивный сайт и ширина его больше ширины окна браузера, то он, конечно же, не уместится целиком, пользователю нужно будет либо уменьшать (масштабировать вручную) либо прокручивать. А если это адаптивный сайт, то он, как и было задумано верстальщиком, сожмется за счет резиновости блоков до ширины окна. Что в итоге и произошло с моим сайтом.
Но радость моя была не долгой. До тех пор пока я не открыл эту страничку на планшете. Ширина экрана моего самсунга в горизонтальной ориентации (а проблема возникла именно в просмотре в горизонтальной ориентации) 1280 пикс.
Что же в итоге получилось. Сайт, максимальная ширина которого, напомню 900 пикс, отобразился в своем нормальной размере в 100% масштабе. Но размер экрана устройства 1280 пикс! И что в итоге получлось? А получилось, что сайт не занял всю ширину экрана, а занял свои законные 900 пикс. В итоге по краям остались поля примерно по 154 пикс ((1280-900)/2). Кто-то скажет, что это ж нормально. Ведь когда мы открываем сайт на ПК, с шириной экрана, скажем, те же 1280 точек, то естественно сайт не будет занимать всю ширину, а будет занимать положенные ему 900 пикс, которые заданы в CSS как максимальная ширина сайта (или фиксированная ширина, если это фиксированный макет).
Но на планшете то эта ситуация не кажется нормальной. Т.к. экран сам по себе все-таки маленький, по сравнению с десктопами, хоть разрешение у него и 1280 точек. Хотелось бы, чтобы сайт занимал максимум пространства этого экрана. На компе нам этого не нужно, т.к. 900 пикс на мониторе будут выглядеть нормально, благо размер пиксела у него побольше чем у планшета. А вот на планшете когда страница не занимает весь экран – это кажется дикостью (по крайней мере мне). И все дело в том самом мета-теге viewport, которым мы задали отображение сайта в реальном масштабе. Это помогало нам, когда размер сайта был меньше 900 точек, т.е. помогало нам не масштабировать его под размер экрана, а отображать в реальном размере. Но это мешает нам при размере экрана больше 900 точек, ведь тут как раз хочется, чтобы масштабирование сработало, чтобы сайт увеличился до размеров окна, т.е. по максимум использовал всю ширину экрана, ведь это ж все-таки мобильное устройство.
Я для сравнения загрузил старую версию этого сайта (дизайн полностью такой же, за тем исключением, что не адаптивный, а фиксированной ширины 900 пикс) и он при первоначальной загрузке занял всю ширину экрана. Ведь в нем я не использовал viewport.
В заключение хочу сказать, что тестировал пока только на самсунге. Боюсь предположить, что же будет на iPad, разрешение которого по широкой стороне в два раза больше самсунга, 2048 пикс. Неужели страница будет занимать меньше половины экрана (она ж 900 точек)?
Короче говоря, хотелось бы поинтересоваться у сообщества, сталкивался ли кто-нибудь с подобными проблемами. И можно ли это считать проблемой? Или это нормальное поведение, которое не нужно никак исправлять? Т.е. отобразился сайт в реальном масштабе. Если не занял весь экран, то клиент без проблем увеличит его уже пальцами, смасштабирует как надо?
Пытался найти способ как сделать так, чтобы при размере экрана меньше 900 пикс, viewport срабатывал бы, а при размере больше 900 пикс не срабатывал. Не нашел.
P.S. прошу прощения что не разместил этот текст в q&a, упустил этот момент, а теперь уже не могу поменять.
Нужна помощь. Подскажите пожалуйста как сделать так, чтобы на мобильных устройствах, окно браузера не сужалось менее чем на 650px по ширине, то есть на устройствах с разрешением менее 650px по ширине, браузер показывал сайт в разрешении 650px.
По данному вопросу этот ответ не поможет, но вот с моей проблемой помог. Мой сайт с минимальной шириной в 1200px в google chrome на мобильных устройствах почему-то масштабировался со стандартным , сайт отображался по всей ширине и появлялось пустое место внизу. После того как отключил масштабирование пользователем - сайт выровнялся на 100% по высоте и появился горизонтальный скролл, что мне и было нужно. спасибо!
Не один из вариантов выше не помог.
Проблема была в том, что на мобильных устройствах отображался не на всю ширину и высоту.
Решил таким образом, но основе комментариев и почитав другие вопросы и ответы:
if (window.devicePixelRatio !== 1) { // Костыль для определения иных устройств, с коэффициентом отличным от 1
var dpt = window.devicePixelRatio;
var widthM = window.screen.width * dpt;
var widthH = window.screen.height * dpt;
document.write('<meta name="viewport" content="width=' + widthM+ ', height=' + widthH + '">');
}
А почему вам именно важно чтобы сайт был не более 900 пикселей по ширине?
А на счет iPad с Retina дисплеем не переживайте, если выключать масштабирование у сайта то фактически вы получите те же 1024 в ландскейпе а не 2048.
Если я всё правильно понял, то у Вас имеется контент, минимальной шириной в 320px и максимальной — в 900px. И Вам надо:
1. Если размер экрана устройства меньше 900px, то задать ширину viewport'а страницы как у экрана устройства (чтобы произошло перестроение CSS разметки под эту ширину).
2. Если размер экрана устройства больше или равен 900px, то задать ширину viewport'а страницы в 900px (чтобы на экранах размером в 900px и больше контент увеличивался за счёт масштаба).
Для этой задачи могу предложить следующее решение (скопируйте из данного примера на свой сайт JavaScript код, разместив его выше всех других подключений и вставок CSS и JavaScript кода). Проверял только на iPad 2.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
(function(){
// Выполняем код только на мобильных браузерах (на всякий случай)
if (typeof(window.orientation) !== 'undefined')
{
// Функция взята отсюда: https://makandracards.com/makandra/13743-detect-effective-horizontal-pixel-width-on-a-mobile-device-with-javascript
function getDeviceWidth()
{
var deviceWidth = window.orientation == 0 ? window.screen.width : window.screen.height;
// iOS returns available pixels, Android returns pixels / pixel ratio
// http://www.quirksmode.org/blog/archives/2012/07/more_about_devi.html
if (navigator.userAgent.indexOf('Android') >= 0 && window.devicePixelRatio)
deviceWidth = deviceWidth / window.devicePixelRatio;
return deviceWidth;
}
var deviceWidth = getDeviceWidth();
var maxWidth = 900;
if (deviceWidth < maxWidth)
{
// Мои эксперименты на iPad 2 показали, что device-width всегда содержит значение ширины
// экрана в книжной (portrait) ориентации (т.е. даже, если устройство находится в
// альбомной (landscape) ориентации). Это же утверждалось в некоторых найденных мною статьях.
if (window.orientation == 0 || window.orientation == 180)
document.write('<meta name="viewport" content="width=device-width">');
else
document.write('<meta name="viewport" content="width=device-height">');
}
else
document.write('<meta name="viewport" content="width=' + maxWidth + '">');
}
})();
</script>
<style type="text/css">
* { margin: 0; padding: 0; }
.content { min-width: 320px; max-width: 900px; background: #ffff99; }
.content div { border: 1px solid #f00; }
</style>
</head>
<body>
<div class="content">
<div>
abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc
abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc
abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc
</div>
</div>
</body>
</html>
всё просто, делайте медиа запросы с указанием ширины окна в сантиметрах, а не пикселях.
Например: media (max-width: 20cm) позволит вам отделить маленькие устройства от мониторов, и неважно какие у них будут разрешения в пикселях.
mobi, сколько будет пикселей зависит от плотности экрана.Более менее абсолютная величина. 96px/in - это вроде дефолтное значение для Windows. Конечно браузер иногда берет значение dpi фиг знает откуда, но с помощью строчки media (max-width: 20cm) вполне можно отделить физически маленькие экраны (хотя и с большим разрешением) от ПК-мониторов. Вместо того, чтобы использовать сложные комбинации из 'px' и разных 'dpi' проще использовать именно сантиметры. Я не предлагаю использовать 'cm' для ширины элементов (может там они и неправильно работают), но именно в media-запросах они полезны.
mobi, зачем мне единички и нолики. Неправда ваша. Я вам по факту говорю. На мобильных устройствах будет не 96 (это для Windows), а другие значения. Не в браузере дело (они все должны более менее одинаково работать), а в самом устройстве и его dpi. Например на моём андроид-смартфоне браузер выдаёт значение 180dpi, а не 96dpi, поэтому и сантиметры высчитываются по другому. Конечно есть несоответствие с реальными физическими сантиметрами (ведь реальная плотность пикселей вообще 290dpi), но всё равно выражения media (max-width: 20cm) вполне хватает чтобы понять - маленький перед нами экран или большой. А это для читабельности как раз важно.
fursanton1986, От dpi зависит только сколько реальных пикселей содержится в единице измерения px в CSS. Для всех CSS правил это внутренние детали реализации, т.к. все абсолютные величины измерения приводятся к px через стандартный набор множителей. И в итоге браузер на лету преобразует ваше @media(max-width:20cm) в @media(max-width:756px) и ничто не мешает задать этот размер сразу в пикселях. При изменении масштаба меняется размер базовой единицы px и, как следствие, всех привязанных к ней остальных единиц измерений (можете для проверки сделать тестовую страницу с блоком width:1cm;height:1cm и посмотреть, как он будет менять размер при изменении масштаба).
mobi, если я использую запрос @media(max-width:12cm). Согласно вашей логике он должен преобразоваться в @media(max-width:453px) и можно просто использовать пиксели. Но такой стиль очевидно не должен примениться на экране смартфона, ведь ширина его экрана (в моём случае) 720px. Однако стиль применяется, так как на смартфоне браузер считает dpi=180, поэтому 12cm это 850px. Если повернуть телефон боком, то в горизонтальной ориентации стиль уже не применится, так как ширина экрана очевидно больше 850px.
При зумировании конечно все элементы (и заданные в сантиметрах) увеличатся, это нормально. Но я ведь речь вёл не об этом. А о том, что на мобильных устройства более высокий dpi и это можно использовать задавая ширину в cm, а не px.
fursanton1986, Обычно браузеры в смартфонах с экраном шириной 720 "реальных" пикселей используют CSS-ширину либо 360px (devicePixelRatio=2), либо 412px (devicePixelRatio=1.75), так что в любом случае стили из @media(max-width:453px) будут применены.