web-dev-qa-db-fra.com

Requête de média CSS - Le clavier logiciel enfreint les règles d’orientation CSS - solution alternative?

Je travaille avec plusieurs tablettes - Android 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) - iPad n'a pas ce problème

Le moyen le plus simple d'appliquer un style basé sur l'orientation du périphérique consiste à utiliser l'orientation de la requête multimé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 sur tous les tablettes. MAIS, le problème est que, lorsque le périphérique est en mode portrait et que l'utilisateur appuie sur un champ de saisie (recherche, par exemple), le clavier virtuel apparaît - ce qui réduit la zone visible de la page Web et l'oblige à restituer en css paysage. Sur les tablettes Android, cela dépend de la hauteur du clavier . Donc, au final, la page Web semble brisée. Par conséquent, je ne peux pas utiliser la requête multimédia d'orientation CSS3 pour appliquer des styles basés sur l'orientation (à moins que la requête multimédia soit mieux orientée). Voici un violon http://jsfiddle.net/hossain/S5nYP/5/ qui émule ceci - pour les tests de périphérique, utilisez la page de test complète - http://jsfiddle.net/S5nYP/embedded/result/

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

Donc, existe-t-il une alternative pour résoudre ce problème? Je suis ouvert aux solutions basées sur JavaScript si la solution basée sur CSS native ne fonctionne pas.

J'ai trouvé un extrait sur http://davidbcalhoun.com/2010/dealing-with-device-orientation qui suggère d'ajouter une classe et une cible 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? 

69
Hossain Khan

Je sais que cela fait quelques années de retard, mais j'ai trouvé une excellente solution

Pour les médias paysagers:

@media screen and (min-aspect-ratio: 13/9) { /* landscape styles here */}

Et pour les médias de portrait:

@media screen and (max-aspect-ratio: 13/9) { /* portrait styles here */}

La solution complète et son fonctionnement peuvent être trouvés ici Michael Barret - Défis du navigateur Android

Edit: ce lien a maintenant expiré, mais un instantané se trouve dans les archives Internet: Michael Barret - Défis du navigateur Android

85
Sean Routledge

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

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

La fonctionnalité de média «d’orientation» est «portrait» lorsque la valeur de la fonctionnalité de média «hauteur» est supérieure ou égale à la valeur de la fonctionnalité de média «largeur». Sinon, ‘orientation’ est ‘paysage’.

Étant donné que la hauteur/largeur est calculée dans la fenêtre visible, le clavier virtuel fait apparemment basculer l'orientation maintenant que la largeur de la fenêtre est inférieure à la hauteur. Une solution consisterait simplement à utiliser vos requêtes multimédia en vous basant uniquement sur width. Cela le rend plus flexible entre les appareils, quelle que soit leur orientation, sans oublier que la largeur/la hauteur est plus largement prise en charge que l'orientation.

Si vous souhaitez prendre en compte 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 car les requêtes ne se limitent pas aux périphériques/agents utilisateurs qui prennent en charge l'orientation, sans oublier que orientation vous en dit très peu par rapport à la largeur.

Bien sûr, si vous vraiment avez besoin de connaître l’orientation, il semble que vous définissiez la classe au début et que vous l’utilisiez peut-être bien.

26
scurker

Une alternative pourrait être d’utiliser device-aspect-ratio , qui reste inchangé. Toutefois, dans Webkit, la rotation de l'appareil ne déclenche pas de mise à jour des règles CSS à l'aide de cette requête, même si les tests JavaScript renvoient la valeur true pour le nouveau rapport de format. Ceci est apparemment à cause d'un bogue , mais je ne parviens pas à trouver un rapport de bogue. L'utilisation d'une combinaison de orientation et {min,max}-device-aspect-ratio semble fonctionner correctement:

@media screen and (max-device-aspect-ratio: 1/1) and (orientation: portrait)
@media screen and (min-device-aspect-ratio: 1/1) and (orientation: landscape)

L'utilisation de orientation déclenche les mises à jour comme prévu et l'utilisation de device-aspect-ratio limite les mises à jour aux changements d'orientation réels.

12
muru

J'ai travaillé à travers les options énumérées ci-dessus et aucune n'a vraiment résolu les problèmes pour moi. Je suis passé à screen.availHeight car il donne des résultats cohérents en hauteur, ce qui évite 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);
6
Robby Jennings

Pour moi, cela a fait l'affaire:

  @media screen and (max-device-aspect-ratio: 1/1), (max-aspect-ratio: 1/1){
        /*Portrait Mode*/
};

Alors que max-aspect-ratio se charge de déclencher le mode Portrait simplement en redimensionnant la fenêtre (utile pour les PC et autres périphériques uniquement en mode paysage), max-device-aspect-ratio aide les smartphones et autres périphériques à orientation variable. Et comme je ne déclare pas de paramètres spécifiques pour le mode Paysage, même si max-aspect-ratio rapporte> 1 au système, le mode Portrait sera toujours déclenché par max-device-aspect-ratio si le périphérique Android est orienté de cette façon. 

La partie 1/1 signifie en gros que si le rapport est <= 1, il passe en mode Portrait, sinon il passe en mode Paysage.

2
Helvecio Neto

J'ai parcouru plusieurs des réponses ci-dessus et aucune d'entre elles n'a fait 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. 

