Каков наилучший метод повторного рендеринга веб-страницы при изменении ориентации?

У меня гибкий макет CSS, который плохо отображается на iphone, когда я меняю ориентацию. (После обновления выглядит нормально).

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

var supportsOrientationChange = "onorientationchange" in window,
    orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";

window.addEventListener(orientationEvent, function() {
    window.location.reload()
}, false);   

Редактировать:

Две основные проблемы при тестировании на iphone:

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


person theorise    schedule 27.10.2011    source источник
comment
Вы уже используете медиа-запросы CSS?   -  person Pointy    schedule 27.10.2011
comment
@Pointy nope, никаких медиа-запросов. Макет страницы такой же, как по горизонтали, так и по вертикали (тот же CSS). Я обновил свой ответ, чтобы объяснить немного лучше.   -  person theorise    schedule 27.10.2011
comment
Вы делаете свою страничку только для iphone? А как насчет ipad, android, WM7 и т. Д.? Если использование браузера другой ширины / размера приводит к тому, что ваша страница плохо отображается, вам нужно посмотреть на макет.   -  person Ryan Ternier    schedule 27.10.2011
comment
@ Райан Тернье: да, все мобильные. Макет отображается нормально, если страница обновляется после изменения ориентации, поэтому это не проблема макета, проблема заключается в том, что телефон отображает страницу после изменения ориентации.   -  person theorise    schedule 27.10.2011
comment
У @theorise есть пример страницы, чтобы я мог проверить то, что вы описали?   -  person RaphaelDDL    schedule 03.11.2011
comment
Медиа-запросы CSS поддерживают ориентацию: w3.org/TR/css3-mediaqueries/#orientation < / а>   -  person Ahmed Nuaman    schedule 09.11.2011
comment
Приведенные выше изменения сценария обновляют страницу при каждом изменении размера окна даже на рабочем столе, поэтому небольшая версия ... var supportsOrientationChange = onorientationchange in window; если (supportsOrientationChange) {window.addEventListener ('изменение ориентации', функция () {window.location.reload ()}, ложь); }   -  person Simon    schedule 23.03.2012


Ответы (8)


Предполагая, что ваш CSS уже успешно отображается на экранах мобильных устройств различного размера, вам необходимо определить область просмотра в ‹head› вашего шаблона.

Например, это устанавливает ширину страницы равной ширине экрана устройства и начальному масштабированию 100%. Первоначальное масштабирование применяется при загрузке страницы, но не при изменении ориентации.

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

Добавив параметр maximum-scale = 1.0 в область просмотра, вы заставите iPad / iPhone поддерживать уровень масштабирования и изменять макет страницы при изменении ориентации. Недостатком этого является отключение масштабирования. Однако преимущество состоит в том, что вы можете вносить изменения в макет с помощью медиа-запросов, чтобы представить контент в соответствии с текущей ориентацией. Подробнее об области просмотра можно узнать здесь: Выбор ViewPort < / а>

Теперь о медиа-запросах. Вы должны помещать медиа-запросы внизу вашего CSS-файла и в порядке от наименьшей ширины до наибольшей ширины для ширины экрана. Например, взято из примера CSS Html5BoilerPlate:

@media only screen and (min-width: 480px) {
  /* Style adjustments for viewports 480px and over go here */

}

@media only screen and (min-width: 768px) {
  /* Style adjustments for viewports 768px and over go here */

}

Итак, все ваши обычные стили находятся выше этого и применяются первыми, затем, если экран 480 пикселей или шире, применяется следующий блок стилей, а затем, если экран 768 пикселей или шире, применяется последний блок стилей.

Комбинируя фиксированный уровень масштабирования до 1.0 и медиа-запросы, вы можете заставить свой сайт быстро изменять размер и ориентацию экрана без использования javascript. Очевидно, вам нужно убедиться, что сайт хорошо спроектирован, чтобы пользователям не нужно было масштабировать. Если ваш сайт оптимизирован для мобильных устройств, это не должно быть проблемой.

Обратите внимание: другие мобильные браузеры, отличные от Safari, могут изменять макет страницы без установки максимального масштаба в области просмотра. Но это поведение непоследовательно, и большинство разработчиков, похоже, обслуживают устройства Apple, даже если реализация хуже, чем у других устройств. Некоторые другие устройства будут поддерживать уровень масштабирования и повторно центрировать область просмотра при изменении ориентации. Но на всех устройствах можно установить уровень масштабирования 1.0.

