Як скинути масштаб / масштаб веб-програми при зміні орієнтації на iPhone?


96

Коли я запускаю програму в портретному режимі, вона працює нормально. Потім я обертаюся в пейзаж, і він масштабується. Щоб отримати правильний масштаб для альбомного режиму, мені потрібно двічі натиснути на щось двічі, спочатку, щоб повністю збільшити масштаб (нормальна поведінка подвійного натискання) і знову, щоб повністю зменшити масштаб (знову ж таки, нормальна поведінка подвійного натискання) . Коли воно зменшується, воно зменшується до правильного НОВОГО масштабу для альбомного режиму.

Перехід до портретного режиму, здається, працює більш послідовно; тобто він обробляє масштабування, щоб масштаб був правильним, коли орієнтація змінюється на портретну.

Я намагаюся зрозуміти, чи це помилка? або якщо це щось, що можна виправити за допомогою JavaScript?

З мета-вмістом області перегляду я встановлюю початковий масштаб на 1,0 і НЕ встановлюю мінімальний або максимальний масштаб (а також не хочу). Я встановлюю ширину на ширину пристрою.

Якісь ідеї? Я знаю, що багато людей будуть вдячні за рішення, оскільки це, здається, є постійною проблемою.


1
Ідеальне рішення: відсутність JavaScript! stackoverflow.com/a/8727440/805787
Стівен

Відповіді:


89

Джеремі Кіт ( @adactio ) має хороше рішення для цього у своєму блозі Орієнтація та масштаб

Зберігайте масштабованість розмітки, не встановлюючи максимальної шкали розмітки.

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

Потім вимкніть масштабованість за допомогою JavaScript під час завантаження до запуску жестів, коли ви знову дозволите масштабованість за допомогою цього сценарію:

if (navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i)) {
    var viewportmeta = document.querySelector('meta[name="viewport"]');
    if (viewportmeta) {
        viewportmeta.content = 'width=device-width, minimum-scale=1.0, maximum-scale=1.0, initial-scale=1.0';
        document.body.addEventListener('gesturestart', function () {
            viewportmeta.content = 'width=device-width, minimum-scale=0.25, maximum-scale=1.6';
        }, false);
    }
}

Оновлення 22-12-2014:
На iPad 1 це не працює, він не працює на списку подій. Я виявив, що видалення .bodyвиправлень, які:

document.addEventListener('gesturestart', function() { /* */ });

4
Напевно, це краще, ніж вимкнути масштабування ?! Найкраще виправлення, яке я знайшов ще :)
danwellman

Хм, це все ще відключає можливість масштабування. Хтось має просте рішення, яке цього не робить?
Бред Свердфегер

Це працює, однак я помітив, що проблема починається знову, якщо я використовую жест масштабування, а потім обертаю екран. Не знаю, як це виправити.
Нілеш

3
Це працює. Однак я помітив, що користувачеві потрібно два рази відкрити, щоб збільшити масштаб. Я здогадуюсь, це тому, що maximum-scale=1.0залишається в силі після початку жесту. Чи є спосіб виправити це?
LandonSchropp,

3
Це не працює з 2 причин: 1) він вимикає запуск жестів номер 1, в результаті чого користувачеві потрібно робити жести двічі. 2) він ламається після того, як користувач подвоює перший жест, тому він справді працює лише в тому випадку, якщо користувач взагалі ніколи не жестикулює. - всі повинні поглянути на рішення Ендрю Ешбахера нижче. Це справді працює.
tmsimont

18

Скотт Джел придумав фантастичне рішення, яке використовує акселерометр для передбачення змін орієнтації. Це рішення дуже чуйне і не заважає жестам масштабування.

https://github.com/scottjehl/iOS-Orientationchange-Fix

Як це працює. Це виправлення працює, прослуховуючи акселерометр пристрою, щоб передбачити, коли ось-ось відбудеться зміна орієнтації. Коли він вважає, що зміна орієнтації неминуча, сценарій відключає масштабування користувача, дозволяючи правильній зміні орієнтації, а масштабування вимкнено. Сценарій знову відновлює масштабування, коли пристрій орієнтований близько до вертикалі, або після зміни орієнтації. Таким чином, масштабування користувача ніколи не вимикається, поки сторінка використовується.

