Il margine sull'elemento figlio sposta l'elemento genitore


415

Ho un div( genitore ) che ne contiene un altro div( figlio ). Parent è il primo elemento bodysenza uno stile CSS particolare. Quando ho impostato

.child
{
    margin-top: 10px;
}

Il risultato finale è che la parte superiore di mio figlio è ancora allineata con il genitore. Invece di spostare il bambino di 10 pixel verso il basso, il mio genitore sposta di 10 pixel verso il basso.

Il mio DOCTYPEè impostato su XHTML Transitional.

Cosa mi sto perdendo qui?

modifica 1 Il
mio genitore deve avere dimensioni rigorosamente definite perché ha uno sfondo che deve essere visualizzato sotto di esso dall'alto verso il basso (pixel perfetto). Quindi impostare margini verticali su di esso è un non andare .

modifica 2
Questo comportamento è lo stesso su FF, IE e CR.


188
questo comportamento non ha alcun senso. Il margine dovrebbe rimanere all'interno del genitore. Non spostare il genitore. Chi scrive queste regole.
Muhammad Umer,

10
+2 per l'ultimo commento. seriamente questa regola mi dà fastidio. "Il 60% delle volte funziona ogni volta" - questo è un margine.
Casey Dwayne,

29
Concordo pienamente con gli ultimi due commentatori. Questo è folle. La cosa interessante è che l'aggiunta di un bordo 1px al genitore fa funzionare bene, tuttavia questo significa che hai un bordo ... se questo è il comportamento previsto, allora è ridicolo
erdomester


5
Questo mi ricorda la regola di dimensionamento della scatola predefinita: " Dobbiamo spedire una scatola. La scatola non deve essere più grande di 100 cm. Abbiamo bisogno di 10 cm di imbottitura all'interno della scatola per garantire che il nostro contenuto non si rompa durante la spedizione. Facciamo la scatola di 120 cm! "Che barzelletta.
Nolonar,

Risposte:


492

È stata trovata un'alternativa agli elementi figlio con margini all'interno dei DIV È inoltre possibile aggiungere:

.parent { overflow: auto; }

o:

.parent { overflow: hidden; }

Ciò impedisce il collasso dei margini . Bordo e imbottitura fanno lo stesso. Quindi, puoi anche usare quanto segue per prevenire un collasso del margine superiore:

.parent {
    padding-top: 1px;
    margin-top: -1px;
}

Aggiornamento su richiesta popolare: l'intero punto del collasso dei margini è la gestione dei contenuti testuali. Per esempio:

h1, h2, p, ul {
  margin-top: 1em;
  margin-bottom: 1em;
}
<h1>Title!</h1>
<div class="text">
  <h2>Title!</h2>
  <p>Paragraph</p>
</div>
<div class="text">
  <h2>Title!</h2>
  <p>Paragraph</p>
  <ul>
    <li>list item</li>
  </ul>
</div>

Poiché il browser comprime i margini, il testo appare come previsto e i <div>tag wrapper non influenzano i margini. Ogni elemento assicura che abbia una spaziatura attorno ad esso, ma la spaziatura non sarà raddoppiata. I margini di <h2>e <p>non si sommano, ma scivolano l'uno nell'altro (collassano). Lo stesso accade per <p>e<ul> elemento .

Purtroppo, con i design moderni questa idea può morderti quando vuoi esplicitamente un contenitore. Questo è chiamato un nuovo contesto di formattazione dei blocchi nel linguaggio CSS. Il overflowtrucco del margine o ti darà questo.


41
voglio sapere perché questo succede a cosa serve a chiunque. Quale situazione doveva essere questa "caratteristica".
Muhammad Umer,

2
@MuhammadUmer, beh, questo ha a che fare con il contenuto del testo. Ad esempio, una serie di <h2>, <p>, <ul>non sarà possibile ottenere strani spazi o margini "doppie" in questo modo.
vdboor

7
Potresti fare qualche esempio. Diciamo che ho div come sfondo. Con h1, h2 e p in esso. Ora voglio spostare un po 'verso il basso h1, quindi non è così vicino al bordo superiore del div dello sfondo, ma non espandere l'elemento h1 stesso. Penso che aggiungere il margine superiore. Questo è ovvio. ma quando lo faccio, lo sfondo glorioso decide di spostarsi verso il basso. Come questa è una caratteristica. Come questo aiuta a spaziare tra h1, h2 e p. Aiutami a vedere cosa stai dicendo.
Muhammad Umer,

