Der Rand des untergeordneten Elements verschiebt das übergeordnete Element

414

Ich habe ein div( Elternteil ), das ein anderes div( Kind ) enthält. Parent ist das erste Element bodyohne bestimmten CSS-Stil. Wenn ich setze

.child
{
    margin-top: 10px;
}

Das Endergebnis ist, dass die Oberseite meines Kindes immer noch mit dem Elternteil ausgerichtet ist. Anstatt das Kind um 10 Pixel nach unten zu verschieben, bewegt sich mein Elternteil um 10 Pixel nach unten.

Mein DOCTYPEist eingestellt auf XHTML Transitional.

Was fehlt mir hier?

Bearbeiten 1
Mein Elternteil muss streng definierte Abmessungen haben, da es einen Hintergrund hat, der von oben nach unten angezeigt werden muss (Pixel perfekt). Das Setzen vertikaler Ränder ist also ein No-Go .

edit 2
Dieses Verhalten ist bei FF, IE und CR gleich.

Robert Koritnik
quelle
188
Dieses Verhalten macht überhaupt keinen Sinn. Margin soll im Elternteil bleiben. Bewegen Sie den Elternteil nicht. Wer schreibt diese Regeln.
Muhammad Umer
10
+2 für den letzten Kommentar. ernsthaft nervt mich diese Regel . "60% der Zeit funktioniert es jedes Mal" - das sind Margen.
Casey Dwayne
29
Ich stimme den beiden letzten Kommentatoren voll und ganz zu. Das ist verrückt. Interessant ist, dass das Hinzufügen eines 1px-Rahmens zum übergeordneten Element richtig funktioniert. Dies bedeutet jedoch, dass Sie einen Rahmen haben. Wenn dies das erwartete Verhalten ist, ist dies lächerlich
erdomester
1
Dies kann Ihnen auch helfen :) stackoverflow.com/questions/35337043/…
Bhojendra Rauniyar
5
Dies erinnert mich an die Standardregel für die Boxgröße: " Wir müssen eine Box versenden. Die Box darf nicht größer als 100 cm sein. Wir benötigen 10 cm Polsterung in der Box, um sicherzustellen, dass unser Inhalt während des Versands nicht beschädigt wird die Box 120cm! "Was für ein Witz.
Nolonar

Antworten:

492

Bei untergeordneten Elementen mit Rändern innerhalb von DIVs wurde eine Alternative gefunden. Sie können auch Folgendes hinzufügen:

.parent { overflow: auto; }

oder:

.parent { overflow: hidden; }

Dies verhindert, dass die Ränder kollabieren . Rand und Polsterung machen dasselbe. Daher können Sie auch Folgendes verwenden, um einen Zusammenbruch am oberen Rand zu verhindern:

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

Update auf vielfachen Wunsch: Der springende Punkt beim Reduzieren von Rändern ist der Umgang mit Textinhalten. Zum Beispiel:

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>

Da der Browser die Ränder reduziert, wird der Text wie erwartet angezeigt und die <div>Wrapper-Tags haben keinen Einfluss auf die Ränder. Jedes Element stellt sicher, dass es einen Abstand hat, aber der Abstand wird nicht verdoppelt. Die Ränder von <h2>und <p>summieren sich nicht, sondern gleiten ineinander (sie kollabieren). Gleiches gilt für das Element <p>und <ul>.

Leider kann diese Idee bei modernen Designs Sie beißen, wenn Sie ausdrücklich einen Container möchten. Dies wird in CSS Speak als neuer Blockformatierungskontext bezeichnet . Der overflowoder Rand Trick wird Ihnen das geben.

vdboor
quelle
41
Ich möchte wissen, warum das passiert, was das für irgendjemanden bringt. Welche Situation sollte dieses "Feature" haben?
Muhammad Umer
2
@ MuhammadUmer, nun, das hat mit Textinhalten zu tun. Zum Beispiel kann eine Reihe von <h2>, <p>, <ul>nicht seltsamen Lücken bekommen oder „doppelte“ Margen auf diese Weise.
Vdboor
7
Könnten Sie ein Beispiel geben? Nehmen wir an, ich habe div als Hintergrund. Mit h1, h2 und p drin. Jetzt möchte ich h1 ein wenig nach unten bewegen, damit es nicht so nahe am oberen Rand des Hintergrund-Div liegt, aber das h1-Element selbst nicht erweitern. Ich würde denken, oberen Rand hinzufügen. Welches ist offensichtlich. aber wenn ich das tue, beschließt der herrliche Hintergrund, mit ihm nach unten zu gehen. Wie das eine Funktion ist. Wie dies beim Abstand zwischen h1, h2 und p hilft. Hilf mir zu sehen, was du sagst.
Muhammad Umer
1
Ich habe ein Beispiel für Sie hinzugefügt
vdboor
3
Ich würde erwarten, dass es mehr Spielraum hinzufügt. Das Zusammenbrechen von Margen ist bei weitem das nervigste in meiner Entwicklungskarriere. Wenn ich 2 Divs mit margin: 5px 10px;id nebeneinander lege, erwarte 2 Divs 5 px von oben und 20px zwischen ihnen, nicht 5 px von oben und 10px zwischen ihnen. wenn ich 10 px zwischen ihnen wollte, habe ich id angegeben margin: 5px 5px;. Ich wünschte ehrlich, es gäbe eine Grundregel, die ich aufstellen könnte, um zu verhindern, dass alle Ränder zusammenbrechen. Ich hasse es, dass ich die Größe der Ränder auf Papier verdoppeln muss, damit sie tatsächlich das tun, was zum Teufel ich auf dem Bildschirm will. und diese Top-Sache ... was für eine Katastrophe
JL Griffin
50

