Margines na elemencie potomnym przenosi element nadrzędny

414

Mam div( rodzica ), który zawiera inny div( dziecko ). Parent jest pierwszym elementem bodybez określonego stylu CSS. Kiedy ustawię

.child
{
    margin-top: 10px;
}

Rezultat końcowy jest taki, że góra mojego dziecka jest nadal wyrównana z rodzicem. Zamiast przesunięcia dziecka o 10 pikseli w dół, mój rodzic przesuwa się o 10 pikseli w dół.

Mój DOCTYPEjest ustawiony na XHTML Transitional.

Czego tu brakuje?

edytuj 1
Mój rodzic musi mieć ściśle określone wymiary, ponieważ ma pod nim tło, które musi być wyświetlane od góry do dołu (idealnie w pikselach). Tak marginesy pionowe ustawienie na nim to nie idź .

edytuj 2
To zachowanie jest takie samo w FF, IE, jak i CR.

Robert Koritnik
źródło
188
takie zachowanie nie ma sensu. Margines powinien pozostać wewnątrz rodzica. Nie ruszaj rodzica. Kto pisze te zasady.
Muhammad Umer
10
+2 za ostatni komentarz. poważnie ta zasada mnie wkurza. „60% czasu działa za każdym razem” - to marże.
Casey Dwayne
29
Całkowicie zgadzam się z dwoma ostatnimi komentatorami. To jest szalone. Interesujące jest to, że dodanie ramki nadrzędnej 1px sprawia, że ​​działa ona poprawnie, jednak oznacza to, że masz granicę ... jeśli jest to oczekiwane zachowanie, to jest śmieszne
erdomester
1
To może ci również pomóc :) stackoverflow.com/questions/35337043/…
Bhojendra Rauniyar
5
Przypomina mi to domyślną zasadę rozmiaru pudełka: „ Musimy wysłać pudełko. Pudełko nie może być większe niż 100 cm. Potrzebujemy 10 cm wypełnienia wewnątrz pudełka, aby upewnić się, że nasza zawartość nie pęknie podczas wysyłki. Zróbmy pudełko 120 cm! ”Co za żart.
Nolonar,

Odpowiedzi:

492

Znalazłem alternatywę w elementach potomnych z marginesami w DIV. Możesz także dodać:

.parent { overflow: auto; }

lub:

.parent { overflow: hidden; }

Zapobiega to marginesy załamania . Obramowanie i wypełnienie to samo. W związku z tym można również użyć następujących elementów, aby zapobiec zwinięciu górnej krawędzi:

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

Aktualizuj według popularnego żądania: Cały punkt zwijania marginesów to obsługa treści tekstowych. Na przykład:

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>

Ponieważ przeglądarka zwija marginesy, tekst będzie wyglądał tak, jak można się spodziewać, a <div>tagi opakowania nie wpływają na marginesy. Każdy element zapewnia odstępy wokół niego, ale odstępy nie zostaną podwojone. Marginesy <h2>i <p>nie będą się sumować, ale wślizgną się w siebie (zwiną się). To samo dzieje się z elementem <p>i <ul>.

Niestety, dzięki nowoczesnym wzorom ten pomysł może cię ugryźć, gdy wyraźnie potrzebujesz pojemnika. Nazywa się to nowym kontekstem formatowania bloku w mowie CSS. overflowLub margines trik daje to.

vdboor
źródło
41
chcę wiedzieć, dlaczego tak się dzieje, co to komuś wyrządza. W jakiej sytuacji miała być ta „cecha”.
Muhammad Umer
2
@MuhammadUmer, cóż, ma to związek z treścią tekstu. Na przykład seria <h2>, <p>, <ul>nie dostaniesz dziwne braki lub marginesy „double” w ten sposób.
vdboor
7
Czy możesz podać jakiś przykład? Powiedzmy, że mam div jako tło. Z h1, h2 i pw nim. Teraz chcę przesunąć h1 nieco w dół, aby nie było tak blisko górnej krawędzi tła div, ale nie rozszerzać samego elementu h1. Chciałbym dodać górny margines. Co jest oczywiste. ale kiedy to robię, chwalebne tło postanawia zejść wraz z nim. Jak to jest funkcja. Jak to pomaga w odstępach między h1, h2 i p. Pomóż mi zobaczyć, co mówisz.
Muhammad Umer
1
Dodałem dla ciebie przykład
vdboor,
3
Spodziewałbym się, że zwiększy to marżę. załamywanie się marginesów jest zdecydowanie najbardziej irytujące w mojej karierze programistycznej. jeśli ustawię 2 div obok siebie z margin: 5px 10px;id, spodziewaj się 2 div 5 pikseli od góry i 20 pikseli między nimi, a nie 5 pikseli od góry i 10 pikseli między nimi. gdybym chciał między nimi 10 pikseli, podałem margin: 5px 5px;. Szczerze, żałuję, że nie istniała podstawowa zasada, która powstrzymałaby wszystkie marże. Nienawidzę tego, że muszę podwoić rozmiar marginesów na papierze, aby faktycznie zrobili to, co do cholery chcę na ekranie. i ta najważniejsza rzecz ... co za katastrofa
JL Griffin
50

