Perché questo stile margine margine CSS non funziona?


321

Provo ad aggiungere valori di margine su un div all'interno di un altro div. Tutto funziona benissimo tranne il valore massimo, sembra essere ignorato. Ma perché?

Cosa mi aspettavo:
Cosa mi aspettavo con margine: 50px 50px 50px 50px;

Cosa ottengo:
Cosa ottengo con margine: 50px 50px 50px 50px;

Codice:

#outer {
    	width: 500px; 
    	height: 200px; 
    	background: #FFCCCC;
    	margin: 50px auto 0 auto;
    	display: block;
}
#inner {
    	background: #FFCC33;
    	margin: 50px 50px 50px 50px;
    	padding: 10px;
    	display: block;
}
<div id="outer">
  <div id="inner">
  	Hello world!
  </div>
</div>

W3Schools non ha alcuna spiegazione del perché il margine si comporti in questo modo.


4
hai provato a far fluttuare quello interiore?
Gallo

6
hum .. Con float:left;esso funziona ... ma perché è necessario. Non voglio che galleggi. E perché funziona il margine sinistro / destro?
jamietelin,

44
Benvenuti nel divertente mondo dell'algoritmo di compressione del margine CSS!
GordonM

10
W3Schools vs. W3CDocs ... Penso che abbiamo un vincitore. : D
enderskill

15
jsFiddle of it, to save the next guy 25 secondi jsfiddle.net/kLeu9
CodyBugstein

Risposte:


453

In realtà stai vedendo il margine superiore #innerdell'elemento crollare nel bordo superiore #outerdell'elemento, lasciando #outerintatto solo il margine (anche se non mostrato nelle immagini). I bordi superiori di entrambe le caselle sono allineati l'uno contro l'altro perché i loro margini sono uguali.

Ecco i punti rilevanti delle specifiche del W3C:

8.3.1 Margini collassanti

Nel CSS, i margini adiacenti di due o più caselle (che potrebbero essere o meno fratelli) possono combinarsi per formare un margine singolo. Si dice che i margini che si combinano in questo modo collassano e il margine combinato risultante viene chiamato margine compresso .

Crollo dei margini verticali adiacenti [...]

Due margini sono contigui se e solo se:

  • entrambi appartengono a caselle a livello di blocco in-flow che partecipano allo stesso contesto di formattazione del blocco
  • nessuna linea, nessun gioco, nessuna imbottitura e nessun bordo li separano
  • entrambi appartengono ai bordi della scatola adiacenti verticalmente, ovvero formano una delle seguenti coppie:
    • margine superiore di una casella e margine superiore del suo primo figlio in-flow

È possibile effettuare una delle seguenti operazioni per evitare il collasso del margine:

Il motivo per cui le opzioni precedenti impediscono il collasso del margine è perché:

  • I margini tra una scatola fluttuante e qualsiasi altra scatola non collassano (nemmeno tra un galleggiante e i suoi figli in-flow).
  • I margini degli elementi che stabiliscono nuovi contesti di formattazione dei blocchi (come float ed elementi con "overflow" diverso da "visibile") non collassano con i loro figli in-flow.
  • I margini delle caselle dei blocchi inline non collassano (nemmeno con i loro figli in-flow).

I margini sinistro e destro si comportano come previsto perché:

I margini orizzontali non collassano mai.



2
Questa risposta è incredibile! Solo qualcosa da aggiungere. La tua citazione di w3c lo dice ma me ne sono accorta solo ora. Quindi, per essere chiari per gli altri, potresti anche dare a #outer un bordo.
driechel,

Il collegamento in Floating sembra essere rotto.
EP

@episanty: ecco cosa succede quando si collega a un commento. Non collegati.
BoltClock

Lo so - volevo solo farti sapere. Dato che sei abilitato per ♦ ho pensato che potresti voler resuscitare il commento o cambiare il tuo post di conseguenza. Grazie per la buona risposta, comunque.
EP

92

Prova a utilizzare display: inline-block;sul div interno.

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:block;
}
#inner {
    background:#FFCC33;
    margin:50px 50px 50px 50px;
    padding:10px;
    display:inline-block;
}

6
Buona risposta. Sarebbe meglio se spiegasse perché questa modifica risolve il problema.
JohnFx

1
Ok, è strano! Perché funziona? Qual è la spiegazione logica del perché non funziona come ci si aspetterebbe. Il margine sinistro / destro funziona senza display:inline-block;. Anche arretrato quando si utilizza display:inline-block;è che si perde la larghezza del 100% sul div.
jamietelin,

3
il passaggio a blocco inline forza il browser a rivalutare la dimensione del div dopo che è stato inserito e sono state applicate altre regole.
Gallo

Ho provato per il mio problema, fatto un effetto scala.
Jonny,

1
display:inline-blockha funzionato per me. Grazie mille.
Starkeen,

24

Quello che ha detto @BoltClock è piuttosto solido. E qui voglio solo aggiungere diverse altre soluzioni per questo problema. controlla questo margine w3c_collapsing . Le parti verdi sono il potenziale pensiero su come risolvere questo problema.

