Comment puis-je réinitialiser l'échelle de zoom d'une application web sur un changement d'orientation sur l'iPhone?
quand je démarre mon application en mode portrait, ça marche très bien. Puis je tourne dans le paysage et il est mis à l'échelle. Pour le mettre à l'échelle correctement pour le mode paysage, je dois faire un double clic sur quelque chose deux fois, d'abord pour zoomer complètement (le comportement normal du double clic) et de nouveau pour zoomer complètement (encore une fois, le comportement normal du double clic). Quand il zoome dehors, il zoome dehors à la nouvelle échelle correcte pour le mode de paysage.
revenir au portrait semble fonctionner plus de façon constante, c'est-à-dire qu'il manipule le zoom de façon à ce que l'échelle soit correcte lorsque l'orientation retourne au portrait.
j'essaie de savoir si c'est un bug? ou si C'est quelque chose qui peut être corrigé avec JavaScript?
avec le contenu meta de viewport, je mets l'échelle initiale à 1,0 et je ne mets pas l'échelle minimale ou maximale (ce que je ne veux pas non plus). Je règle la largeur à device-width.
des idées? Je sais beaucoup de gens seraient heureux d'avoir une solution car il semble être un problème persistant.
11 réponses
Jeremy Keith ( @adactio ) a une bonne solution pour cela sur son blog Orientation et échelle
garder le balisage extensible en ne fixant pas d'échelle maximale dans le balisage.
<meta name="viewport" content="width=device-width, initial-scale=1">
puis désactiver l'évolutivité avec javascript à la charge jusqu'à gesturestart lorsque vous autorisez à nouveau l'évolutivité avec ce script:
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);
}
}
mise à Jour 22-12-2014:
Sur un iPad 1 cela ne fonctionne pas, il ne fonctionne pas sur le eventlistener. J'ai trouvé que supprimer .body
corrige que:
document.addEventListener('gesturestart', function() { /* */ });
Scott Jehl a trouvé une solution fantastique qui utilise l'accéléromètre pour anticiper les changements d'orientation. Cette solution est très réactive et n'interfère pas avec les gestes de zoom.
https://github.com/scottjehl/iOS-Orientationchange-Fix
comment ça marche: ce correctif fonctionne en écoutant les accéléromètre de prédire quand un changement d'orientation est d'environ produire. Quand il juge un changement d'orientation imminent, le script désactive l'utilisateur zoom, permettant le changement d'orientation de se produire correctement, avec zoom désactivé. Le script rétablit zoom une fois que l'appareil est soit orientée proche de la verticale, ou après son orientation a modifié. De cette façon, le zoom utilisateur n'est jamais désactivé tant que la page est dans utiliser.
Minifiés source:
/*! 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);
j'ai eu le même problème, et le réglage de l'échelle maximale=1,0 a fonctionné pour moi.
Edit: Comme indiqué dans les commentaires, cela empêche l'utilisateur de zoomer sauf lorsque le contenu dépasse la largeur-résolution. Comme mentionné, cela peut ne pas être sage. Dans certains cas, cela peut aussi être souhaitable.
de La fenêtre de code:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0;">
si vous avez la largeur définie dans le viewport:
<meta name = "viewport" content = "width=device-width; initial-scale=1.0;
maximum-scale=1.0;" />
et puis changer l'orientation qu'il va zoom au hasard dans parfois (surtout si vous faites glisser sur l'écran) pour corriger ce ne fixe pas une largeur ici, j'ai utilisé :
<meta id="viewport" name="viewport" content="initial-scale=1.0; user-scalable=0;
minimum-scale=1.0; maximum-scale=1.0" />
cela corrige le zoom quoi qu'il arrive, vous pouvez utiliser l'une ou l'autre des fenêtres.onorientationchange event ou si vous voulez qu'il soit indépendant de la plate-forme (pratique pour tester) la fenêtre .innerWidth la méthode.
MobileSafari supporte L'événement orientationchange
sur l'objet window
. Malheureusement, il ne semble pas y avoir de moyen de contrôler directement le zoom via JavaScript. Peut - être pourriez-vous écrire/changer dynamiquement la balise meta
qui contrôle le viewport-mais je doute que cela fonctionne, cela n'affecte que l'état initial de la page. Peut-être pourriez-vous utiliser cet événement pour redimensionner votre contenu en utilisant CSS. Bonne chance!
j'ai créé une démo de travail d'une mise en page Paysage/portrait mais le zoom doit être désactivé pour qu'il fonctionne sans JavaScript:
http://matthewjamestaylor.com/blog/ipad-layout-with-landscape-portrait-modes
j'ai utilisé cette fonction dans mon projet.
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;
}
il suffit de rajoutereventlistener:
if( /iPad|iPhone|iPod|Android/i.test(navigator.userAgent) ){
window.addEventListener("orientationchange", function() {
changeViewPort("maximum-scale", 1);
changeViewPort("maximum-scale", 10);
}
}
j'ai trouvé une nouvelle solution, différente de toutes celles que j'ai vues, en désactivant le zoom natif iOS, et en implémentant la fonctionnalité zoom dans JavaScript.
un excellent background sur les différentes autres solutions au problème de zoom/orientation est par Sérgio Lopes: une correction au célèbre bug iOS zoom sur le changement d'orientation passer au portrait .
<!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 /q/how-to-make-div-not-larger-than-its-contents-33139/"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>
Il pourrait être amélioré, mais pour mes besoins, il évite les inconvénients majeurs qui se produisent avec toutes les autres solutions que j'ai vu. Jusqu'à présent, je ne l'ai testé qu'avec un Safari mobile sur un iPad 2 avec iOS4.
Le focus()/blur() est une solution de contournement pour éviter les occasionnels de blocage de la fonctionnalité de zoom qui peut se produire après des changements d'orientation et de zoomer un peu de temps.
Paramétrage du document.corps.le style oblige à repeindre tout l'écran, ce qui évite des problèmes intermittents lorsque le repeindre il échoue après zoom.
Elisabeth vous pouvez changer dynamiquement le contenu de viewport en ajoutant la propriété "id" à la métabalise:
<meta name="viewport" id="view" content="user-scalable=yes, width=device-width minimum-scale=1, maximum-scale=1" />
alors vous pouvez simplement appeler par javascript:
document.getElementById("view").setAttribute('content','user-scalable=yes, width=device-width, minimum-scale=1, maximum-scale=10');
Voici une autre façon de le faire, qui semble bien fonctionner.
-
définissez la balise meta pour restreindre le viewport à scale=1, ce qui empêche le zoom:
< meta name=" viewport "content=" width = device-width, initial-scale=1, minimum-scale=1, maximum-scale = 1 " >
-
avec javascript, changez la balise meta 1/2 seconde plus tard en autoriser le zoom:
setTimeout (function () {document.querySelector ("meta[name=viewport]").setAttribute ('content', 'width=device-width, initial-scale)=1');}, 500);
-
à nouveau avec javascript, sur le changement d'orientation, rechargez la page:
de la fenêtre.onorientationchange = function () {window.emplacement.rechargement();};
chaque fois que vous réorientez l'appareil, la page se recharge, initialement sans zoom. Mais 1/2 seconde plus tard, la capacité de zoom est restaurée.
a trouvé une solution très facile à mettre en œuvre. Définissez le focus à un élément de texte qui a une taille de police de 50px à la fin du formulaire. Il ne semble pas fonctionner si l'élément de texte est caché, mais cacher cet élément est facilement fait en définissant les propriétés de couleur des éléments pour n'avoir aucune opacité.