Dies ist normal (zumindest bei Browser-Implementierungen). Der Rand wirkt sich nicht auf die Position des Kindes in Bezug auf seinen Elternteil aus, es sei denn, der Elternteil verfügt über einen Abstand. In diesem Fall fügen die meisten Browser den Rand des Kindes zum Abstand des Elternteils hinzu.

Um das gewünschte Verhalten zu erzielen, benötigen Sie:

.child {
    margin-top: 0;
}

.parent {
    padding-top: 10px;
}
Ben James
quelle
3
Das Hinzufügen eines .parent {border: solid 1px;}
Rahmens
1
Der Rand trägt nicht zur Polsterung bei ... er gilt separat. Der visuelle Effekt ist jedoch der gleiche.
Brilliand
1
Was ist, wenn Sie einen Top-Rand wollen? Keine wirkliche Lösung.
Feeela
3
Wie Feeela sagte - dies ist keine wirkliche Lösung, wenn ein oberer Rand erforderlich ist. Die Antwort von vdboor passt besser.
Joey Morani
1
Es gibt eine Reihe von Lösungen, Sie müssen nur kreativ genug sein. Prost. :-)
Slavik Meltser
23

Obwohl alle Antworten das Problem beheben, kommen sie mit Kompromissen / Anpassungen / Kompromissen wie

  • floats, Sie müssen Elemente schweben
  • border-topDies drückt das übergeordnete Element mindestens 1 Pixel nach unten, was dann angepasst werden sollte, indem ein -1pxRand in das übergeordnete Element selbst eingefügt wird . Dies kann zu Problemen führen, wenn Eltern bereits margin-toprelative Einheiten haben.
  • padding-top, der gleiche Effekt wie bei der Verwendung border-top
  • overflow: hidden, Kann nicht verwendet werden, wenn Eltern überlaufende Inhalte anzeigen sollen, z. B. ein Dropdown-Menü
  • overflow: auto, Führt Bildlaufleisten für übergeordnete Elemente ein, deren Inhalt (absichtlich) überläuft (z. B. Schatten oder das Dreieck der QuickInfo).

Das Problem kann mithilfe der folgenden CSS3-Pseudoelemente behoben werden

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

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

Ejaz
quelle
margin-top: -1pxscheint unnötig zu sein. Aber ich mag das.
Flimm
3
Eigentlich beides margin-top: -1pxund height: 0scheint unnötig. In Chrome getestet. Aber beste Lösung.
NinjaFart
Diese Methode funktioniert meistens, berücksichtigt jedoch nicht den unteren Rand des letzten Elements im Container. Es ist keine gleichwertige Lösung für den Überlauf: versteckt; zum Beispiel.
Michael Giovanni Pumo
1
@ MichaelGiovanniPumo die Antwort kann geändert werden, um mit dem unteren Rand des letzten Elements zu arbeiten, indem.parent:after...
Ejaz
Dies ist heutzutage definitiv die richtige Antwort. Funktioniert einwandfrei (sowohl nach als auch vor), ich hoffe, die Leute wagen es, an den anderen vorbei zu scrollen!
fgblomqvist
13

Stil display:inline-blockzum untergeordneten Element hinzufügen

Атанас Димитров
quelle
9

Das übergeordnete Element darf nicht leer sein, zumindest nicht &nbsp;vor dem untergeordneten Element.

George SEDRA
quelle
2
Ja, manchmal kann nur dies helfen ... oder besser gesagt: <div style = 'width: 0; height: 0'> </ div>
Pigalev Pavel
7

Das hat bei mir funktioniert

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

.child {
margin-top:260px;
}

http://jsfiddle.net/97fzwuxh/

