Pourquoi height: 100% ne marche pas

Le blog que Maujor consacre à CSS depuis 2006 est bien connu au Brésil pour ses articles spécialisés ou de vulgarisation. Celui-ci fait le point sur le problème height:100%.

Par

Une des déclarations CSS championnes des réclamations chez les débutants (et même chez ceux qui ont déjà une bonne pratique de CSS) est la déclaration height: 100%;. Il est courant de trouver sur les forums de discussion des questions ou remarques du genre :

J’ai déjà déclaré height: 100% dans mon CSS et cette div ne s’étire pas verticalement comme on pouvait l’espérer, un conseil ?

ou des réponses du genre :

Déclare height: 100% et ta div sera responsive dans le sens vertical

Le problème ne vient pas du fonctionnement de la propriété, car elle a été créée pour étirer la hauteur d’une boîte de 100%, exactement en effet comme on pouvait l’espérer. Alors, où est le problème ? Eh bien en fait il n’y a pas de problème, ce qu’il faut c’est bien comprendre comment fonctionne la propriété height.

Une mesure CSS (comme n’importe quelle mesure) exprimée en pourcentage est une mesure relative, elle doit donc être rapportée à autre chose.

Width: 100%

Dans le modèle de boîte CSS, la boîte a une largeur (width) initiale définie comme égale à auto qui par défaut est considérée comme couvrant toute la largeur du viewport. Si l’utilisateur redimensionne la fenêtre du navigateur, il modifie de manière dynamique la largeur du viewport et par conséquent la largeur auto de la boîte pour lui donner la valeur actuelle du viewport.

La largeur à laquelle se réfère le navigateur pour calculer celle, exprimée en pourcentage, d’une boîte est la largeur de son élément parent. Ainsi, une boîte ayant une largeur width: 50% qui est enfant d’un container de largeur égale à 200px aura une largeur de 50% de 200px, c’est à dire 100px. Élémentaire.

Et si la largeur de l’élément parent n’est pas définie, comment s’effectue le calcul ?

Eh bien dans ce cas, elle est par défaut considérée comme auto.

Et s’il n’y a pas d’élément parent ayant une largeur définie ?

Dans ce cas, on considère implicitement que la largeur de tous les éléments parents est auto, en d’autres termes la largeur est calculée par rapport à celle du viewport, comme nous venons de le voir. Dans ces conditions, une boîte ayant une largeur de 25% occupera toujours 1/4 dela largeur du viewport. Si l’utilisateur redimensionne la fenêtre du navigateur, la largeur s’ajuste automatiquement.

Height: 100%

Dans le modèle de boîte CSS, une boîte a une hauteur initiale définie comme auto mais, contrairement à width, cette valeur par défaut n’est pas égale à la hauteur du viewport. Pour la propriété height, la valeur auto par défaut est celle qui permet de faire rentrer le contenu verticalement dans la boîte — et elle dépend d’autres facteurs, comme par exemple la largeur de la boîte.

Pour le calcul de la hauteur exprimée en pourcentage, la référence est la hauteur de l’élément parent. Ainsi, une boîte de hauteur height: 50% qui est l’enfant d’une boîte de hauteur égale à 200px aura une hauteur de 50% de 200px, soit 100px. Élémentaire à nouveau.

Et si la hauteur de l’élément parent n’est pas définie ? Comment se fait le calcul ?

Dans ce cas, il est implicite que la hauteur de l’élément parent est auto (indéfini) et n’importe quel pourcentage d’indéfini donnera indéfini.

La déclaration CSS n’est donc pas appliquée, et ce qui détermine la hauteur est alors le contenu. Voilà pourquoi height: 100% ne fonctionne pas.

Faire fonctionner height: 100%

Reprenons ce que nous venons d’exposer et n’oublions pas que les éléments html et body sont les ancêtres les plus distants de n’importe quel élément de notre document.

Dans toute structure HTML, lorsque nous définissons la hauteur d’un élément en pourcentage il est nécessaire que son élément parent ait une hauteur définie. Si cette hauteur est définie de manière absolue, on calcule le pourcentage sur la valeur en question et c’est bon.

