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...

29voto

Sarath Ak Points 851

Vous pouvez le faire en ajoutant le script et le style suivants

  function appHeight() {
    const doc = document.documentElement
    doc.style.setProperty('--vh', (window.innerHeight*.01) + 'px');
  }

  window.addEventListener('resize', appHeight);
  appHeight();

Style

.module {
  height: 100vh; /* Fallback for browsers that do not support Custom Properties */
  height: calc(var(--vh, 1vh) * 100);
}

5 votes

Ceci est décrit en détail ici : css-tricks.com/the-trick-to-viewport-units-on-mobile/

26voto

Pour de nombreux sites que je construis, le client demande une bannière de 100vh et, comme vous l'avez constaté, cela donne une mauvaise expérience "saccadée" sur les mobiles lorsque vous commencez à faire défiler le texte. Voici comment je résous le problème pour une expérience fluide et cohérente sur tous les appareils :

J'ai d'abord défini la CSS de mon élément de bannière comme height:100vh

J'utilise ensuite jQuery pour obtenir la hauteur en pixels de mon élément de bannière et appliquer un style en ligne en utilisant cette hauteur.

var viewportHeight = $('.banner').outerHeight();
$('.banner').css({ height: viewportHeight });

Cela résout le problème sur les appareils mobiles, car lorsque la page se charge, l'élément de bannière est défini à 100vh à l'aide de la CSS, mais jQuery passe outre en plaçant une CSS en ligne sur mon élément de bannière, ce qui l'empêche de se redimensionner lorsque l'utilisateur commence à faire défiler la page.

Cependant, sur un ordinateur de bureau, si un utilisateur redimensionne la fenêtre de son navigateur, l'élément de ma bannière ne sera pas redimensionné car il a maintenant une hauteur fixe définie en pixels en raison du jQuery ci-dessus. Pour résoudre ce problème, j'utilise Détection mobile pour ajouter une classe "mobile" au corps de mon document. Ensuite, je place le jQuery ci-dessus dans une instruction if :

if ($('body').hasClass('mobile')) {
  var viewportHeight = $('.banner').outerHeight();
  $('.banner').css({ height: viewportHeight });
}

Par conséquent, si un utilisateur se trouve sur un appareil mobile, la classe "mobile" est présente dans le corps de ma page et la commande jQuery ci-dessus est exécutée. Ainsi, l'élément de ma bannière ne recevra le CSS en ligne que sur les appareils mobiles, tandis que sur les ordinateurs de bureau, la règle CSS 100vh originale reste en place.

5 votes

Je le modifierais pour utiliser $('.banner').css({ height: window.innerHeight }); à la place, qui est la hauteur "réelle" de la fenêtre d'affichage. Exemple de fonctionnement de innerHeight

11 votes

Ce qui est document.querySelector('.banner').style.height = window.innerHeight; pour les personnes qui écrivent du vrai JavaScript.

21voto

Mike Points 546

Je suis venu avec un composant React - vérifiez-le si vous utilisez React ou parcourir le code source si vous ne le faites pas, afin de l'adapter à votre environnement.

Il définit le plein écran div à la hauteur de window.innerHeight et le met à jour lorsque la fenêtre est redimensionnée.

1 votes

Et pour les amoureux de Vue ... github.com/razumnyak/vue-div-100vh

10voto

Jürgen P. Points 201

Comme je cherchais une solution depuis quelques jours, voici la mienne pour tous ceux qui utilisent VueJS avec Vuetify (ma solution utilise v-app-bar, v-navigation-drawer et v-footer) : J'ai créé App.scss (utilisé dans App.vue) avec le contenu suivant :

.v-application {
    height: 100vh;
    height: -webkit-fill-available;
}

.v-application--wrap {
    min-height: 100vh !important;
    min-height: -webkit-fill-available !important;
}

1 votes

Cela semblait fonctionner au début pour moi, mais j'ai ensuite remarqué que le conteneur n'était pas redimensionné en cas de changement d'orientation sur les appareils mobiles.

1 votes

html { height: 100vh; height: -webkit-fill-available; } body, body > div, .v-application, .v-application--wrap { height: 100vh; height: -webkit-fill-available; min-height: 100vh; min-height: -webkit-fill-available; } Ça m'a évité les deux problèmes. Enfin

7voto

Hasan upinion Points 37

Vous pouvez essayer de donner position: fixed; top: 0; bottom: 0; à votre conteneur.

2 votes

Ajoutez plus d'informations sur la raison pour laquelle il s'agit d'une réponse à la question.

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