543 votes

CSS3 100vh non constant dans le navigateur mobile

J'ai un problème très étrange... dans chaque navigateur et version mobile, j'ai rencontré ce comportement :

  • tous les navigateurs ont un menu supérieur lorsque vous chargez la page (montrant la barre d'adresse par exemple) qui glisse vers le haut lorsque vous commencez à faire défiler la page.
  • 100vh parfois n'est calculée que sur la partie visible d'un viewport, donc lorsque la barre du navigateur glisse vers le haut, 100vh augmente (en termes de pixels)
  • toute la mise en page doit être repeinte et réajustée car les dimensions ont changé
  • un mauvais effet de saut pour l'expérience utilisateur

Comment éviter ce problème ? Quand j'ai entendu parler de viewport-height pour la première fois, j'étais enthousiaste et je pensais pouvoir l'utiliser pour des blocs de hauteur fixe au lieu d'utiliser javascript, mais maintenant je pense que le seul moyen de le faire est en fait javascript avec un événement de redimensionnement...

vous pouvez voir le problème à : site de prélèvement

Quelqu'un peut-il m'aider ou me suggérer une solution CSS ?


code de test simple :

/* maybe i can track the issue whe it occours... */
$(function(){
  var resized = -1;
  $(window).resize(function(){
    $('#currenth').val( $('.vhbox').eq(1).height() );
    if (++resized) $('#currenth').css('background:#00c');
  })
  .resize();
})

*{ margin:0; padding:0; }

/*
  this is the box which should keep constant the height...
  min-height to allow content to be taller than viewport if too much text
*/
.vhbox{
  min-height:100vh;
  position:relative;
}

.vhbox .t{
  display:table;
  position:relative;
  width:100%;
  height:100vh;
}

.vhbox .c{
  height:100%;
  display:table-cell;
  vertical-align:middle;
  text-align:center;
}

<div class="vhbox" style="background-color:#c00">
  <div class="t"><div class="c">
  this div height should be 100% of viewport and keep this height when scrolling page
    <br>
    <!-- this input highlight if resize event is fired -->
    <input type="text" id="currenth">
  </div></div>
</div>

<div class="vhbox" style="background-color:#0c0">
  <div class="t"><div class="c">
  this div height should be 100% of viewport and keep this height when scrolling page
  </div></div>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

2 votes

Si j'ai bien compris la question, le problème auquel vous êtes confronté est que dans le navigateur mobile, la hauteur est supérieure à la hauteur du viewport visible n'est-ce pas ?

0 votes

Intéressant, je n'avais jamais remarqué ça avant. C'est principalement l'image d'arrière-plan qui est sensiblement instable. Et si vous ajoutiez un transition: 0.5s ou plus, pour que le changement soit moins brutal ?

1 votes

@GauravAggarwal non, c'est exactement le contraire : la hauteur réelle du viewport est supérieure à celle fournie par le navigateur lorsque sa barre d'adresse est visible...

4voto

mate Points 155

@nils l'a expliqué clairement.

Quelle est la suite ?

Je viens de revenir à l'utilisation relative "classique". % (pourcentage) en CSS.

La mise en œuvre de quelque chose demande souvent plus d'efforts que si l'on utilisait les services de l'UE. vh Mais au moins, vous disposez d'une solution assez stable qui fonctionne sur différents appareils et navigateurs sans problèmes d'interface.

3 votes

La hauteur : 100% pour les bannières saute toujours sur les navigateurs mobiles. Je l'ai testé sur Android, et jusqu'à présent Chrome et Opera Mini donnent 100% comme hauteur VP visible, et ne change pas lors du défilement. Edge et Firefox changent la hauteur de 100%, et repeignent la vue. Firefox est particulièrement mauvais, avec des déchirures, du texte rendu à nouveau, et un repositionnement très évident.

3voto

Ray1422 Points 31

Le code suivant a résolu le problème (avec jQuery).

var vhHeight = $("body").height();
var chromeNavbarHeight = vhHeight - window.innerHeight;
$('body').css({ height: window.innerHeight, marginTop: chromeNavbarHeight });

Et les autres éléments utilisent % comme une unité pour remplacer vh .

2voto

t.j.goodman Points 11

Comme je suis nouvelle, je ne peux pas commenter les autres réponses.

Si quelqu'un cherche une solution pour que cela fonctionne (et peut utiliser javascript - car il semble que cela soit nécessaire pour que cela fonctionne actuellement), cette approche a plutôt bien fonctionné pour moi et elle tient également compte des changements d'orientation des mobiles. J'utilise Jquery pour le code d'exemple mais cela devrait être faisable avec vanillaJS.

-D'abord, j'utilise un script pour détecter si le périphérique est tactile ou survolé. Exemple simple :

if ("ontouchstart" in document.documentElement) {
    document.body.classList.add('touch-device');

} else {
    document.body.classList.add('hover-device');
}

Cela ajoute une classe à l'élément body en fonction du type de dispositif (hover ou touch) qui pourra être utilisée ultérieurement pour le script de hauteur.

-Utilisez ensuite ce code pour définir la hauteur du dispositif au chargement et au changement d'orientation :

if (jQuery('body').hasClass("touch-device")) {
//Loading height on touch-device
    function calcFullHeight() {
        jQuery('.hero-section').css("height", $(window).height());
    }

    (function($) {
        calcFullHeight();

        jQuery(window).on('orientationchange', function() {
            // 500ms timeout for getting the correct height after orientation change
            setTimeout(function() {
                calcFullHeight();
            }, 500);

        });
    })(jQuery);

} else {
    jQuery('.hero-section').css("height", "100vh");

}

-Le délai d'attente est défini de manière à ce que l'appareil calcule correctement la nouvelle hauteur en cas de changement d'orientation. S'il n'y a pas de délai d'attente, d'après mon expérience, la hauteur ne sera pas correcte. 500 ms est peut-être un peu exagéré mais cela a fonctionné pour moi.

-100vh sur les dispositifs de survol est une solution de repli si le navigateur remplace le CSS 100vh.

2 votes

Touchstart n'est pas pris en charge par tous les navigateurs, et certains appareils non mobiles en sont équipés. developer.mozilla.org/fr/US/docs/Web/Events/touchstart

0 votes

@Drenai Touchstart est pris en charge par la plupart des navigateurs mobiles. Sur les ordinateurs de bureau, le support est un peu moins bon, IE, Opera et Safari ne le supportent pas. Cependant, la question originale vise les mobiles et non les ordinateurs de bureau. Ce qui en fait une réponse valide.

0 votes

Merci pour les commentaires ! J'ai principalement utilisé cette tactique pour surmonter les réajustements et les sauts d'écran sur certains navigateurs mobiles. Si le navigateur ne supporte pas le touchstart, la solution de repli sera le css 100vh - si 100vh n'est pas supporté, c'est un autre sujet. Si l'appareil de bureau est doté d'un support tactile, la hauteur sera calculée en javascript. Nous perdons alors le re-calcul au redimensionnement que 100vh fournit, mais ce n'est pas un problème fatal en général car il n'y a pas de changement d'orientation sur le bureau.

2voto

BenRacicot Points 869

N'utilisez pas les approches recommandées telles que -webkit-fill-available .
Je viens de passer toute la journée à me précipiter pour corriger ce "bug".

Ajouter une classe lorsque votre application est chargée avec un navigateur avec un "chin".

JavaScript

// Angular example but applicable for any JS solution
@HostBinding('class.browser-has-chin') browserHasChin: boolean = false;

public ngOnInit(): void {
    this.browserHasChin = this._isMobileSafari();
}

private _isMobileSafari() {
    return navigator.userAgent.match(/(iPod|iPhone|iPad)/) && navigator.userAgent.match(/AppleWebKit/) ? true : false;
}

CSS

.browser-has-chin {
  @media screen and (max-device-width: 767px){
    // offset with padding or something
  }
}

NOTES :
Il y a des problèmes majeurs avec le -webkit-fill-available prop pour la compatibilité entre navigateurs.

J'ai réussi à le faire fonctionner dans Chrome et iOS Safari pour résoudre le problème du calcul de la hauteur du menton. Cependant, il n'a pas fonctionné dans Android Chrome et Firefox avait également des bugs avec lui.

Il semble que -webkit-fill-available a été intégré à la hâte dans webkit à un moment donné et peut-être adopté au hasard par Apple comme un correctif pour le calcul du menton/de la hauteur ?

Il s'appuie sur dimensionnement intrinsèque qui n'est PAS encore sûr à utiliser.

2voto

Jahaziel Points 136

Je viens de découvrir qu'une application web que j'ai conçue a ce problème avec les iPhones et les iPads, et j'ai trouvé un article suggérant de le résoudre en utilisant des requêtes média ciblées sur des appareils Apple spécifiques.

Je ne sais pas si je peux partager le code de cet article ici, mais l'adresse est la suivante : http://webdesignerwall.com/tutorials/css-fix-for-ios-vh-unit-bug

Je cite l'article : "il suffit de faire correspondre la hauteur de l'élément avec celle du périphérique en utilisant des requêtes média qui ciblent les anciennes versions de la résolution de l'iPhone et de l'iPad."

Ils ont ajouté seulement 6 media queries pour adapter les éléments de pleine hauteur, et cela devrait fonctionner car c'est entièrement implémenté en CSS.

Edition en cours : Je ne suis pas en mesure de le tester pour le moment, mais je reviendrai et ferai part de mes résultats.

3 votes

Je suis désolé de ne pas être revenu comme promis. Mais après avoir bidouillé le HTML et le CSS pendant beaucoup plus longtemps que je ne l'aurais souhaité, j'ai modifié la conception de ma mise en page et j'ai trouvé un moyen qui fonctionnait "bien" pour mes besoins, mais qui n'était pas une solution universelle.

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