Cela fonctionne en affectant la largeur et la hauteur de la fenêtre de la fenêtre d'affichage du périphérique à un attribut de données pour une vérification ultérieure. Étant donné que les téléphones ne redimensionnent pas la largeur lorsque vous tirez le clavier, seule la hauteur, la vérification du rapport ET la largeur par rapport à la largeur d'origine peuvent vous indiquer si le clavier est en position haute. Je n'ai pas encore trouvé de cas d'utilisation qui a échoué, mais je suis sûr que je le ferai. Si vous en trouvez tous un, s'il vous plaît faites le moi savoir.

J'utilise certains globals, tels que InitialRun et MobileOrientation, qui sont utilisés pour la commutation js. J'utilise également les attributs de données html5 pour stocker des informations dans le DOM pour la manipulation de fichiers 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'});
            }
        }

    }
1
therebelrobot

J'ai été confronté exactement au même problème sur iPad.
c'est à dire; lorsque le clavier virtuel apparaît en mode portrait, le périphérique est détecté en orientation paysage et les styles de paysage sont appliqués à l'écran, ce qui crée une vue embrouillée.

Spécification de périphérique

  • Appareil: iPad Mini 4 
  • OS: iOS 11.2.6 
  • Résolution d'écran: 1024 x 768

malheureusement pour moi, cette solution n'a pas fonctionné.

@media screen and (min-aspect-ratio: 13/9) { /* landscape styles here */}
@media screen and (max-aspect-ratio: 13/9) { /* portrait styles here */}

Donc, ce que j’ai fait, c’est que j’ai écrit une requête multimédia comme celle-ci pour mon mode portrait.

@media only screen and (min-width : 300px) and (max-width : 768px) and (orientation : landscape) {
/* portrait styles, when softkeyboard appears, goes here */
}

c'est à dire; lorsque le clavier virtuel apparaît, la hauteur de l'écran est réduite mais la largeur de l'écran reste à 768 pixels, ce qui a permis à la requête multimédia de détecter l'écran en orientation paysage. D'où le travail autour donné comme ci-dessus.

0
Jacob Nelson

Cela fonctionne de manière fiable pour moi. J'utilise http://detectmobilebrowsers.com/ pour l'extension jQuery afin de détecter $ .browser.mobile.

if ($.browser.mobile) {
  var newOrientationPortrait = true;

//Set orientation based on height/width by default
  if ($(window).width() < $(window).height())
      newOrientationPortrait = true;
  else
      newOrientationPortrait = false;

//Overwrite orientation if mobile browser supports window.orientation
if (window.orientation != null)
    if (window.orientation === 0)
        newOrientationPortrait = true;
    else
        newOrientationPortrait = false;

Voici mon code pour modifier la fenêtre d'affichage en fonction de l'orientation. Cette fonction n'est appelée que pour les appareils mobiles, pas même les tablettes. Cela me permet d’écrire facilement des CSS pour 400px et 800px (Portrait vs Paysage).

_onOrientationChange = function() {
    if (_orientationPortrait) 
        $("meta[name=viewport]").attr("content", "width=400,user-scalable=no");
    else 
        $("meta[name=viewport]").attr("content", "width=800");
}

En raison de la nature de mes exigences, je ne pouvais pas le faire uniquement dans les requêtes CSS Media, car le DOM lui-même devait changer en fonction de l'orientation. Malheureusement, dans mon travail, les hommes d’affaires rédigent les exigences logicielles sans consulter au préalable le développement.

0
Chris Fremgen

Jetez un oeil à ce lien: http://www.alistapart.com/articles/a-pixel-identity-crisis/
Compter non seulement sur l'orientation, mais aussi sur max-device-height ou device-pixel-ratio peut aider. Quoi qu'il en soit, je ne l'ai pas testé, donc je ne suis pas sûr que ça va aider. 

0
Sergiy T.

Idée: supprimez le paramètre portrait de votre requête multimédia et laissez-le uniquement avec une largeur minimale. Utilisez votre style habituel pour le mode portrait dans cette requête multimédia. Créez ensuite une autre requête multimédia pour le mode paysage avec une hauteur minimale suffisante pour que le navigateur ne l'utilise pas lorsque le clavier apparaît. Vous devrez expérimenter ce qu'est cette "hauteur suffisante" (min-height), mais cela ne devrait pas être trop difficile, car la plupart (sinon tous) des modes Paysage ont une hauteur supérieure à celle d'un clavier. En outre, vous pouvez ajouter à la requête Paysage une "largeur minimale" qui est plus grande que la plupart des téléphones intelligents en mode portrait (environ 400px) afin de limiter la portée de la requête.

Voici une solution alternative (et ténue): - Ajoutez à votre code html un élément arbitraire vide qui aura «display: none» en mode autre que le mode portrait. . Lorsque vous cliquez sur une entré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 redéfinir votre style avec JS dans vos requêtes en mode portrait. Inversement, vous auriez une entrée: blur listener pour effacer les propriétés style.cssText des éléments codés en dur.

J'expérimente moi-même en ce moment - je posterai le code de ce qui fonctionne lorsque je reçois quelque chose de solide et de gérable. (Ma première solution semble la plus raisonnable).

0
user3718546