85 votes

CSS Media Query - Le clavier souple enfreint les règles d'orientation CSS - une autre solution ?

Je travaille avec plusieurs tablettes, Android et autres. et iOS . Actuellement, j'ai les variations de résolution suivantes pour toutes les tablettes.

  • 1280 x 800
  • 1280 x 768
  • 1024 x 768 (iPad évidemment) - L'iPad n'a pas ce problème

La façon la plus simple d'appliquer un style basé sur l'orientation du dispositif est d'utiliser l'orientation de la requête média en utilisant la syntaxe suivante.

@media all and (orientation:portrait)
{
  /* My portrait based CSS here */
}

@media all and (orientation:landscape)
{
  /* My landscape based CSS here */
}

Cela fonctionne parfaitement bien sur toutes les tablettes. MAIS Le problème est que, lorsque l'appareil est en mode portrait et que l'utilisateur tape sur un champ de saisie (par exemple, une recherche), le clavier virtuel s'affiche, ce qui réduit la zone visible de la page Web et la force à s'afficher en mode paysage. Sur les tablettes Android, cela dépend de la hauteur du clavier. En fin de compte, la page Web semble cassée. Par conséquent, je ne peux pas utiliser la requête de média d'orientation de CSS3 pour appliquer des styles basés sur l'orientation (à moins qu'il existe une meilleure requête de média pour cibler l'orientation). Voici une astuce http://jsfiddle.net/hossain/S5nYP/5/ qui émule ceci - pour les tests de dispositifs, utilisez la page de test complète. http://jsfiddle.net/S5nYP/embedded/result/

Voici une capture d'écran du comportement tirée de la page de démonstration. enter image description here

Je suis ouvert à une solution basée sur JavaScript si la solution native basée sur CSS ne fonctionne pas.

J'ai trouvé un extrait sur http://davidbcalhoun.com/2010/dealing-with-device-orientation qui suggère d'ajouter la classe et de cibler en fonction de cela. Par exemple :

<html class="landscape">
  <body>
    <h1 class="landscape-only">Element Heading - Landscape</h1>
    <h1 class="portrait-only">Element Heading - Portrait</h1>
    <!-- .... more... ->

# CSS
.landscape .landscape-only { display:block; }
.landspace .portrait-only  { display:none; }
.portrait .portrait-only   { display:block; }
.portrait .landscape-only  { display:none; }

Qu'est-ce que vous en pensez ? Avez-vous une meilleure solution ?

0 votes

Je viens de le découvrir, iPad hace PAS ont ce problème. SEUL le système d'exploitation Android (tablettes Honeycomb) et les mobiles ont ce problème.

0 votes

J'ai rencontré un problème similaire avec mon site Web mobile. Après avoir testé plusieurs appareils Android, il ne semble pas être limité à un système d'exploitation spécifique ou à un appareil mobile/tablette. Il semble que ce soit principalement un problème avec les appareils Motorola et Samsung. Je n'ai pas été en mesure de reproduire le problème sur notre téléphone HTC.

1 votes

Ce problème se pose principalement avec les appareils Android, mobiles/tablettes - la seule façon de le reproduire est d'installer un clavier personnalisé qui a une grande hauteur, de sorte que, lorsque le clavier est affiché, la hauteur disponible pour le webview est inférieure à la largeur disponible. Ce n'est qu'à ce moment-là que le webview déclenche le changement d'orientation. Par exemple, dans la capture d'écran, si je peux désactiver la couche de suggestion au-dessus du clavier, alors ce problème ne se posera pas, car la hauteur du webview sera supérieure à la largeur. Mais, de toute façon, je n'ai pas encore trouvé de solution élégante et efficace.

27voto

scurker Points 2440

Le problème réside dans la manière dont l'orientation est calculée :

http://www.w3.org/TR/css3-mediaqueries/#orientation

L'élément de média "orientation" est "portrait" lorsque la valeur de l'élément de média "hauteur" est supérieure ou égale à la valeur de l'élément de média "largeur". Sinon, l'"orientation" est "paysage".