Зменшене джерело:

/*! A fix for the iOS orientationchange zoom bug. Script by @scottjehl, rebound by @wilto.MIT License.*/(function(m){if(!(/iPhone|iPad|iPod/.test(navigator.platform)&&navigator.userAgent.indexOf("AppleWebKit")>-1)){return}var l=m.document;if(!l.querySelector){return}var n=l.querySelector("meta[name=viewport]"),a=n&&n.getAttribute("content"),k=a+",maximum-scale=1",d=a+",maximum-scale=10",g=true,j,i,h,c;if(!n){return}function f(){n.setAttribute("content",d);g=true}function b(){n.setAttribute("content",k);g=false}function e(o){c=o.accelerationIncludingGravity;j=Math.abs(c.x);i=Math.abs(c.y);h=Math.abs(c.z);if(!m.orientation&&(j>7||((h>6&&i<8||h<8&&i>6)&&j>5))){if(g){b()}}else{if(!g){f()}}}m.addEventListener("orientationchange",f,false);m.addEventListener("devicemotion",e,false)})(this);

Приємно! Виглядає елегантним рішенням.
Елізабет

1
це повинна бути прийнята відповідь !!!! Мені б хотілося, щоб я це вперше побачив, перш ніж витрачати годину на рішення вище :)
tmsimont