Jest to normalne zachowanie (przynajmniej wśród implementacji przeglądarki). Margines nie wpływa na pozycję dziecka w stosunku do jego rodzica, chyba że rodzic ma wypełnienie, w którym to przypadku większość przeglądarek doda margines dziecka do wypełnienia rodzica.

Aby uzyskać pożądane zachowanie, potrzebujesz:

.child {
    margin-top: 0;
}

.parent {
    padding-top: 10px;
}
Ben James
źródło
3
Dodanie ramki do rodzica również wpłynie na margines dziecka, spróbuj.parent {border: solid 1px;}
okw
1
Margines nie dodaje się do wypełnienia ... stosuje się osobno. Ale efekt wizualny jest taki sam.
Brilliand
1
Co jeśli chcesz uzyskać najwyższy margines…? Niezupełnie rozwiązanie.
feeela 16.06.11
3
Jak powiedziała opłata - nie jest to tak naprawdę rozwiązanie, jeśli wymagana jest najwyższa marża. Odpowiedź vdboor pasuje lepiej.
Joey Morani,
1
Istnieje wiele rozwiązań, wystarczy być wystarczająco kreatywnym. Twoje zdrowie. :-)
Slavik Meltser
23

Chociaż wszystkie odpowiedzi rozwiązują ten problem, pochodzą one jednak z kompromisami / korektami / kompromisami

  • floatsTy masz się unosić elementy
  • border-top, Spycha to element nadrzędny co najmniej 1px w dół, co należy następnie wyregulować, wprowadzając -1pxmargines do samego elementu nadrzędnego. Może to powodować problemy, gdy rodzic ma już margin-topjednostki względne.
  • padding-top, taki sam efekt jak przy użyciu border-top
  • overflow: hiddenNie można używać, gdy rodzic powinien wyświetlać przepełnione treści, takie jak menu rozwijane
  • overflow: auto, Wprowadza paski przewijania dla elementu nadrzędnego, który ma (celowo) przepełnioną zawartość (jak cienie lub trójkąt etykietki)

Problem można rozwiązać za pomocą pseudoelementów CSS3 w następujący sposób

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

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

Ejaz
źródło
margin-top: -1pxwydaje się niepotrzebne. Ale podoba mi się to.
Flimm,
3
Faktycznie, zarówno margin-top: -1pxi height: 0wydaje się zbędne. Testowane w Chrome. Ale najlepsze rozwiązanie.
NinjaFart,
Ta metoda działa głównie, ale nie przestrzega dolnego marginesu dla ostatniego elementu w kontenerze. Przepełnienie nie jest równe: ukryte; na przykład.
Michael Giovanni Pumo
1
@MichaelGiovanniPumo odpowiedź można zmodyfikować, aby działała z dolnym marginesem ostatniego elementu za pomocą.parent:after...
Ejaz
Jest to obecnie zdecydowanie poprawna odpowiedź. Działa bezbłędnie (załóż go zarówno przed, jak i przed), mam nadzieję, że ludzie odważą się przewijać inne!
fgblomqvist
13

dodaj styl display:inline-blockdo elementu potomnego

Атанас Димитров
źródło
9

element nadrzędny nie musi być pusty przynajmniej &nbsp;przed elementem podrzędnym.

George SEDRA
źródło
2
tak, czasami tylko to może pomóc ... lub lepiej umieścić coś takiego: <div style = 'width: 0; height: 0'> & nbsp; </div>
Pigalev Pavel
7

To działało dla mnie

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

.child {
margin-top:260px;
}

http://jsfiddle.net/97fzwuxh/

erdomester
źródło
2