Étant donné que la hauteur/largeur est calculée sur la fenêtre d'affichage visible, le clavier souple provoque apparemment une inversion de l'orientation, car la largeur de la fenêtre d'affichage est inférieure à la hauteur. Une solution consisterait à utiliser vos requêtes médias en se basant uniquement sur les éléments suivants width à la place. Cela permet une plus grande souplesse sur les appareils, quelle que soit l'orientation, sans compter que le rapport largeur/hauteur est plus largement pris en charge que l'orientation.

Si vous voulez tenir compte de la largeur au lieu de l'orientation, je vais utiliser l'iPhone comme exemple :

@media screen and (max-width: 320px) {
  /* rules applying to portrait */
}

@media screen and (max-width: 480px) {
  /* rules applying to landscape */
}

Cette approche est plus flexible que l'orientation puisque les requêtes ne sont pas limitées aux appareils/agents utilisateurs qui supportent l'orientation, sans compter que l'orientation vous dit très peu de choses par rapport à la largeur.

Bien sûr, si vous vraiment doivent connaître l'orientation, il semble que définir la classe initialement et l'utiliser simplement soit la meilleure option.

1 votes

Je comprends comment le paysage et le portrait sont calculés par les navigateurs. Mais, j'ai besoin d'une alternative et d'une meilleure façon de gérer cela. Une autre chose intéressante est que l'iPad ne déclenche pas de changement d'orientation lorsque le clavier est relevé. Je ne sais pas pourquoi **** Android a dû mettre en œuvre cette méthode.

0 votes

Je suis simplement curieux de savoir pourquoi vous avez spécifiquement besoin de l'orientation de l'appareil plutôt que de sa largeur. Quel est le problème que vous essayez de résoudre et que la largeur seule ne peut résoudre ?

0 votes

Je travaille avec plusieurs appareils ayant des résolutions différentes. Pourriez-vous donner un exemple de la façon dont la largeur peut être utilisée comme alternative à l'orientation ? En ce qui concerne l'utilisation du changement d'orientation, il existe de nombreuses applications pour ce changement - l'espace disponible est généralement différent selon l'orientation. Ainsi, certains éléments peuvent être cachés ou redimensionnés en fonction de l'orientation. Merci pour votre aide.

6voto

Robby Jennings Points 91

J'ai examiné les options énumérées ci-dessus, mais aucune ne m'a permis de résoudre le problème. Je suis passé à l'utilisation de screen.availHeight qui donne des résultats cohérents en termes de hauteur, évitant ainsi le problème d'affichage du clavier.

// Avoiding the keyboard in Android causing the portrait orientation to change to landscape. 
// Not an issue in IOS. Can use window.orientation.
var currentOrientation = function() {
  // Use screen.availHeight as screen height doesn't change when keyboard displays.  
  if(screen.availHeight > screen.availWidth){
    $("html").addClass('portrait').removeClass('landscape'); 
  } else {
    $("html").addClass('landscape').removeClass('portrait'); 
  }
}

// Set orientation on initiliasation
currentOrientation();
// Reset orientation each time window is resized. Keyboard opening, or change in orientation triggers this.
$(window).on("resize", currentOrientation);

0 votes

J'ai donc testé un peu plus et ce n'est pas si simple. Les appareils Android doivent utiliser screen.availHeight et screen.availWidth. IOS est bogué avec ces derniers, donc utilisez window.orientation pour IOS. Les ordinateurs de bureau doivent utiliser window.innerHeight et window.innerWidth car vous voulez les dimensions de la fenêtre et non celles de l'écran.

0 votes

Je me suis tapé la tête contre le mur avec le code ci-dessus. Trop délicat. Je ne supporte pas le desktop pour cette application, donc j'utilise window.orientation comme solution magique pour Android et IOS. Cela fonctionne bien maintenant. var orientation = Math.abs(window.orientation) === 90 ? 'landscape' : 'portrait' ;

1voto

Trent Oswald Points 11

J'ai parcouru plusieurs des réponses ci-dessus et aucune d'entre elles ne répondait exactement à ce que je voulais, c'est-à-dire imiter le plus fidèlement possible les fonctionnalités de l'iPhone. Ce qui suit est ce qui fonctionne pour moi en production maintenant.