person BenSwayne    schedule 04.11.2011
comment
Похоже, вы могли бы отказаться от максимального масштаба, предложенного выше, и при желании добавить в макет некоторый javascript (без перезагрузки страницы). Ознакомьтесь с другой страницей stackoverflow по управлению окном просмотра с помощью JavaScript: Управление ViewPort с помощью JavaScript - person BenSwayne; 04.11.2011
comment
Вы также можете использовать orientation:landscape и orientation:portrait медиа-запросы. - person Bob Aman; 10.11.2011
comment
@BobAman Вы правы, я думаю, что причина, по которой CSS Html5Boilerblate использует ширину экрана, заключается в кросс-платформенной поддержке, включая настольные компьютеры / ноутбуки. Например, что, если вы просто изменили размер окна браузера на настольном компьютере до портретной формы. (например: нажмите Win + Left на компьютере с Windows 7, чтобы занять половину экрана слева - обычно используется для просмотра двух приложений рядом). Но я полагаю, что вы могли бы расширить приведенные выше медиа-запросы, включив в них корректировки размеров и ориентации, если вам нужно, чтобы эти сценарии были другими. - person BenSwayne; 10.11.2011
comment
Это также проблема более широкого распространения поддержки размеров устройств. - person Bob Aman; 11.11.2011
comment
Ответ БенСуэйна: добавив параметр maximum-scale = 1.0 в область просмотра, вы заставите iPad / iPhone поддерживать уровень масштабирования и изменять макет страницы при изменении ориентации. похоже, больше не работает. Страницы не меняют макет. Изменило ли что-то обновление iOS с момента ответа на эту тему? - person Steve F; 10.11.2012
comment
Начиная с Safari 7, это больше не работает. Вот демонстрация. Чтобы убедиться, что вы видите, как это не работает, начните с iPad в альбомном режиме, загрузите страницу, а затем поверните. Обратите внимание, что страница не расширяется до полной высоты, несмотря на то, что все время используется flexbox. - person Dan Dascalescu; 11.07.2015

Обновление 2015 г.

Все остальные ответы неверны или устарели. Вот что работает:

  window.addEventListener('orientationchange', function () {
    var originalBodyStyle = getComputedStyle(document.body).getPropertyValue('display');
    document.body.style.display='none';
    setTimeout(function () {
      document.body.style.display = originalBodyStyle;
    }, 10);
  });

Код прослушивает событие смены ориентации и вызывает повторное поток элемента body, скрыв его и показывая через 10 миллисекунд. Это не зависит от каких-либо <meta> тегов или медиа-запросов.

В других ответах предлагалось использовать медиа-запросы, но вы их уже используете, поскольку вы сказали: «Все выглядит нормально, когда обновляется».

В некоторых других ответах предлагается использовать location.reload(). Это очень неэффективно, потому что при этом будет перезагружена вся страница, включая изображения и т. Д., Особенно на мобильных устройствах, вы не хотите этого делать.

В других ответах предлагалось добавить <meta name="viewport" content="width=device-width, initial-scale=1.0"> или его варианты. Начиная с Safari 7, это больше не работает. Вот демонстрация. Чтобы убедиться, что вы видите, как это не работает, начните с iPad в альбомном режиме, загрузите страницу, а затем поверните. Обратите внимание, что страница не расширяется до полной высоты, несмотря на то, что все время используется flexbox.

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

person Dan Dascalescu    schedule 11.07.2015
comment
У меня это работает прямо из коробки. Отличное решение. - person mags; 05.12.2015
comment
Хорошо, поэтому я сказал спасибо преждевременно. У меня это НЕ работает, и у меня правильно установлен метатег. Рассматриваемый div представляет собой динамически отображаемое слайд-шоу, которое создает дочерний div с абсолютным позиционированием встроенного стиля. Это какая-то сторонняя вещь, поэтому, конечно, я не могу прикоснуться к самому коду напрямую (и у меня нет возможности сказать своему работодателю, чтобы он выбросил его), так что ... бросьте мне кость, кто угодно! - person code-sushi; 04.02.2016
comment
что, если событие смены ориентации сработало дважды в течение 10 миллисекунд .. есть вероятность, что вы полностью потеряете свойство отображения тела и окончание с отображением none ... @Dan Dascalescu - person Ashish Sajwan; 18.02.2016

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

$(window).on('orientationchange', function() {
    document.body.style.display='none';
    document.body.offsetHeight; //cause a reflow
    document.body.style.display='block'; //cause a repaint
}); 

Или эквивалент не jquery

window.addEventListener('orientationchange', function () {
    document.body.style.display='none';
    document.body.offsetHeight; //cause a reflow
    document.body.style.display='block'; //cause a repaint
});
person James Westgate    schedule 22.04.2016

По моему опыту, лучше всего это сделать так

<meta name = "viewport" content = "user-scalable=no, initial-scale=1.0, maximum-scale=1.0, width=device-width /">
<meta name="apple-mobile-web-app-capable" content="yes"/>

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

person komu_Mkeya    schedule 06.02.2014
comment
Это тоже не работает. Вот демонстрация. Чтобы убедиться, что вы видите, как это не работает, начните с iPad в альбомном режиме, загрузите страницу, а затем поверните. Обратите внимание, что страница не расширяется до полной высоты, несмотря на то, что все время используется flexbox. - person Dan Dascalescu; 11.07.2015

У меня была похожая проблема, и вот как я исправил ее с помощью jQuery.

В моем случае стили не менялись правильно для моего элемента <nav>. Я использовал модифицированную версию кода kidkaos77 в сочетании с $.get(), чтобы загрузить только определенную часть страницы:

$(window).bind("resize",function() {
    //on resize reload only nav & replace
    $.get("index.php" +  ' nav', function(data) {
        $("nav").replaceWith($(data).find("nav"));
    });
});

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

person Tommy DC    schedule 16.12.2015
comment
Можно ли использовать это решение без названия страницы? Просто $ .get (this + 'div.className', function (data) ...? Если нет, то почему? - person code-sushi; 04.02.2016

Другой вариант может заключаться в добавлении и удалении классов CSS из ваших элементов html (div, var, span и т. Д.). Таким образом, вы можете изменять только те элементы, которые доставляют вам проблемы, а также вы можете настраивать контент в немобильных браузерах, если пользователь изменяет размер окна браузера.

Вот код Javascript / JQuery, который вам понадобится:

// Code to run when page has finished loading
$(function() {
    // Add CSS-class to body depending on device platform using user agent string
    // You can add more validations here and/or separate Android from iPhone or add more customized classes like "landscape_iPad", "landscape_iPhone", etc.
   // You can also validate browser types and add classes like "background_IE" or "background_Chrome", etc
    if ((navigator.userAgent.indexOf("iPad") != -1)) {
        $("#background").addClass("landscape");
    } else if ((navigator.userAgent.indexOf("Android") != -1) || (navigator.userAgent.indexOf("iPhone") != -1) || 
    (navigator.userAgent.indexOf("iPhone") != -1)) {
        $("body").addClass("iPhone");
    }

    // Get the initial orientation on iOS devices
    if (!isNaN(window.orientation)) {
        var orientation = ($(window).width() < 980) ? "portrait" : "landscape";
        // Index php
        $("#background").addClass(orientation);
    } else {
        // Choose layout depending on viewport/window width
        var orientation = ($(window).width() < 980) ? "portrait" : "landscape";
        // Index php
        $("#background").addClass(orientation);
    }

    // Bind orientationChange (or viewport/window size changes)
    if (window.onorientationchange != undefined) {
        window.onorientationchange = function() {
            var orientation = ($(window).width() < 980) ? "portrait" : "landscape";
            // Index php
            $("#background").removeClass("portrait landscape").addClass(orientation);
        }
    } else {
        // Use landscape styling if it's wider than 980 pixels. 
        // This is for non mobile browsers, this way if the user resize the browser window, content will adjust too.
        $(window).bind('resize', function(){
            var orientation = ($(window).width() < 980) ? "portrait" : "landscape";
            // Index php
            $("#background").removeClass("portrait landscape").addClass(orientation);
        });
    }
});

А вот CSS-класс для образца элемента «background»:

#background.portrait {
    position:absolute;
    top:0px;
    left:0px;
    width:768px;
    height:946px;
    z-index:0;
    background:url(background.png) top center no-repeat;
}
#background.landscape {
    position:absolute;
    top:10px;
    left:20px;
    width:1024px;
    height:724px;
    z-index:0;
    background:url(background_landscape.png) top center no-repeat;
}

Таким образом, вы можете настроить поведение в альбомной и портретной ориентации, а также добавить дополнительные классы, например: «landscape_iPhone», «portrait_Android» или что-то еще, что вам нужно, чтобы контролировать рендеринг страницы для каждого конкретного устройства.

Кроме того, вам не нужно перезагружать страницу, она настроит ее на лету.

Надеюсь, это поможет вам или кому-то еще =), это позволило мне создавать веб-сайты, настроенные для каждого размера экрана, мобильного бренда или даже типа браузера с одним и тем же HTML, но с разными классами CSS.

person Paul N    schedule 08.11.2011
comment
Я аплодирую вашему рвению, но сниффинг UserAgent становится устаревшим в пользу обнаружения функций. Вы никогда не знаете, когда выйдет на рынок следующий планшет или браузер, который может нарушить работу вашего UserAgent. Также я не вижу, что это дает, чего не делают медиа-запросы. Мы не пытаемся поддерживать IE6 для изменения ориентации, поэтому мы можем уверенно использовать соответствующую текущую технологию. IMO, JavaScript следует использовать только для устранения недостатков между браузерами, а именно разницы между обработкой области просмотра Safari в iOS и другими браузерами для планшетов. - person BenSwayne; 10.11.2011

Попробуйте что-то вроде этого:

$(function(){

    changeOrientation(window.orientation == 0 ? "portrait" : "landscape");

    $('body').bind('orientationchange',function(event){
        changeOrientation(event.orientation)
    });

    function changeOrientation(ori){
        $("#orientation").removeClass('portrait landscape');
        $("#orientation").addClass(ori);
    }     
});
person James Johnson    schedule 08.11.2011
comment
Я подозреваю, что без объяснения причин или HTML и CSS для элемента #orientation намерение идентично скрытию / отображению тела в мой ответ. - person Dan Dascalescu; 11.07.2015

$(window).bind('resize', function() { location.reload(); });

Этот код работал у меня.

person kidkaos77    schedule 30.07.2014