Si par contre la hauteur de l’élément parent est définie en pourcentage, il faut alors examiner la définition de la hauteur de l’ancêtre (l’élément parent de l’élément parent) et répéter le processus jusqu’à arriver à l’élément racine html.

Si dans cette chaîne d’ancêtres l’un n’a pas de hauteur définie, les définitions de hauteur en pourcentage pour tous ses descendants ne sont pas prises en compte, puisque comme nous l’avons vu ne pas définir de hauteur revient à donner la valeur auto (qui est indéfinie).

Exemples

Pour démontrer le fonctionnement de la déclaration height: 100% j’ai créé ces quelques démos.

Les démos montrent un élément div ayant une classe de um (“un” en portugais) et son contenu : un petit texte et le code correspondant à la démo. Nous souhaitons que la div prenne toute la hauteur de la page.

La première tentative consiste simplement à déclarer la règle de style :

.um { height: 100%; }

Cela ne va pas fonctionner car l’élément parent de div.um (body) n’a pas de hauteur déclarée. Voir la démo 1.

Pour que cela fonctionne, nous devons déclarer la hauteur de tous les éléments ancêtres de div.um. Ce sont body et html. Voir la démo 2.

Vous aurez peut-être la tentation de déclarer * { height: 100%; } dans l’espoir de normer les hauteurs. Ou encore de déclarer height: 100%; pour tous les éléments d’une partie du DOM où vous aurez besoin de cette extension. Attention : procéder de la sorte peut résulter en une belle confusion dans votre mise en page.

Si un élément sur lequel vous déclarez height: 100% comporte des marges ou du padding verticaux, des barres de défilement apparaîtront dans le rendu final car le calcul du pourcentage est effectué avant ajout des marges et/ou padding. Voir la démo 3 (observez la barre de défilement)

Pour éliminer les barres de défilement, nous devons soustraire la valeur des marges et/ou padding verticaux de nos 100%. Si ces espacements sont eux-mêmes définis en pourcentages, c’est simple, il suffit de les déduire de nos 100%, sinon utilisez la fonction calc() de CSS. Voir la démo 4.

NB : on peut également utiliser la propriété box-sizing à la place de la fonction calc().

Conclusion

Pour faire fonctionner height: 100% il suffit de déclarer explicitement la valeur de hauteur de tous les éléments ancêtres. La difficulté est de savoir quelles implications cela peut avoir sur le reste de la mise en page.

Par conséquent, la déclaration height: 100% est finalement d’usage restreint, et n’est certainement pas la solution à tous nos problèmes de hauteur.

Tout n’est pas perdu cependant, Flexbox est là ! Parmi les fonctionnalités de cette nouvelle spécification, celles qui permettent un plus grand contrôle des dimensions de nos boîtes, sans dépendre des éléments liés dans le markup, sont particulièrement intéressantes.

Mise à jour

du 24 juillet 2015, grâce à jon begood : la spécification du W3C CSS Values and Units Module Level 3 est actuellement dans la phase de candidate à recommandation. Parmi les fonctionnalités proposées, on trouve les unités de mesure dont la valeur est un pourcentage de la largeur ou de la hauteur du viewport (unités ‘vw’, ‘vh’, ‘vmin’, ‘vmax’).
Cette unité de mesure est bien supportée par les navigateurs actuels, voir l'exemple 5.

NdT : un bel exemple de cascade de la connaissance : un article brésilien traduit en français, mis à jour par un lecteur français. Merci Johnny B Good !


Intéressé par CSS ? Retrouvez une liste des meilleurs articles et ressources du web.

Tous les articles sur CSS parus dans la Cascade.

Tous les articles sur les bases de CSS parus dans la Cascade.


original paru le dans Blog do Maujor.

Sur l’auteur : Mauricio Samy Silva, dit se définit lui-même comme le dinosaure du Web au Brésil. Son blog consacré à CSS existe depuis 2006, et il est très populaire parmi tous les publics, des débutants aux développeurs front end confirmés. On peut le suivre sur Twitter ou sur son blog.

Traduit avec l’aimable autorisation de Blog do Maujor et de l’auteur.
Copyright Blog do Maujor © 2013.