1
Ho aggiunto un esempio per te
vdboor,

3
mi aspetterei che aggiungesse più margine. crollare i margini è di gran lunga la cosa più fastidiosa nella mia carriera di sviluppo. se metto 2 div uno accanto all'altro con margin: 5px 10px;ID mi aspetto 2 div 5 px dall'alto e 20px tra loro non 5 px dall'alto e 10px tra di loro. se avessi voluto 10 px tra loro ho specificato l'id margin: 5px 5px;. onestamente vorrei che ci fosse una regola di base che avrei potuto fermare il crollo di tutti i margini. odio dover raddoppiare le dimensioni dei margini sulla carta per farli effettivamente fare ciò che diamine voglio sullo schermo. e questa cosa eccezionale ... che disastro
JL Griffin,

50

Questo è un comportamento normale (almeno tra le implementazioni del browser). Il margine non influisce sulla posizione del bambino rispetto al suo genitore, a meno che il genitore non abbia il riempimento, nel qual caso la maggior parte dei browser aggiungerà quindi il margine del bambino al riempimento del genitore.

Per ottenere il comportamento desiderato, è necessario:

.child {
    margin-top: 0;
}

.parent {
    padding-top: 10px;
}

3
L'aggiunta del bordo al genitore influirà anche sul margine del bambino, prova.parent {border: solid 1px;}
ok,

1
Il margine non si aggiunge all'imbottitura ... si applica separatamente. Ma l'effetto visivo è lo stesso.
Brilliand,

1
E se vuoi un margine superiore ...? Non proprio una soluzione.
feeela,

3
Come ha detto feeela, questa non è davvero una soluzione se è richiesto un margine superiore. La risposta di vdboor si adatta meglio.
Joey Morani,

1
Ci sono un sacco di soluzioni, devi solo essere abbastanza creativo. Saluti. :-)
Slavik Meltser

24

Sebbene tutte le risposte risolvano il problema, ma presentano compromessi / rettifiche / compromessi come

  • floats, Si deve a galleggiare elementi
  • border-top, Ciò spinge il genitore verso il basso di almeno 1px verso il basso, che dovrebbe quindi essere regolato introducendo -1pxmargine per l'elemento genitore stesso. Questo può creare problemi quando il genitore ha già margin-topin unità relative.
  • padding-top, stesso effetto dell'utilizzo border-top
  • overflow: hidden, Non può essere utilizzato quando il genitore deve visualizzare contenuti straripanti, come un menu a discesa
  • overflow: auto, Presenta barre di scorrimento per l'elemento genitore che ha (intenzionalmente) contenuti traboccanti (come ombre o triangolo della punta degli strumenti)

Il problema può essere risolto utilizzando gli pseudo elementi CSS3 come segue

.parent::before {
  clear: both;
  content: "";
  display: table;
  margin-top: -1px;
  height: 0;
}

https://jsfiddle.net/hLgbyax5/1/


margin-top: -1pxsembra non essere necessario. Ma mi piace questo
Flimm,

3
In realtà, entrambi margin-top: -1pxe height: 0sembra inutile. Testato in Chrome. Ma la migliore soluzione.
Ninja,

Questo metodo funziona principalmente, ma non rispetterà il margine inferiore per l'ultimo elemento all'interno del contenitore. Non è una soluzione uguale a overflow: nascosto; per esempio.
Michael Giovanni Pumo,

1
@MichaelGiovanniPumo la risposta può essere modificata per funzionare con il margine inferiore dell'ultimo elemento usando.parent:after...
Ejaz

Questa è sicuramente la risposta corretta al giorno d'oggi. Funziona in modo impeccabile (indossalo sia dopo che prima), spero che la gente osi scorrere oltre gli altri!
fgblomqvist,


9

l'elemento genitore non deve essere vuoto almeno messo &nbsp;prima dell'elemento figlio.


2
sì, a volte solo questo può aiutare ... o meglio mettere qualcosa del genere: <div style = 'width: 0; height: 0'> & nbsp; </div>
Pigalev Pavel


2

Scopro che, all'interno del tuo .css> se imposti la proprietà display di un elemento div su blocco inline , risolve il problema. e il margine funzionerà come previsto.


2

Neat soluzione solo CSS

Usa il codice seguente per anteporre un primo figlio senza contenuto al div che si sposta involontariamente:

.parent:before
{content: '';position: relative;height: 0px;width: 0px;overflow: hidden;white-space: pre;}