Soluzione 1

I margini tra una scatola fluttuante e qualsiasi altra scatola non collassano (nemmeno tra un galleggiante e i suoi figli in-flow).

ciò significa che posso aggiungere float:lefta #outero #inner demo1 .

nota anche che floatciò invaliderebbe il automargine in.

Soluzione 2

I margini degli elementi che stabiliscono nuovi contesti di formattazione dei blocchi (come float ed elementi con "overflow" diverso da "visibile") non collassano con i loro figli in-flow.

altro che visible, mettiamolo overflow: hiddendentro #outer. E in questo modo sembra abbastanza semplice e decente. Mi piace.

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    overflow: hidden;
}
#inner {
    background: #FFCC33;
    height: 50px;
    margin: 50px;
}

Soluzione 3

I margini delle caselle posizionate in modo assoluto non collassano (nemmeno con i loro figli in-flow).

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    position: absolute; 
}
#inner{
    background: #FFCC33;
    height: 50px;
    margin: 50px;
}

o

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    position: relative; 
}
#inner {
    background: #FFCC33;
    height: 50px;
    margin: 50px;
    position: absolute;
}

questi due metodi interromperanno il normale flusso di div

Soluzione 4

I margini delle caselle dei blocchi inline non collassano (nemmeno con i loro figli in-flow).

è uguale a @enderskill

Soluzione 5

Il margine inferiore di un elemento a livello di blocco nel flusso collassa sempre con il margine superiore del suo fratello a livello di blocco nel flusso successivo, a meno che quel fratello non abbia spazio.

Questo non ha molto lavoro a che fare con la domanda poiché è il margine di collasso tra fratelli. significa in genere se una top-box ha margin-bottom: 30pxe una fratelli-box ha margin-top: 10px. Il margine totale tra loro è 30pxinvece di 40px.

Soluzione 6

Il margine superiore di un elemento di blocco in-flow collassa con il margine superiore del suo primo figlio a livello di blocco in-flow se l'elemento non ha bordo superiore, nessuna imbottitura superiore e il bambino non ha spazio.

Questo è molto interessante e posso solo aggiungere una linea di confine superiore

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    border-top: 1px solid red;

}
#inner {
    background: #FFCC33;
    height: 50px;
    margin: 50px;

}

E anche il <div>livello di blocco è predefinito, quindi non è necessario dichiararlo apposta. Ci scusiamo per non poter pubblicare più di 2 link e immagini a causa della mia reputazione da principiante. Almeno sai da dove viene il problema la prossima volta che vedi qualcosa di simile.


14

Non sono sicuro del perché ciò che hai non funziona, ma puoi aggiungerlo

overflow: auto;

al div esterno.


Carichi di diverse soluzioni a questo problema. Grazie! Questa risposta combinata con la risposta di @ BoltClock fornisce buone informazioni sul perché questa soluzione funziona.
jamietelin,

12

Se aggiungi qualche imbottitura a #outer, funziona.

dimostrazione

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:block;
    padding-top:1px;
}

11

Non so esattamente perché, ma cambiando il CSS interno in

display:inline-block;

sembra funzionare;


3

Non risponde al "perché" (deve essere qualcosa con margine collassante), ma sembra che il modo più semplice / logico di fare ciò che stai cercando di fare sia semplicemente aggiungere padding-topal div esterno :

http://jsfiddle.net/hpU5d/1/

Nota minore: non dovrebbe essere necessario impostare un div su a display:block;meno che non ci sia qualcos'altro nel tuo codice che dice di non essere un blocco.


3

prova questo:

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:table;
}
#inner {
    background:#FFCC33;
    margin:50px 50px 50px 50px;
    padding:10px;
    display:block;
}​

http://jsfiddle.net/7AXTf/

In bocca al lupo


2

Immagino che anche l'impostazione della proprietà position del div #inner su relative possa aiutare a ottenere l'effetto. Ma comunque ho provato il codice originale incollato nella domanda su IE9 e nell'ultimo Google Chrome e danno già l'effetto desiderabile senza alcuna modifica.


2

Utilizzare padding-top:50pxper div esterno. Qualcosa come questo:

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:table;}

Nota: l'imbottitura aumenta le dimensioni del div. In questo caso, se la dimensione del tuo div è importante, intendo se deve avere un'altezza specifica. riduci l'altezza di 50 px:

#outer {
    width:500px; 
    height:150px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:table;}

1

Hai provato! Importante prima di tutto, forzerà tutto:

margin:50px 50px 50px 50px !important;

-1

Solo per una soluzione rapida, prova a avvolgere gli elementi figlio in un divelemento come questo:

<div id="outer">
   <div class="divadjust" style="padding-top: 1px">
      <div id="inner">
         Hello world!
      </div>
   </div>
</div>

Il margine di innerdiv non collasserà a causa del riempimento di 1pxin-between outere innerdiv. Quindi logicamente avrai 1pxspazio extra insieme al margine esistente di innerdiv.

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.