it-swarm.com.ru

Установка видового экрана в соответствии с шириной и шириной

Я работаю над сайтом, который подходит для определенной ширины и высоты (885x610 div с границей 1px и верхним полем 3px). Я бы хотел, чтобы пользователю никогда не приходилось прокручивать или масштабировать, чтобы увидеть весь элемент div; это всегда должно быть полностью видимым. Поскольку устройства имеют широкий спектр разрешений и соотношений сторон, идея, которая пришла в голову, заключалась в том, чтобы динамически устанавливать метатег «viewport» с помощью JavaScript. Таким образом, div всегда будет иметь одинаковые размеры, разные устройства должны будут масштабироваться по-разному, чтобы вместить весь div в их области просмотра. Я опробовал свою идею и получил странные результаты.

Следующий код работает при первой загрузке страницы (протестировано в Chrome 32.0.1700.99 на Android 4.4.0), но по мере обновления уровень масштабирования меняется. Кроме того, если я закомментирую alert, он не будет работать даже при загрузке первой страницы.

Fiddle

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0">
        <script type="text/javascript">
            function getViewportWidth() {
                if (window.innerWidth) {
                    return window.innerWidth;
                }
                else if (document.body && document.body.offsetWidth) {
                    return document.body.offsetWidth;
                }
                else {
                    return 0;
                }
            }

            function getViewportHeight() {
                if (window.innerHeight) {
                    return window.innerHeight;
                }
                else if (document.body && document.body.offsetHeight) {
                    return document.body.offsetHeight;
                }
                else {
                    return 0;
                }
            }

            if (/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)) {
                var actual_width = getViewportWidth();
                var actual_height = getViewportHeight();

                var min_width = 887;
                var min_height = 615;

                var ratio = Math.min(actual_width / min_width, actual_height / min_height);

                if (ratio < 1) {
                    document.querySelector('meta[name="viewport"]').setAttribute('content', 'initial-scale=' + ratio + ', maximum-scale=' + ratio + ', minimum-scale=' + ratio + ', user-scalable=yes, width=' + actual_width);
                }
            }

            alert(document.querySelector('meta[name="viewport"]').getAttribute('content'));
        </script>
        <title>Test</title>
        <style>
            body {
                margin: 0;
            }

            div {
                margin: 3px auto 0;
                width: 885px;
                height: 610px;
                border: 1px solid #f00;
                background-color: #fdd;
            }
        </style>
    </head>
    <body>
        <div>
            This div is 885x610 (ratio is in between 4:3 and 16:10) with a 1px border and 3px top margin, making a total of 887x615.
        </div>
    </body>
</html>

Что я могу сделать, чтобы масштаб этого веб-сайта соответствовал ширине и высоте?

10
Nick

Можно получить последовательное поведение. Но это, к сожалению, очень сложно. Я работаю над сценарием, который обнаруживает поддельные агенты и динамически масштабирует область просмотра соответственно на рабочий стол или других поддельных агентов. Я также столкнулся с проблемой масштабирования в Android/Chrome, а также в эмуляторе iOS ...

Чтобы обойти это, вам нужно отключить масштабирование и/или установить область просмотра дважды. На первом проходе, желательно встроенном в <head>, как вы делаете сейчас, вы устанавливаете масштаб и временно отключаете пользовательское масштабирование, чтобы предотвратить проблему масштабирования, используя одинаковое фиксированное значение для всех 3 масштабов, например:

document.querySelector('meta[name=viewport]').setAttribute('content', 'width='+width+',minimum-scale='+scale+',maximum-scale='+scale+',initial-scale='+scale);

Затем, чтобы восстановить масштабирование, вы снова устанавливаете область просмотра на DOMContentLoaded с тем же масштабом, за исключением того, что на этот раз вы устанавливаете нормальные значения минимального/максимального масштаба для восстановления пользовательского масштабирования:

document.querySelector('meta[name=viewport]').setAttribute('content', 'width='+width+',minimum-scale=0,maximum-scale=10');

В вашем контексте, поскольку макет фиксирован и больше, чем область просмотра, initial-scale='+scale, возможно, необходим для более надежной альтернативы DOMContentLoaded:

document.querySelector('meta[name=viewport]').setAttribute('content', 'width='+width+',minimum-scale=0,maximum-scale=10,initial-scale='+scale);

Это должно привести к изменению масштаба области просмотра, как вы хотели бы в браузерах Webkit, без проблем с масштабированием. Я говорю только в webkit, потому что, к сожалению, IE и Firefox не поддерживают изменение области просмотра в соответствии с этой таблицей совместимости браузера для видов, экранов и размеров пикселов устройств: http://www.quirksmode.org/mobile/ tableViewport.html

В IE есть собственный способ динамического изменения области просмотра, который действительно необходим для адаптивных режимов привязки IE . http://timkadlec.com/2012/10/ie10-snap-mode-and -ответ-дизайн/

Поэтому для IEMobile и IE SnapMode (IE10 и 11) вам нужно динамически вставить встроенный <style> в <head> с чем-то вроде.

<script>
 var s = document.createElement('style');
 s.appendChild(document.createTextNode('@-ms-viewport{width:'+width+'px')+';}'));
 document.head.appendChild(s);
</script>

И, к сожалению, Firefox не имеет ни того, ни другого: область просмотра устанавливается раз и навсегда, как показано в приведенной выше таблице совместимости. На данный момент, из-за отсутствия других методов, использование CSS Transform (как указал @imcg) является единственным способом изменить область просмотра в FireFox Mobile на Android или ОС Gecko. Я только что протестировал его, и он работает в контексте дизайна фиксированного размера. (В «Responsive Design context» макет может быть изменен с помощью CSS Transform, например, при размере рабочего стола на телефоне, но Firefox по-прежнему считывает MQ размера телефона. Так что об этом следует помнить в контексте RWD./Помимо webkit )

Тем не менее, я заметил несколько случайных сбоев Webkit с CSSTransform на Android, поэтому я рекомендую метод просмотра для Safari/Chrome/Opera как более надежный.

Кроме того, для того, чтобы получить межбраузерную надежность для ширины области просмотра, вы также должны столкнуться/исправить общее несоответствие между браузерами для innerWidth (обратите внимание, что documentElement.clientWidth гораздо надежнее, чтобы получить точную ширину пикселя макета по сравнению с innerWidth), и вы Также необходимо учитывать расхождения devicePixelRatio, как указано в таблице quirksmode.org.

Обновление: На самом деле, после некоторого размышления над решением моей собственной проблемы с Firefox, я только что нашел способ переопределить область просмотра в Firefox Mobile, используя document.write(), примененную только один раз:

document.write('<meta name="viewport" content="width='+width+'px,initial-scale='+scale+'">');

Только что успешно протестировал это в Webkit и Firefox без проблем с масштабированием. Я не могу проверить на Windows Phone, поэтому я не уверен, что itf document.write работает на IEMobile ...

8
hexalys

Я знаю, что это на два года позже, но я потратил много времени, работая над этой проблемой, и хотел бы поделиться своим решением. Исходный вопрос мне показался очень полезным, поэтому я чувствую, что отправка этого ответа - мой способ ответить. Мое решение работает на iPhone6 ​​и 7 "Galaxy Tab. Я не знаю, как оно работает на других устройствах, но я предполагаю, что оно должно в основном вести себя.

Я разделил логику области просмотра во внешний файл, чтобы его можно было легко использовать Во-первых, вот как вы будете использовать код:

<HTML>
<HEAD>    
  <SCRIPT type="text/javascript" src="AutoViewport.js"></SCRIPT>
</HEAD>
<BODY>
  <SCRIPT>
  AutoViewport.setDimensions(yourNeededWidth, yourNeededHeight);
  </SCRIPT>
  <!-- The rest of your HTML goes here -->
</BODY>
</HTML>

На самом деле, я немного увеличил желаемую ширину и высоту (15 пикселей или около того), чтобы намеченный дисплей был хорошо оформлен. Также обратите внимание, что из кода использования вам не нужно указывать тег viewport в вашем HTML. Моя библиотека автоматически создаст ее для вас, если она еще не существует . Вот AutoViewport.js:

/** Steven Yang, July 2016
Based on http://stackoverflow.com/questions/21419404/setting-the-viewport-to-scale-to-fit-both-width-and-height , this Javascript code allows you to 
cause the viewport to auto-adjust based on a desired pixel width and height
that must be visible on the screen.

This code has been tested on an iPhone6 and a 7" Samsung Galaxy Tab.
In my case, I have a game with the exact dimensions of 990 x 660.  This
script allows me to make the game render within the screen, regardless 
of whether you are in landscape or portrait mode, and it works even
when you hit refresh or rotate your device.

Please use this code freely.  Credit is appreciated, but not required!
*/

function AutoViewport() {}

AutoViewport.setDimensions = function(requiredWidth, requiredHeight) {

/* Conditionally adds a default viewport tag if it does not already exist. */
var insertViewport = function () {

  // do not create if viewport tag already exists
  if (document.querySelector('meta[name="viewport"]'))
    return;

  var viewPortTag=document.createElement('meta');
  viewPortTag.id="viewport";
  viewPortTag.name = "viewport";
  viewPortTag.content = "width=max-device-width, height=max-device-height,initial-scale=1.0";
  document.getElementsByTagName('head')[0].appendChild(viewPortTag);
};

var isPortraitOrientation = function() {
  switch(window.orientation) {  
  case -90:
  case 90:
  return false;
  }

  return true;
 };

var getDisplayWidth = function() {
  if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {
    if (isPortraitOrientation())
      return screen.width;
    else
      return screen.height;
  }

  return screen.width;
}

var getDisplayHeight = function() {
  if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {
    if (isPortraitOrientation())
      return screen.height;
    else
      return screen.width;
  }

  // I subtract 180 here to compensate for the address bar.  This is imperfect, but seems to work for my Android tablet using Chrome.
  return screen.height - 180;
}

var adjustViewport = function(requiredWidth, requiredHeight) {

  if (/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)){

    var actual_height = getDisplayHeight();
    var actual_width = getDisplayWidth();

    var min_width = requiredWidth;
    var min_height = requiredHeight;

    var ratio = Math.min(actual_width / min_width, actual_height / min_height);

    document.querySelector('meta[name="viewport"]').setAttribute('content', 'initial-scale=' + ratio + ', maximum-scale=' + ratio + ', minimum-scale=' + ratio + ', user-scalable=yes, width=' + actual_width);
}    
};

  insertViewport();
  adjustViewport(requiredWidth, requiredHeight);
  window.addEventListener('orientationchange', function() {
    adjustViewport(requiredWidth, requiredHeight);      
  });
};

Если вы сравните мой код с исходным кодом, найденным в вопросе, вы заметите несколько различий. Например, я никогда не полагаюсь на ширину или высоту области просмотра. Вместо этого я полагаюсь на экранный объект. Это важно, потому что при обновлении страницы или повороте экрана ширина и высота области просмотра могут изменяться, но screen.width и screen.height никогда не изменяются. Следующее, что вы заметите, это то, что я не делаю проверку (отношение <1). При обновлении или повороте экрана эта проверка вызывала несоответствие, поэтому я удалил ее. Также я включил обработчик для поворота экрана. 

Наконец, я просто хотел бы поблагодарить человека, который создал этот вопрос для того, чтобы заложить основу, что сэкономило мне время!

4
Steven

Замените ваш видовой экран следующим:

<META NAME="viewport" CONTENT="width=device-width, height=device-height, initial-scale=1, user-scalable=no"/>

User-scalable = 0 здесь сделает всю работу за вас.

Это будет работать для вас. Если это все еще не работает, нам придется расширить область просмотра, поэтому замените вашу область просмотра и добавьте это: 

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, target-densitydpi=medium-dpi, user-scalable=0" />

Для вашей ошибки JavaScript взгляните на эту ссылку:

масштабировать мобильный веб-контент, используя метатег viewport

3
user3274745

Если вы не можете получить согласованное поведение на разных устройствах, изменив метатег области просмотра, можно увеличить масштаб без изменения размеров с помощью преобразований CSS3:

if (ratio < 1) {
    var box = document.getElementsByTagName('div')[0];
    box.style.webkitTransform = 'scale('+ratio+')';
    box.style.webkitTransformOrigin = '0 0';
}

console.log(box.offsetWidth); // always original width
console.log(box.getBoundingClientRect().width); // new width with scaling applied

Заметьте, что я упустил здесь любые префиксы поставщиков, кроме webkit, чтобы упростить его.

Чтобы центрировать масштабированный div, вы можете использовать translate transforms:

var x = (actual_width - min_width * ratio) / 2;
var y = (actual_height - min_height * ratio) / 2;
box.style.webkitTransform = 'translateX('+x+'px) translateY('+y+'px) scale('+ratio+')';
box.style.webkitTransformOrigin = '0 0';
2
imcg

Я думаю, что Стивен должен быть принятым ответом.

В случае, если это кому-то пригодится, я бы добавил следующие 2 вещи в AutoViewport.js Стивена, чтобы центрировать вид в области просмотра, когда пользователь находится в альбомной ориентации: 

Добавьте "var viewport_margin = 0;" как первая строка кода (как собственная строка перед «function AutoViewport () {}».

Добавьте "viewport_margin = Math.abs (actual_width- (ratio * requiredWidth))/(actual_width * 2) * 100;" после строки, которая читает «document.querySelector ('meta [name =" viewport "]'). setAttribute ('content', 'initial-scale =' + ratio + ', Maximum-scale =' + ratio + ', минимум -scale = '+ ratio +', масштабируемый пользователем = yes, width = '+ actual_width); "

Спасибо всем, кто опубликовал это решение.

ОБНОВЛЕНИЕ: В Android мои дополнения работают только с API 24+. Не уверен, почему они не работают с API 19-23. Есть идеи?

0
Strongdog

Установите высоту и ширину родительских элементов div (html и body) на 100% и обнулите поле.

html, body {
  margin: 0;
  height: 100%;
  width: 100%;
}

Далее, поскольку вам нужна граница для div, вы должны убедиться, что ширина границы включена, когда вы указываете ширину/высоту элемента, для этого используйте box-sizing: border-box в div.

Потому что вы хотите, чтобы верхнее поле в 3px относительного расположения div приводило к высоте, которая на 3px слишком высока. Чтобы исправить это, используйте абсолютное позиционирование на div и установите top, left и bottom в 0.

div {
  position: absolute;
  top: 3px;
  left: 0;
  bottom: 0;
  box-sizing: border-box;
  width: 100%;
  border: 1px solid #f00;
  background-color: #fdd;
}

Вот рабочий пример .

ОБНОВЛЕНИЕ: Я думаю, что я неправильно понял вопрос. Вот пример кода, который регулирует «зум» в зависимости от области просмотра устройства

http://jpanagsagan.com/viewport/index2.html

Обратите внимание, что я использовал jquery для добавления метатега, так как у меня возникли проблемы с использованием Vanilla append.

Одна вещь, которую я заметил, это то, что если вы жестко запрограммировали HTML и изменили его с помощью JS, в документе не будет применено исправление (требуется проверка). Я смог изменить его с помощью JS, если в HTML нет предыдущего тега, поэтому я использовал append.

Вы можете поиграть с соотношением, но в примере я использовал ширину области просмотра, деленную на ширину div. 

надеюсь это поможет.

0
Scott Bartell

ОБНОВЛЕНИЕ: Я думаю, что я неправильно понял вопрос. Вот пример кода, который регулирует «зум» в зависимости от области просмотра устройства

http://jpanagsagan.com/viewport/index2.html

Обратите внимание, что я использовал jquery для добавления метатега, так как у меня возникли проблемы с использованием Vanilla append.

Одна вещь, которую я заметил, это то, что если вы жестко запрограммировали HTML и изменили его с помощью JS, в документе не будет применено исправление (требуется проверка). Я смог изменить его с помощью JS, если в HTML нет предыдущего тега, поэтому я использовал append.

Вы можете поиграть с соотношением, но в примере я использовал ширину области просмотра, деленную на ширину div. 

надеюсь это поможет.

0
Dan1121