Okazuje się, że wewnątrz twojego pliku .css> jeśli ustawisz właściwość display elementu div na blok wbudowany, rozwiąże to problem. i margines będzie działał zgodnie z oczekiwaniami.

Vincent Thorpe
źródło
2

Zgrabne rozwiązanie tylko dla CSS

Użyj poniższego kodu, aby dołączyć bez zawartości pierwsze dziecko do niezamierzonego ruchu div:

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

Zaletą tej metody jest to, że nie trzeba zmieniać CSS żadnego istniejącego elementu, a zatem ma minimalny wpływ na projekt. Obok tego dodawany jest pseudoelement, którego nie ma w drzewie DOM.

Obsługa pseudo-elementów jest szeroko rozpowszechniona: Firefox 3+, Safari 3+, Chrome 3+, Opera 10+ i IE 8+. Będzie to działać w dowolnej nowoczesnej przeglądarce (uważaj na nowszą ::before, która nie jest obsługiwana w IE8).

Kontekst

Jeśli pierwsze dziecko elementu ma margin-top, rodzic dostosuje swoją pozycję jako sposób zwijania zbędnych marginesów. Dlaczego? Po prostu tak jest.

Biorąc pod uwagę następujący problem:

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

Możesz to naprawić, dodając dziecko z zawartością, na przykład prostą spacją. Ale wszyscy nienawidzimy dodawać spacji dla tego, co jest kwestią wyłącznie projektową. Dlatego użyj tej white-spacewłaściwości do sfałszowania treści.

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

Gdzie position: relative;zapewnia prawidłowe ustawienie poprawki. I white-space: pre;sprawia, że ​​nie musisz dodawać żadnych poprawek - takich jak białe znaki. I height: 0px;width: 0px;overflow: hidden;upewnia się, że nigdy nie zobaczysz poprawki.

W starożytnych przeglądarkach IE może być konieczne dodanie line-height: 0px;lub max-height: 0px;upewnienie się, że wysokość jest równa zero (nie jestem pewien). I opcjonalnie możesz dodać <!--dummy-->do niego w starych przeglądarkach IE, jeśli to nie działa.

Krótko mówiąc, możesz to wszystko zrobić tylko za pomocą CSS (co eliminuje potrzebę dodawania rzeczywistego potomka do drzewa 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>
Yeti
źródło
Używaj tego rozwiązania tylko, jeśli jesteś zdesperowany i nie możesz ustawić żadnego niestandardowego CSS dla istniejących elementów - w przeciwnym razie użyj prawdziwego rozwiązania: ustaw overflow: hidden;dla rodzica.
Yeti
2

Aby zapobiec „Div rodzic” użyj marginesu „div dziecko”:
W rodzicu użyj tych css:

  • Pływak
  • Wyściółka
  • Granica
  • Przelewowy
bingo
źródło
1

Zawarte marginw nim elementy .childsię zapadają.

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

W tym przykładzie podbiera marginz domyślnych stylów przeglądarki. Domyślna przeglądarka font-sizeto zwykle 16 pikseli. Mając margin-topponad 16px #child, zaczynasz zauważać, że zmienia się pozycja.

25. godzina
źródło
1

Miałem też ten problem, ale wolałem zapobiegać włamaniom do marży ujemnej, więc umieściłem

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

wokół tego wszystkiego, co ma wypełnienia zamiast marginesów. Oczywiście oznacza to więcej divitis, ale jest to prawdopodobnie najczystszy sposób, aby zrobić to poprawnie.

Zyl
źródło
1

co ciekawe, moje ulubione rozwiązanie tego problemu nie zostało jeszcze wspomniane: używanie pływaków.

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

zobacz tutaj: http://codepen.io/anon/pen/Iphol

zwróć uwagę, że jeśli potrzebujesz dynamicznej wysokości nadrzędnej, musi ona także unosić się, więc po prostu zamień height:100px;nafloat:left;

schellmax
źródło
1

Alternatywnym rozwiązaniem, które znalazłem, zanim poznałem prawidłową odpowiedź, było dodanie przezroczystej ramki do elementu nadrzędnego.

Twoje pudełko będzie jednak używać dodatkowych pikseli ...

.parent {
    border:1px solid transparent;
}
SandRock
źródło
0

Zastosowanie topzamiast margin-topjest innym możliwym rozwiązaniem, jeśli to właściwe.

lamplightdev
źródło