1
після подальшого тестування це свого роду ненадійне рішення :( воно суперечливе, і після перегляду коду я бачу, чому ... визначений "поріг" руху не завжди досягається, особливо якщо ви тримаєте ipad на кут під час обертання
tmsimont

Це може мати неприємні наслідки для тих, хто використовує блокування повороту ... вони можуть тримати телефон під певним кутом і втрачати можливість масштабування - користувач не здогадується, чому
1owk3y

14

У мене була та ж проблема, і встановлення максимального масштабу = 1,0 працювало для мене.

Редагувати: Як згадувалось у коментарях, це вимикає масштабування користувача, за винятком випадків, коли вміст перевищує роздільну здатність. Як уже зазначалося, це може бути не розумно. Це також може бути бажаним у деяких випадках.

Код області перегляду:

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

Гарне рішення. Хороша робота, підтримуючи сторінку на постійному рівні масштабування (відносно ширини пристрою) через зміни орієнтації. Дякуємо, що поділилися цим!
Люк Стівенсон,

17
недоліком є ​​те, що користувачі з обмеженими можливостями не можуть збільшувати ваш сайт!
Джес Джейкобс,

Я помітив, що всі ці методи заважають CSS на основі медіа-запитів правильно реєструвати нову ширину пристрою (наприклад: @media all та (max-width: 479px)
mheavers

2
вбити масштабування користувача - дуже погана ідея див. рішення Ендрю Ешбахера нижче
tmsimont

Не впевнений у iPhone, але на iPad це не вирішує проблему, це просто перешкоджає користувачеві мати можливість зменшувати масштаб вручну, коли браузер збільшує зміну орієнтації.
Alejo

3

Якщо у вікні перегляду встановлена ​​ширина:

<meta name = "viewport" content = "width=device-width; initial-scale=1.0;
 maximum-scale=1.0;" />

А потім змініть орієнтацію, яку іноді буде довільно збільшувати (особливо якщо ви перетягуєте по екрану), щоб виправити це, не встановлюйте тут ширину:

<meta id="viewport" name="viewport" content="initial-scale=1.0; user-scalable=0;
minimum-scale=1.0; maximum-scale=1.0" />

Це виправляє масштабування, що б не сталося, тоді ви можете використовувати або подію window.onorientationchange, або якщо ви хочете, щоб вона була незалежною від платформи (зручна для тестування) метод window.innerWidth .


1

MobileSafari підтримує orientationchangeподію на windowоб'єкті. На жаль, не існує способу безпосереднього управління масштабуванням за допомогою JavaScript. Можливо, ви могли б динамічно писати / змінювати metaтег, який контролює область перегляду - але я сумніваюся, що це спрацює, це впливає лише на початковий стан сторінки. Можливо, ви можете використати цю подію, щоб фактично змінити розмір вмісту за допомогою CSS. Удачі!


3
Дякую! Так, я спробував динамічно змінити значення області перегляду мета-тегу, і це нічого не зробило. Мені здається, що якщо ви повернетесь у альбомну орієнтацію, ви хочете, щоб вона правильно масштабувалась, щоб зберегти масштаб, щоб сторінка вмістилася у вікно Safari. Мені здається дуже дивним, що це не поведінка за замовчуванням!
Елізабет


1

Я використовував цю функцію у своєму проекті.

function changeViewPort(key, val) {
    var reg = new RegExp(key, "i"), oldval = document.querySelector('meta[name="viewport"]').content;
    var newval = reg.test(oldval) ? oldval.split(/,\s*/).map(function(v){ return reg.test(v) ? key+"="+val : v; }).join(", ") : oldval+= ", "+key+"="+val ;
    document.querySelector('meta[name="viewport"]').content = newval;
}

так що просто addEventListener:

if( /iPad|iPhone|iPod|Android/i.test(navigator.userAgent) ){
    window.addEventListener("orientationchange", function() { 
        changeViewPort("maximum-scale", 1);
        changeViewPort("maximum-scale", 10);
    }
}

0

Я знайшов нове вирішення проблеми, відмінне від будь-якого іншого, яке я бачив, вимкнувши власне масштабування iOS і замість цього застосувавши функцію масштабування в JavaScript.

Чудовим фоном для різних інших рішень проблеми масштабування / орієнтації є Сергіо Лопес: виправлення відомої помилки масштабування iOS при зміні орієнтації на портретну .

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" id="viewport" content="user-scalable=no,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0" />
    <title>Robocat mobile Safari zoom fix</title>
    <style>
        body {
            padding: 0;
            margin: 0;
        }
        #container {
            -webkit-transform-origin: 0px 0px;
            -webkit-transform: scale3d(1,1,1);
            /* shrink-to-fit needed so can measure width of container http://stackoverflow.com/questions/450903/make-css-div-width-equal-to-contents */
            display: inline-block;
            *display: inline;
            *zoom: 1;
        }
        #zoomfix {
            opacity: 0;
            position: absolute;
            z-index: -1;
            top: 0;
            left: 0;
        }
    </style>
</head>

<body>
    <input id="zoomfix" disabled="1" tabIndex="-1">
    <div id="container">
        <style>
            table {
                counter-reset: row cell;
                background-image: url(http://upload.wikimedia.org/wikipedia/commons/3/38/JPEG_example_JPG_RIP_010.jpg);
            }
            tr {
                counter-increment: row;
            }
            td:before {
                counter-increment: cell;
                color: white;
                font-weight: bold;
                content: "row" counter(row) ".cell" counter(cell);
            }
        </style>
        <table cellspacing="10">
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
            <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td>
        </table>
    </div>

    <script>
    (function() {
        var viewportScale = 1;
        var container = document.getElementById('container');
        var scale, originX, originY, relativeOriginX, relativeOriginY, windowW, windowH, containerW, containerH, resizeTimer, activeElement;
        document.addEventListener('gesturestart', function(event) {
            scale = null;
            originX = event.pageX;
            originY = event.pageY;
            relativeOriginX = (originX - window.pageXOffset) / window.innerWidth;
            relativeOriginY = (originY - window.pageYOffset) / window.innerHeight;
            windowW = window.innerWidth;
            windowH = window.innerHeight;
            containerW = container.offsetWidth;
            containerH = container.offsetHeight;
        });
        document.addEventListener('gesturechange', function(event) {
            event.preventDefault();
            if (originX && originY && event.scale && event.pageX && event.pageY) {
                scale = event.scale;
                var newWindowW = windowW / scale;
                if (newWindowW > containerW) {
                    scale = windowW / containerW;
                }
                var newWindowH = windowH / scale;
                if (newWindowH > containerH) {
                    scale = windowH / containerH;
                }
                if (viewportScale * scale < 0.1) {
                    scale = 0.1/viewportScale;
                }
                if (viewportScale * scale > 10) {
                    scale = 10/viewportScale;
                }
                container.style.WebkitTransformOrigin = originX + 'px ' + originY + 'px';
                container.style.WebkitTransform = 'scale3d(' + scale + ',' + scale + ',1)';
            }
        });
        document.addEventListener('gestureend', function() {
            if (scale && (scale < 0.95 || scale > 1.05)) {
                viewportScale *= scale;
                scale = null;
                container.style.WebkitTransform = '';
                container.style.WebkitTransformOrigin = '';
                document.getElementById('viewport').setAttribute('content', 'user-scalable=no,initial-scale=' + viewportScale + ',minimum-scale=' + viewportScale + ',maximum-scale=' + viewportScale);
                document.body.style.WebkitTransform = 'scale3d(1,1,1)';
                // Without zoomfix focus, after changing orientation and zoom a few times, the iOS viewport scale functionality sometimes locks up (and completely stops working).
                // The reason I thought this hack would work is because showing the keyboard is the only way to affect the viewport sizing, which forces the viewport to resize (even though the keyboard doesn't actually get time to open!).
                // Also discovered another amazing side effect: if you have no meta viewport element, and focus()/blur() in gestureend, zoom is disabled!! Wow!
                var zoomfix = document.getElementById('zoomfix');
                zoomfix.disabled = false;
                zoomfix.focus();
                zoomfix.blur();
                setTimeout(function() {
                    zoomfix.disabled = true;
                    window.scrollTo(originX - relativeOriginX * window.innerWidth, originY - relativeOriginY * window.innerHeight);
                    // This forces a repaint. repaint *intermittently* fails to redraw correctly, and this fixes the problem.
                    document.body.style.WebkitTransform = '';
                }, 0);
            }
        });
    })();
    </script>
</body>
</html>

Її можна було б вдосконалити, але для моїх потреб вона дозволяє уникнути основних недоліків, які виникають з усіма іншими рішеннями, які я бачив. Наразі я протестував його лише за допомогою мобільного Safari на iPad 2 з iOS4.

Фокус () / розмиття () - це обхідний спосіб, щоб запобігти випадковому блокуванню функцій масштабування, яке може статися після зміни орієнтації та масштабування кілька разів.

Встановлення документа.


0

Елізабет, ти можеш динамічно змінювати вміст області перегляду, додаючи властивість "id" до метатегу:

<meta name="viewport" id="view" content="user-scalable=yes, width=device-width minimum-scale=1, maximum-scale=1" />

Тоді ви можете просто зателефонувати за допомогою javascript:

document.getElementById("view").setAttribute('content','user-scalable=yes, width=device-width, minimum-scale=1, maximum-scale=10');

@bridgestew, якщо ви хочете динамічно змінити масштаб або область перегляду, використовуйте прокручування підпрогляду, що міститься в uiwebview. Я додав зразок сніпету до іншої теми: посилання
M Penades

4
@Elisabeth це працює для вас? Це не скидає масштабування при перемиканні в альбомному режимі для мене.
екземпляр мене

0

Ось ще один спосіб зробити це, який, здається, працює добре.

  1. Встановіть мета-тег для обмеження області перегляду масштабу = 1, що перешкоджає масштабуванню:

    <meta name = "viewport" content = "width = пристрій-ширина, початковий-масштаб = 1, мінімальний-масштаб = 1, максимальний-масштаб = 1">

  2. За допомогою JavaScript змініть метатег на 1/2 секунди пізніше, щоб дозволити масштабування:

    setTimeout (function () {document.querySelector ("meta [name = viewport]"). setAttribute ('вміст', 'ширина = ширина пристрою, початкова шкала = 1');}, 500);

  3. Знову з javascript, при зміні орієнтації перезавантажте сторінку:

    window.onorientationchange = function () {window.location.reload ();};

Щоразу, коли ви переорієнтуєте пристрій, сторінка перезавантажується, спочатку без збільшення. Але через 1/2 секунди можливість збільшення збільшується.


6
Відповісти на питання через 5 років після того, як його задали, це щось ... На жаль, це не так, як працює Інтернет у 2015 році. Ви НЕ ПОВТОРЮЄТЕ сторінку, коли користувач обертає свій пристрій.
П’єр,

0

Знайдено дуже легко реалізоване виправлення. Встановіть фокус на текстовий елемент із розміром шрифту 50 пікселів після заповнення форми. Здається, це не працює, якщо текстовий елемент прихований, але приховування цього елемента легко зробити, встановивши властивості кольорів елементів, щоб не було прозорості.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.