Come impostare il margine o il riempimento come percentuale di altezza del contenitore principale?


236

Mi ero scervellato per creare un allineamento verticale in CSS usando quanto segue

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

Mentre questo sembrava funzionare per questo caso, sono rimasto sorpreso dal fatto che quando ho aumentato o diminuito la larghezza del mio div base, l'allineamento verticale si spezzasse. Mi aspettavo che quando avessi impostato la proprietà padding-top, avrei preso il padding come percentuale dell'altezza del contenitore padre, che è base nel nostro caso, ma il valore sopra del 50 percento viene calcolato come percentuale del larghezza. :(

C'è un modo per impostare l'imbottitura e / o il margine come percentuale dell'altezza, senza ricorrere all'utilizzo di JavaScript?

Risposte:


223

La correzione è che sì, padding verticale e il margine sono relative al larghezza, ma tope bottom non lo sono.

Quindi posiziona un div all'interno di un altro e, nel div interno, usa qualcosa di simile top:50%(ricorda le positioncose se continua a non funzionare)


3
topfunziona alla grande per il ridimensionamento in base all'altezza del browser / finestra. Che ne dici di avere un div sotto quel div? Come puoi clearil 2 ° div essere sotto il div che viene spostato verso il basso di un top:50%??
Federico,

Scopri di nuovo. Prima non sapevo che l'imbottitura verticale e il margine fossero relativi alla larghezza. Grazie.
shaosh

5
È anche possibile aggiungere un div 'distanziatore' con un'altezza percentuale impostata. Sembra un po 'sporco ma funziona. vedi questa risposta .
WCByrne,

4
Cosa l'eterno @%! ^? Perché il margine verticale e l'imbottitura sono relativi alla larghezza ? CHE COSA? Perché mai quella decisione è stata presa?
temporaneo

La tua risposta è estremamente sproporzionatamente votata rispetto alla risposta di Alain di seguito, che offre una soluzione generale, e l'ho trovata molto utile e quasi non l'ho vista. top: 50%non è molto utile se è necessario allineare i contenuti con il proprio centro.
Okovko,

35

Una risposta a una domanda leggermente diversa: puoi usare le vhunità per riempire gli elementi al centro della finestra :

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

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

Perché questa risposta non è votata più in alto? C'è qualcosa di sbagliato nell'usare VH?
AlanH,

3
È perché non è una risposta su misura per la domanda originale, è un trucco utile che funziona solo in alcuni casi correlati.
Willoller,

l'utilizzo vhè quasi uguale alle percentuali ... anche peggio in alcuni casi. Questa risposta è irrilevante per la domanda
vsync,

33

Ecco due opzioni per emulare il comportamento necessario. Non è una soluzione generale, ma può aiutare in alcuni casi. La spaziatura verticale qui viene calcolata sulla base della dimensione dell'elemento esterno, non del suo genitore, ma questa stessa dimensione può essere relativa al genitore e in questo modo anche la spaziatura sarà relativa.

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

Prima opzione: utilizzare pseudo-elementi, qui la spaziatura verticale e orizzontale sono relative all'esterno. dimostrazione

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

Spostare la spaziatura orizzontale sull'elemento esterno la rende relativa al genitore dell'esterno. dimostrazione

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

Seconda opzione: utilizzare il posizionamento assoluto. dimostrazione

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

10

Per rendere l'elemento figlio posizionato in modo assoluto rispetto al suo elemento padre, è necessario impostare la posizione relativa sull'elemento padre E la posizione assoluta sull'elemento figlio.

Quindi, l'elemento figlio 'top' è relativo all'altezza del genitore. Quindi devi anche "tradurre" verso l'alto il 50% della sua altezza.

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

C'è un'altra soluzione che utilizza la scatola flessibile.

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

Troverai vantaggi / svantaggi per entrambi.


1
L'uso di translate è l'unico modo reale di spostare un elemento verticalmente rispetto alla sua stessa dimensione.
Eran Goldin,

Grazie per questo. Questa dovrebbe essere la risposta scelta.
Wessam El Mahdy,

6

Questo può essere ottenuto con la writing-modeproprietà. Se si imposta un elemento writing-modesu una modalità di scrittura verticale, ad esempio vertical-lr, i valori percentuali dei suoi discendenti per il riempimento e il margine, in entrambe le dimensioni, diventano relativi all'altezza anziché alla larghezza.

Dalle specifiche :

. . . le percentuali sulle proprietà di margine e riempimento, che sono sempre calcolate rispetto alla larghezza del blocco contenitore in CSS2.1, sono calcolate rispetto al dimensione in linea del blocco contenitore in CSS3.

La definizione di dimensione in linea :

Una misura nella dimensione incorporata: si riferisce alla larghezza fisica (dimensione orizzontale) nelle modalità di scrittura orizzontale e all'altezza fisica (dimensione verticale) nelle modalità di scrittura verticale.

Esempio, con un elemento ridimensionabile, in cui i margini orizzontali sono relativi alla larghezza e i margini verticali sono relativi all'altezza.

.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'uso di una modalità di scrittura verticale può essere particolarmente utile nelle circostanze in cui si desidera che le proporzioni di un elemento rimangano costanti, ma si desidera ridimensionare le sue dimensioni in relazione alla sua altezza anziché alla larghezza.


Questa è, IMO, sarebbe la soluzione più elegante, ma (dal 05-05-2018) le modalità di scrittura verticale non sono ben supportate . Spero che presto cambi.
zanerock

1
@zanerock Sono abbastanza sicuro che la tabella di compatibilità MDN sia obsoleta. Ad esempio, dice che Safari ha bisogno del -webkit-prefisso, ma secondo caniuse non ha richiesto il prefisso da Safari 11. L'hai provato con qualsiasi browser in cui non funzionava?
James T,

1
No, devo ammettere che ho solo pensato che fosse buono, persino automatizzato.
zanerock

4

Un altro modo per centrare il testo di una riga è:

.parent{
  position: relative;
}

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

o solo

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

0

Un'imbottitura al 50% non centrerà il bambino, lo posizionerà sotto il centro. Penso che tu voglia davvero una imbottitura del 25%. Forse stai esaurendo lo spazio man mano che il contenuto diventa più alto? Hai anche provato a impostare il margine superiore invece di padding superiore?

EDIT: Nevermind, dice il sito w3schools

% Specifica il riempimento in percentuale della larghezza dell'elemento contenitore

Quindi forse usa sempre la larghezza? Non l'avevo mai notato.

Quello che stai facendo può essere realizzato usando display: table (almeno per i browser moderni). La tecnica è spiegata qui .


1
Grazie Spliff. Capisco che il mio 50% non centrerà il contenuto del div. In realtà ho solo una riga di testo che deve essere centrata verticalmente. Grazie mille per il link!
Ryan,

3
Se è solo una riga di testo hai preso in considerazione l'utilizzo di un ridicolmente grande line-height, ovvero rendere l'altezza della linea di 200 px?
SpliFF,

@Ryan per centrare il testo verticalmente, vedi stackoverflow.com/questions/8865458/…
utente

il tuo collegamento è interrotto
quemeful

0

Questo è un bug molto interessante. (Secondo me, è comunque un bug) Bella scoperta!

Per quanto riguarda come impostarlo, consiglierei la risposta di Camilo Martin. Ma per quanto riguarda perché , vorrei spiegarlo un po 'se non vi dispiace.


Nel specifiche CSS ho trovato:

'imbottitura'
Percentuali di : fare riferimento alla larghezza del blocco contenitore

... che è strano, ma va bene.

Quindi, con un genitore width: 210pxe un figliopadding-top: 50% , ottengo un valore calcolato / calcolato di padding-top: 96.5px- che non è il previsto105px .

Questo perché in Windows (non sono sicuro di altri sistemi operativi), la dimensione delle barre di scorrimento comuni è predefinita 17px × 100%(o 100% × 17pxper le barre orizzontali). Questi 17pxvengono sottratti prima di calcolare il 50%, quindi 50% of 193px = 96.5px.


C'è una ragione per la specifica, e questo lo spiega meglio: hongkiat.com/blog/calculate-css-percentage-margins
manikanta
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.