Il fonctionne en assignant la largeur et la hauteur de la fenêtre du dispositif à un attribut de données pour une vérification ultérieure. Étant donné que les téléphones ne redimensionnent pas la largeur lorsqu'ils tirent le clavier vers le haut, mais seulement la hauteur, la vérification du rapport ET de la largeur par rapport à la largeur d'origine peut vous indiquer si le clavier est en place. Je n'ai pas encore trouvé de cas d'utilisation où cela a échoué, mais je suis sûr que cela arrivera. Si vous en trouvez un, faites-le moi savoir.

J'utilise certains globaux, comme InitialRun et MobileOrientation, qui sont utilisés pour le changement de js, j'utilise également les attributs de données html5 pour stocker des informations dans le DOM pour la manipulation css.

    var InitialRun = true; // After the initial bootstrapping, this is set to false;
    var MobileOrientation = 'desktop';
    function checkOrientation(winW, winH){ // winW and winH are the window's width and hieght, respectively
        if (InitialRun){
            if (winW > winH){
                $('body').attr('data-height',winW);
                $('body').attr('data-width',winH);
                MobileOrientation = 'landscape';    
                $('body').attr('data-orientation','landscape'); 
            }
            else{
                $('body').attr('data-height',winH);
                $('body').attr('data-width',winW);
                MobileOrientation = 'portrait';
                $('body').attr('data-orientation','portrait');
            }
        }
        else{
            if (winW > winH && winW != $('body').data('width')){
                MobileOrientation = 'landscape';    
                $('body').hdata('orientation','landscape'); //TODO:uncomment
                $('body, #wrapper').css({'height':"100%",'overflow-y':'hidden'});
                //$('body').attr('data-orientation','portrait');
            }
            else{
                MobileOrientation = 'portrait';
                $('body').attr('data-orientation','portrait');
                $('body, #wrapper').css({'height':$('body').data('height'),'overflow-y':'auto'});
            }
        }

    }

0voto

Sergiy T. Points 549

Jetez un coup d'œil à ce lien : http://www.alistapart.com/articles/a-pixel-identity-crisis/
S'appuyant non seulement sur l'orientation, mais aussi sur max-device-height o device-pixel-ratio peut aider. Quoi qu'il en soit, je ne l'ai pas testé, donc je ne suis pas sûr qu'il soit utile.

0voto

user3718546 Points 28

Idée : Retirez le paramètre portrait de votre requête média et laissez-le uniquement avec une largeur minimale. Faites votre style normal pour le mode portrait dans cette requête média. Ensuite, créez une autre requête média pour le mode paysage avec une hauteur minimale suffisamment élevée pour que le navigateur n'utilise pas cette requête lorsque le clavier s'affiche. Vous devrez expérimenter la définition de cette "hauteur minimale", mais cela ne devrait pas être trop difficile, car la plupart des modes paysage (si ce n'est tous) ont une hauteur supérieure à celle que vous aurez lorsque le clavier s'affichera. En outre, vous pourriez ajouter une "largeur minimale" à la requête paysage qui est plus grande que celle de la plupart des smartphones en mode portrait (c'est-à-dire environ ~400px) pour limiter la portée de la requête.

Voici une solution alternative (et ténue) : - Ajoutez un élément arbitraire vide à votre html qui aura 'display : none' dans tout autre mode que le mode portrait. - Créez un écouteur jquery ou javascript pour input:focus. Lorsqu'une entrée est cliquée, votre javascript vérifie la propriété display de l'élément arbitraire. S'il renvoie 'block' ou ce que vous avez défini en mode portrait, vous pouvez alors remplacer votre style par des requêtes JS en mode portrait. Inversement, vous auriez un écouteur input:blur pour effacer les propriétés style.cssText des éléments que vous avez codés en dur.

Je suis en train d'expérimenter cela moi-même en ce moment - je posterai le code de ce qui fonctionne quand j'aurai quelque chose de solide et de gérable. (Ma première solution semble la plus raisonnable).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X