erdomester
quelle
2

Ich finde heraus, dass innerhalb Ihrer .css>, wenn Sie die display-Eigenschaft eines div-Elements auf inline-block setzen , das Problem behoben wird. und die Marge wird wie erwartet funktionieren.

Vincent Thorpe
quelle
2

Ordentliche CSS-Lösung

Verwenden Sie den folgenden Code, um dem ungewollt bewegten div ein inhaltsloses erstes Kind voranzustellen:

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

Der Vorteil dieser Methode besteht darin, dass Sie das CSS eines vorhandenen Elements nicht ändern müssen und daher nur minimale Auswirkungen auf das Design haben. Daneben ist das hinzugefügte Element ein Pseudoelement, das sich nicht im DOM-Baum befindet.

Die Unterstützung für Pseudoelemente ist weit verbreitet: Firefox 3+, Safari 3+, Chrome 3+, Opera 10+ und IE 8+. Dies funktioniert in jedem modernen Browser (seien Sie vorsichtig mit dem neueren ::before, der in IE8 nicht unterstützt wird).

Kontext

Wenn das erste untergeordnete Element eines Elements ein hat margin-top, passt das übergeordnete Element seine Position an, um redundante Ränder zu reduzieren. Warum? Es ist einfach so.

Angesichts des folgenden Problems:

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

Sie können das Problem beheben, indem Sie ein untergeordnetes Element mit Inhalten hinzufügen, z. B. einem einfachen Leerzeichen. Aber wir alle hassen es, Räume für ein reines Designproblem hinzuzufügen. Verwenden Sie daher die white-spaceEigenschaft, um Inhalte zu fälschen.

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

Wobei position: relative;die korrekte Positionierung des Fixes gewährleistet ist. Und white-space: pre;macht Sie keine Inhalte hinzufügen, die - wie ein weißer Raum - zu dem Update. Und height: 0px;width: 0px;overflow: hidden;stellt sicher, dass Sie das Update nie sehen werden.

Möglicherweise müssen Sie in alten IE-Browsern hinzufügen line-height: 0px;oder max-height: 0px;sicherstellen, dass die Höhe tatsächlich Null ist (ich bin mir nicht sicher). Und optional können Sie <!--dummy-->es in alten IE-Browsern hinzufügen , wenn es nicht funktioniert.

Kurz gesagt, Sie können dies alles nur mit CSS tun (wodurch das Hinzufügen eines tatsächlichen untergeordneten Elements zum HTML-DOM-Baum entfällt):

<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>
Yeti
quelle
Verwenden Sie diese Lösung nur, wenn Sie verzweifelt sind und Sie kein benutzerdefiniertes CSS für die vorhandenen Elemente festlegen können. Verwenden Sie andernfalls die echte Lösung: set overflow: hidden;für das übergeordnete Element .
Yeti
2

Um "Div parent" zu verhindern, verwenden Sie den Rand von "div child":
Verwenden Sie im Parent diese CSS:

  • Schweben
  • Polsterung
  • Rand
  • Überlauf
Bingo
quelle
1

Die darin marginenthaltenen Elemente .childkollabieren.

<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 diesem Beispiel werden vom Browser Standardstile pempfangen margin. Die Standardeinstellung des Browsers font-sizeist normalerweise 16px. Wenn Sie einen margin-topWert von mehr als 16 Pixel haben #child, bemerken Sie, dass sich die Position bewegt.

25. Stunde
quelle
1

Ich hatte auch dieses Problem, zog es jedoch vor, Hacks mit negativen Margen zu verhindern, also setzte ich ein

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

um alles herum, was Polster anstelle von Rändern hat. Natürlich bedeutet dies mehr Divitis, aber es ist wahrscheinlich der sauberste Weg, dies richtig zu machen.

Zyl
quelle
1

Interessanterweise wird meine Lieblingslösung für dieses Problem hier noch nicht erwähnt: die Verwendung von Floats.

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

siehe hier: http://codepen.io/anon/pen/Iphol

Beachten Sie, dass für den Fall, dass Sie eine dynamische Höhe für das übergeordnete Element benötigen, diese ebenfalls schweben muss. Ersetzen Sie sie einfach height:100px;durchfloat:left;

schellmax
quelle
1

Eine alternative Lösung, die ich gefunden habe, bevor ich die richtige Antwort wusste, war das Hinzufügen eines transparenten Rahmens zum übergeordneten Element.

Ihre Box verwendet jedoch zusätzliche Pixel ...

.parent {
    border:1px solid transparent;
}
SandRock
quelle
0

Verwenden von topanstelle von margin-topist gegebenenfalls eine andere mögliche Lösung.

lamplightdev
quelle