Il vantaggio di questo metodo è che non è necessario modificare il CSS di alcun elemento esistente e pertanto ha un impatto minimo sulla progettazione. Accanto a questo, l'elemento che viene aggiunto è uno pseudo-elemento, che non si trova nell'albero DOM.

Il supporto per gli pseudo-elementi è molto diffuso: Firefox 3+, Safari 3+, Chrome 3+, Opera 10+ e IE 8+. Funzionerà con qualsiasi browser moderno (fai attenzione al più recente::before , che non è supportato in IE8).

Contesto

Se il primo figlio di un elemento ha a margin-top , il genitore regolerà la sua posizione come un modo per far collassare i margini ridondanti. Perché? È proprio così.

Dato il seguente problema:

<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}
</style>

<div class="parent"><!--This div moves 40px too-->
    <div class="child">Hello world!</div>
</div>

Puoi risolverlo aggiungendo un bambino con contenuti, come uno spazio semplice. Ma tutti odiamo aggiungere spazi per ciò che è solo un problema di progettazione. Pertanto, utilizzare la white-spaceproprietà per falsificare il contenuto.

<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}
.fix {position: relative;white-space: pre;height: 0px;width: 0px;overflow: hidden;}
</style>

<div class="parent"><!--This div won't move anymore-->
    <div class="fix"></div>
    <div class="child">Hello world!</div>
</div>

Dove position: relative;garantisce il corretto posizionamento della correzione. E white-space: pre;ti fa non dover aggiungere alcun contenuto - come uno spazio bianco - alla correzione. E height: 0px;width: 0px;overflow: hidden;assicurati che non vedrai mai la correzione.

Potrebbe essere necessario aggiungere line-height: 0px;o max-height: 0px;assicurarsi che l'altezza sia effettivamente zero nei browser IE antichi (non sono sicuro). E facoltativamente puoi aggiungerlo <!--dummy-->nei vecchi browser IE, se non funziona.

In breve, puoi fare tutto questo solo con CSS (il che elimina la necessità di aggiungere un figlio effettivo all'albero DOM HTML):

<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}

.parent:before {content: '';position: relative;height: 0px;width: 0px;overflow: hidden;white-space: pre;}
</style>

<div class="parent"><!--This div won't move anymore-->
    <div class="child">Hello world!</div>
</div>

Usa questa soluzione solo se sei disperato e non puoi impostare alcun CSS personalizzato sugli elementi esistenti, altrimenti usa la soluzione reale: imposta overflow: hidden;per il genitore.
Yeti,

2

Per evitare che "Div parent" usi il margine di "div child":
In parent usa questi css:

  • Galleggiante
  • Imbottitura
  • Confine
  • straripamento

1

Gli marginelementi contenuti all'interno .childstanno collassando.

<html>
<style type="text/css" media="screen">
    #parent {background:#dadada;}
    #child {background:red; margin-top:17px;}
</style>
<body>
<div id="parent">

    <p>&amp;</p>

    <div id="child">
        <p>&amp;</p>    
    </div>

</div>
</body>
</html>

In questo esempio, priceve uno margindagli stili predefiniti del browser. L'impostazione predefinita del browser font-sizeè in genere 16 px. Avendo uno margin-topdi più di 16px #childinizi a notare che è il movimento di posizione.


1

Ho avuto anche questo problema, ma ho preferito prevenire gli hack sui margini negativi, quindi ho inserito un

<div class="supercontainer"></div>

attorno ad esso tutto ciò che ha delle imbottiture anziché dei margini. Ovviamente questo significa più divite, ma è probabilmente il modo più pulito per farlo correttamente.


1

è interessante notare che la mia soluzione preferita a questo problema non è ancora menzionata qui: usare float.

html:

<div class="parent">
    <div class="child"></div>
</div>

css:

.parent{width:100px; height:100px;}
.child{float:left; margin-top:20px; width:50px; height:50px;}

vederlo qui: http://codepen.io/anon/pen/Iphol

nota che nel caso in cui tu abbia bisogno di un'altezza dinamica sul genitore, deve anche galleggiare, quindi sostituiscilo semplicemente height:100px;confloat:left;


1

Una soluzione alternativa che ho trovato prima di conoscere la risposta corretta era quella di aggiungere un bordo trasparente all'elemento genitore.

La tua scatola utilizzerà pixel extra però ...

.parent {
    border:1px solid transparent;
}

0

L'utilizzo topinvece di margin-topè un'altra possibile soluzione, se del caso.

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.