web-dev-qa-db-fra.com

Comment définir la marge ou le remplissage en pourcentage de la hauteur du conteneur parent?

Je m'étais creusé la cervelle pour créer un alignement vertical en CSS à l'aide de ce qui suit

.base{
    background-color:green;
    width:200px;
    height:200px;
    overflow:auto;
    position:relative;
}

.vert-align{
    padding-top:50%;
    height:50%;
}

et utilisé la structure div suivante.

<div class="base">
   <div class="vert-align">
       Content Here
   </div>
</div>

Bien que cela semble fonctionner dans ce cas, j'ai été surpris de constater que, lorsque j'augmentais ou diminuais la largeur de mon div de base, l'alignement vertical se cassait. Je m'attendais à ce que, lorsque je définisse la propriété padding-top, celle-ci prenne le remplissage en pourcentage de la hauteur du conteneur parent, qui est la base dans notre cas, mais la valeur ci-dessus de 50% est calculée en tant que pourcentage du largeur. :(

Existe-t-il un moyen de définir le remplissage et/ou la marge sous forme de pourcentage de la hauteur, sans recourir à JavaScript? 

199
Ryan

La solution est que oui, le remplissage vertical et la marge sont relatifs à la largeur, mais top et bottomare are.

Il suffit donc de placer une div à l’intérieur d’une autre, et d’utiliser quelque chose comme top:50% (rappelez-vous que position importe si cela ne fonctionne toujours pas)

198
Camilo Martin

Voici deux options pour émuler le comportement requis. Pas une solution générale, mais peut aider dans certains cas. L'espacement vertical ici est calculé sur la base de la taille de l'élément externe, pas de son parent, mais cette taille elle-même peut être relative au parent et ainsi, l'espacement sera également relatif.

<div id="outer">
    <div id="inner">
        content
    </div>
</div>

Première option: utiliser des pseudo-éléments, ici l'espacement vertical et horizontal est relatif à l'extérieur. Démo

#outer::before, #outer::after {
    display: block;
    content: "";
    height: 10%;
}
#inner {
    height: 80%;
    margin-left: 10%;
    margin-right: 10%;
}

Le déplacement de l'espacement horizontal vers l'élément externe le rend relatif au parent de l'élément externe. Démo

#outer {
    padding-left: 10%;
    padding-right: 10%;
}

Deuxième option: utiliser le positionnement absolu. Démo

#outer {
    position: relative;
}
#inner {
    position: absolute;
    left: 10%;
    right: 10%;
    top: 10%;
    bottom: 10%;
}
30
user

Une réponse à une question légèrement différente: Vous pouvez utiliser vh unités pour placer des éléments au centre de la vue viewport:

.centerme {
    margin-top: 50vh;
    background: red;
}

<div class="centerme">middle</div>
29
willoller

Pour que l'élément enfant soit positionné de manière absolue par rapport à son élément parent, vous devez définir une position relative sur l'élément parent ET une position absolue sur l'élément enfant. 

Ensuite, l'élément enfant 'top' est relatif à la hauteur du parent. Vous devez donc également "traduire" l'enfant vers le haut de 50% de sa propre taille.

.base{
    background-color: green;
    width: 200px;
    height: 200px;
    overflow: auto;
    position: relative;
}
    
.vert-align {
    position: absolute;
    top: 50%;
    transform: translate(0, -50%);
}
    <div class="base">
        <div class="vert-align">
            Content Here
        </div>
    </div>

Il existe une autre solution utilisant flex box.

.base{
    background-color:green;
    width: 200px;
    height: 200px;
    overflow: auto;
    display: flex;
    align-items: center;
}
<div class="base">
    <div class="vert-align">
        Content Here
    </div>
</div>

Vous trouverez des avantages/inconvénients pour les deux.

10
alain

Une autre façon de centrer le texte sur une ligne est la suivante:

.parent{
  position: relative;
}

.child{
   position: absolute;
   top: 50%;
   line-height: 0;
}

ou juste

.parent{
  overflow: hidden; /* if this ins't here the parent will adopt the 50% margin of the child */
}

.child{
   margin-top: 50%;
   line-height: 0;
}
3
rawiro

Un rembourrage de 50% ne centre pas votre enfant, il le placera en dessous du centre. Je pense que vous voulez vraiment un rembourrage de 25%. Peut-être que vous êtes juste à court d'espace alors que votre contenu devient plus grand? Aussi avez-vous essayé de définir la marge supérieure en lieu et place de la marge supérieure?

EDIT: Nevermind, dit le site w3schools 

% Spécifie le remplissage en pourcentage de la largeur de l'élément conteneur

Alors peut-être qu'il utilise toujours la largeur? Je n'avais jamais remarqué.

Ce que vous faites peut être réalisé avec display: table (du moins pour les navigateurs modernes). La technique est expliquée ici .

1
SpliFF

Ceci peut être réalisé avec la propriété writing-mode . Si vous définissez le writing-mode d'un élément sur un mode d'écriture vertical, tel que vertical-lr, les valeurs de pourcentage de ses descendants pour le remplissage et la marge, dans les deux dimensions, deviennent relatives à la hauteur plutôt qu'à la largeur.

De la spec :

. . . les pourcentages sur les propriétés de marge et de remplissage, qui sont toujours calculés par rapport à la largeur du bloc conteneur en CSS2.1, sont calculés par rapport à la taille inline du bloc conteneur en CSS3.

La définition de inline size :

Une mesure dans la dimension en ligne: fait référence à la largeur physique (dimension horizontale) dans les modes d’écriture horizontale et à la hauteur physique (dimension verticale) dans les modes d’écriture vertical. 

Exemple, avec un élément redimensionnable, où les marges horizontales sont relatives à la largeur et les marges verticales, à la hauteur.

.resize {
  width: 400px;
  height: 200px;
  resize: both;
  overflow: hidden;
}

.outer {
  height: 100%;
  background-color: red;
}

.middle {
  writing-mode: vertical-lr;
  margin: 0 10%;
  width: 80%;
  height: 100%;
  background-color: yellow;
}

.inner {
  writing-mode: horizontal-tb;
  margin: 10% 0;
  width: 100%;
  height: 80%;
  background-color: blue;
}
<div class="resize">
  <div class="outer">
    <div class="middle">
      <div class="inner"></div>
    </div>
  </div>
</div>

L'utilisation d'un mode d'écriture vertical peut s'avérer particulièrement utile dans les cas où vous souhaitez que le rapport de format d'un élément reste constant, mais que sa taille soit redimensionnée en fonction de sa hauteur plutôt que de sa largeur.

1
James T

C'est un bug très intéressant. (À mon avis, c'est un bug quand même) Belle découverte!

En ce qui concerne comment pour le définir, je recommanderais la réponse de Camilo Martin. Mais en ce qui concerne pourquoi, j'aimerais expliquer un peu cela si cela ne vous dérange pas.


Dans les spécifications CSS j'ai trouvé:

'padding'
Les pourcentages: font référence à la largeur du bloc conteneur

… Ce qui est bizarre, mais d'accord.

Donc, avec un parent width: 210px et un enfant padding-top: 50%, j'obtiens une valeur calculée/calculée de padding-top: 96.5px - qui n'est pas le 105px attendu.

En effet, sous Windows (je ne suis pas sûr des autres systèmes d’exploitation), la taille des barres de défilement courantes est par défaut 17px × 100% (ou 100% × 17px pour les barres horizontales). Ces 17px sont soustraits avant en calculant le 50%, d'où 50% of 193px = 96.5px.

0
WoodrowShigeru