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

236

J'avais creusé la tête pour créer un alignement vertical en CSS en utilisant ce qui suit

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

    .vert-align{
		padding-top:50%;
		height:50%;
	}
<!-- and used the following div structure. -->

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

Bien que cela semble fonctionner pour 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éfinissais la propriété padding-top, cela prendrait le rembourrage 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 pourcentage de la largeur. :(

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

Ryan
la source

Réponses:

223

Le correctif est que oui, rembourrage vertical et la marge par rapport à la largeur, mais topet bottom ne sont pas.

Il suffit donc de placer un div à l'intérieur d'un autre, et dans le div intérieur, utilisez quelque chose comme top:50%(rappelez-vous des positionquestions si cela ne fonctionne toujours pas)

Camilo Martin
la source
3
topfonctionne très bien pour le redimensionnement en fonction de la hauteur du navigateur / de la fenêtre. Que diriez-vous d'avoir un div en dessous de ce div? Comment pouvez-vous clearle 2ème div être sous le div qui est décalé vers le bas par un top:50%??
Federico
Apprenez quelque chose de nouveau. Je ne savais pas que le rembourrage vertical et la marge étaient relatifs à la largeur auparavant. Je vous remercie.
shaosh du
5
Il est également possible d'ajouter un div «spacer» avec un pourcentage de hauteur défini. Semble peu sale mais ça marche. voir cette réponse .
WCByrne
4
Qu'est-ce que l'éternel @%! ^? Pourquoi la marge verticale et le rembourrage sont-ils relatifs à la largeur ? QUOI? Pourquoi diable cette décision a-t-elle été prise?
temporaire_user_name
Votre réponse est extrêmement disproportionnée par rapport à la réponse d'Alain ci-dessous, qui donne une solution générale, et je l'ai trouvée très utile et je ne l'ai presque pas vue. top: 50%n'est pas très utile si vous devez aligner le contenu par son propre centre.
okovko
35

Une réponse à une question légèrement différente: vous pouvez utiliser des vhunités pour garnir les éléments au centre de la fenêtre :

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

<div class="centerme">middle</div>
Willoller
la source
Pourquoi cette réponse n'est-elle pas votée plus haut? Y a-t-il un problème avec l'utilisation de vh?
AlanH
3
C'est parce que ce n'est pas une réponse adaptée à la question d'origine, c'est une astuce utile qui ne fonctionne que dans quelques cas connexes.
willoller
l'utilisation vhest presque la même que les pourcentages ... encore pire dans certains cas. Cette réponse est sans rapport avec la question
vsync
33

Voici deux options pour émuler le comportement nécessaire. 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 extérieur, pas de son parent, mais cette taille elle-même peut être relative au parent et de cette façon, l'espacement sera également relatif.

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

Première option: utiliser des pseudo-éléments, ici les espacements verticaux et horizontaux sont relatifs à 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 extérieur le rend relatif au parent de l'extérieur. 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%;
}
utilisateur
la source
10

Pour que l'élément enfant soit positionné absolument par rapport à son élément parent, vous devez définir la position relative sur l'élément parent ET la position absolue sur l'élément enfant.

Ensuite, l'élément enfant «top» est relatif à la hauteur du parent. Vous devez donc également «traduire» vers le haut l'enfant 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 la boîte flexible.

.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 / désavantages pour les deux.

alain
la source
1
L'utilisation de translate est le seul moyen réel de déplacer un élément verticalement par rapport à sa propre taille.
Eran Goldin
Merci pour cela. Ce devrait être la réponse choisie.
Wessam El Mahdy
6

Cela peut être réalisé avec la writing-modepropriété. Si vous définissez un élément writing-modesur un mode d'écriture vertical, tel que vertical-lr, les valeurs de pourcentage de ses descendants pour le rembourrage et la marge, dans les deux dimensions, deviennent relatives à la hauteur au lieu de la largeur.

De la spécification :

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

La définition de la taille en ligne :

Une mesure dans la dimension en ligne: se réfère à la largeur physique (dimension horizontale) dans les modes d'écriture horizontale et à la hauteur physique (dimension verticale) dans les modes d'écriture verticale.

Exemple, avec un élément redimensionnable, où les marges horizontales sont relatives à la largeur et les marges verticales sont relatives à 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 verticale peut être particulièrement utile dans les cas où vous souhaitez que le rapport d'aspect d'un élément reste constant, mais que sa taille soit mise à l'échelle en corrélation avec sa hauteur au lieu de sa largeur.

James T
la source
C'est, l'OMI, serait la solution la plus élégante, mais (à partir du 05/05/2018), les modes d'écriture verticale ne sont pas bien pris en charge . Espérons que cela change bientôt.
zanerock
1
@zanerock Je suis assez certain que la table compat MDN est obsolète. Par exemple, il dit que Safari a besoin du -webkit-préfixe, mais selon caniuse, il n'a pas exigé le préfixe depuis Safari 11. L'avez-vous essayé avec un navigateur dans lequel il ne fonctionnait pas?
James T
1
Non, je dois admettre que je viens de supposer que c'était bon, même automatisé.
zanerock
4

Une autre façon de centrer le texte d'une ligne est:

.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;
}
rawiro
la source
0

Un rembourrage à 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 manquez d'espace à mesure que votre contenu grandit? Avez-vous également essayé de définir la marge supérieure au lieu de la garniture supérieure?

EDIT: Nevermind, le site w3schools dit

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

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

Ce que vous faites peut être obtenu en utilisant display: table cependant (au moins pour les navigateurs modernes). La technique est expliquée ici .

Joint
la source
1
Merci Spliff. Je comprends que mes 50% ne centreront pas le contenu de la div. En fait, je n'ai qu'une seule ligne de texte qui doit être centrée verticalement. Merci beaucoup pour le lien!
Ryan
3
Si c'est juste une ligne de texte, avez-vous envisagé d'utiliser un ridiculement grand line-height, c'est-à-dire faire la hauteur de ligne à 200 pixels?
SpliFF
@Ryan pour centrer le texte verticalement, voir stackoverflow.com/questions/8865458/…
utilisateur
votre lien est rompu
quemeful
0

Ceci est un bug très intéressant. (A mon avis, c'est quand même un bug) Belle trouvaille!

En ce qui concerne la façon de le régler, je recommanderais la réponse de Camilo Martin. Mais pourquoi , je voudrais expliquer un peu cela si cela ne vous dérange pas.


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


Pourcentages 'padding' : se réfèrent à la largeur du bloc contenant

… Ce qui est bizarre, mais d'accord.

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

En effet, dans 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% × 17pxpour les barres horizontales). Ceux-ci 17pxsont soustraits avant de calculer le 50%, par conséquent 50% of 193px = 96.5px.

WoodrowShigeru
la source
Il y a une raison à la spécification, et cela l'explique mieux: hongkiat.com/blog/calculate-css-percentage-margins
manikanta