Dlaczego ten styl marginesów CSS nie działa?

321

Próbuję dodać wartości marginesów do div wewnątrz innego div. Wszystko działa dobrze, z wyjątkiem najwyższej wartości, wydaje się być ignorowane. Ale dlaczego?

Czego się spodziewałem:
Czego się spodziewałem z marginesem: 50px 50px 50px 50px;

Co dostaję:
Co dostaję z marginesem: 50px 50px 50px 50px;

Kod:

#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 nie ma wyjaśnienia, dlaczego margines zachowuje się w ten sposób.

jamietelin
źródło
4
próbowałeś unieść wewnętrzną?
Kogut
6
przydźwięk ... Dzięki float:left;temu działa ... ale dlaczego jest to potrzebne. Nie chcę, żeby się unosiło. I dlaczego działa margines dla lewej / prawej?
jamietelin
44
Witamy w zabawnym świecie algorytmu zwinięcia marginesów CSS!
GordonM,
10
W3Schools vs. W3CDocs ... Myślę, że mamy zwycięzcę. : D
enderskill
15
jsFiddle tego, aby uratować następnego faceta 25 sekund jsfiddle.net/kLeu9
CodyBugstein

Odpowiedzi:

453

Rzeczywiście widzisz, jak górny margines #innerelementu zapada się w górną krawędź #outerelementu, pozostawiając tylko #outermargines nienaruszony (choć nie pokazano go na zdjęciach). Górne krawędzie obu pól są zrównane ze sobą, ponieważ ich marginesy są równe.

Oto odpowiednie punkty ze specyfikacji W3C:

8.3.1 Zwijane marginesy

W CSS przylegające marginesy dwóch lub więcej pól (które mogą, ale nie muszą być rodzeństwem) mogą łączyć się, tworząc jeden margines. Mówi się , że marginesy łączące się w ten sposób zwinięte , a wynikowy łączny margines nazywany jest marginesem zwiniętym .

Przyleganie do pionowych marginesów zwija się [...]

Dwa marginesy sąsiadują wtedy i tylko wtedy, gdy:

  • oba należą do pól na poziomie bloku przepływu, które uczestniczą w tym samym kontekście formatowania bloku
  • bez pól linii, bez prześwitu, bez wypełnienia i bez obramowania
  • oba należą do przylegających do siebie krawędzi pudełka, tj. tworzą jedną z następujących par:
    • górny margines pola i górny margines pierwszego elementu podrzędnego w przepływie

Możesz wykonać dowolną z następujących czynności, aby zapobiec zwijaniu się marginesu:

Powyższe opcje zapobiegają zwinięciu marginesu, ponieważ:

  • Marginesy między zmiennoprzecinkowym polem a dowolnym innym polem nie ulegają zwinięciu (nawet między zmiennoprzecinkowym a jego elementami potomnymi w przepływie).
  • Marginesy elementów, które ustanawiają nowe konteksty formatowania bloków (takie jak zmiennoprzecinkowe i elementy z „przepełnieniem” innym niż „widoczny”), nie ulegają zwinięciu wraz z ich potomkami w przepływie.
  • Marginesy pól bloków wstawianych nie zapadają się (nawet w przypadku ich potomków w przepływie).

Lewy i prawy margines zachowują się zgodnie z oczekiwaniami, ponieważ:

Poziome marginesy nigdy się nie zawalają.

BoltClock
źródło
12
Najwyraźniej nie tylko ty myślisz, że to głupie ...
BoltClock
2
Ta odpowiedź się kołysze! Po prostu coś do dodania. Twój cytat w3c mówi to, ale dopiero teraz zrozumiałem. Żeby było jasne dla innych, możesz także wyznaczyć #outer granicę.
driechel
Link w pływającym wydaje się być zepsuty.
EP
@episanty: Tak się dzieje, gdy link do komentarza. Niepowiązane
BoltClock
Wiem - chciałem cię tylko poinformować. Ponieważ masz włączoną opcję ♦ Pomyślałem, że możesz wskrzesić komentarz - lub odpowiednio zmienić swój post. Nawiasem mówiąc, dzięki za dobrą odpowiedź.
EP
92

Spróbuj użyć display: inline-block;na wewnętrznej div.

#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;
}
enderskill
źródło
6
Dobra odpowiedź. Byłoby lepiej, gdyby wyjaśnił, dlaczego ta zmiana rozwiązuje problem.
JohnFx
1
Ok, to dziwne! Dlaczego to działa? Jakie jest logiczne wytłumaczenie, dlaczego nie działa tak, jak można się spodziewać. Margines lewy / prawy działa bez display:inline-block;. Cofnij się również, gdy używasz, display:inline-block;ponieważ tracisz szerokość 100% na div.
jamietelin
3
przełączenie na blok wbudowany zmusza przeglądarkę do ponownej oceny rozmiaru div po jego umieszczeniu i zastosowaniu innych reguł.
Kogut
Wypróbowałem to na mój problem, zrobiłem efekt schodów.
Jonny,
1
display:inline-blockpracował dla mnie. Dziękuję bardzo.
starkeen
24

To, o czym wspominał @BoltClock, jest dość solidne. A tutaj chcę tylko dodać kilka innych rozwiązań tego problemu. sprawdź ten margines w3c_collapsing . Zielone części są potencjalną myślą, jak rozwiązać ten problem.

Rozwiązanie 1

Marginesy między zmiennoprzecinkowym polem a dowolnym innym polem nie ulegają zwinięciu (nawet między zmiennoprzecinkowym a jego elementami potomnymi w przepływie).

Oznacza to, że można dodać float:leftdo jednej #outerlub #inner demo1 .

zauważ również, floatże unieważniłoby to automargines.

Rozwiązanie 2

Marginesy elementów, które ustanawiają nowe konteksty formatowania bloków (takie jak zmiennoprzecinkowe i elementy z „przepełnieniem” innym niż „widoczny”), nie ulegają zwinięciu wraz z ich potomkami w przepływie.

inne niż visible, umieścić Chodźmy overflow: hiddendo #outer. I ten sposób wydaje się dość prosty i przyzwoity. Lubię to.

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

Rozwiązanie 3

Marginesy absolutnie pozycjonowanych pudełek nie zapadają się (nawet w przypadku dzieci przepływających).

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

lub

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

te dwie metody spowodują przerwanie normalnego przepływu div

Rozwiązanie 4

Marginesy pól bloków wstawianych nie zapadają się (nawet w przypadku ich potomków w przepływie).

jest taki sam jak @enderskill

Rozwiązanie 5

Dolny margines elementu na poziomie bloku przepływu zawsze zapada się wraz z górnym marginesem następnego rodzeństwa na poziomie bloku przepływu, chyba że ma on prześwit.

Nie ma to wiele wspólnego z tym pytaniem, ponieważ jest to zawalający się margines między rodzeństwem. ogólnie oznacza to, że ma górne pudełko margin-bottom: 30pxi ma rodzeństwo margin-top: 10px. Całkowity margines między nimi jest 30pxzamiast 40px.

Rozwiązanie 6

Górny margines elementu blokującego przepływ zapada się wraz z górnym marginesem potomnym pierwszego bloku przepływowego, jeśli element nie ma górnej granicy, górnego wypełnienia, a dziecko nie ma luzu.

To bardzo interesujące i mogę po prostu dodać jedną górną linię graniczną

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

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

}

A także <div>domyślnie jest na poziomie bloku, więc nie musisz celowo go deklarować. Przepraszam, że nie mogłem opublikować więcej niż 2 linków i zdjęć z powodu mojej reputacji początkującego. Przynajmniej wiesz, skąd pochodzi problem, kiedy następnym razem zobaczysz coś podobnego.

Qiang
źródło
14

Nie wiesz, dlaczego to, co masz, nie działa, ale możesz dodać

overflow: auto;

do zewnętrznej div.

Brandon
źródło
Mnóstwo różnych rozwiązań tego problemu. Dzięki! Ta odpowiedź w połączeniu z odpowiedzią @ BoltClock dostarcza dobrych informacji na temat tego, dlaczego to rozwiązanie działa.
jamietelin
12

Jeśli dodasz padding #outer, działa.

Próbny

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:block;
    padding-top:1px;
}
regał na książki
źródło
11

Nie jestem pewien, dlaczego, ale zmieniając wewnętrzny CSS na

display:inline-block;

wydaje się działać;

harriyott
źródło
3

Nie odpowiada na „dlaczego” (musi to być coś z zawalającym się marginesem), ale wydaje się, że najłatwiejszym / najbardziej logicznym sposobem na zrobienie tego, co próbujesz zrobić, byłoby dodanie padding-topdo zewnętrznego div :

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

Drobna uwaga - ustawianie div nie powinno być konieczne, display:block;chyba że w twoim kodzie jest coś innego, co mówi, żeby nie blokować.

Dave
źródło
3

Spróbuj tego:

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

Powodzenia

Mustafa M. Jalal
źródło
2

Wydaje mi się, że ustawienie właściwości position #inner div na relative może również pomóc osiągnąć ten efekt. Ale w każdym razie próbowałem oryginalnego kodu wklejonego w pytaniu na IE9 i najnowszej przeglądarce Google Chrome i już dają pożądany efekt bez żadnych modyfikacji.

viditkothari
źródło
2

Użyj padding-top:50pxdla zewnętrznego div. Coś takiego:

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

Uwaga: wypełnienie zwiększy rozmiar div. W tym przypadku, jeśli rozmiar twojego div jest ważny, mam na myśli, czy musi on mieć określoną wysokość. zmniejsz wysokość o 50px .:

#outer {
    width:500px; 
    height:150px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:table;}
Ata Iravani
źródło
1

Próbowałeś! Ważne przede wszystkim, to wymusi wszystko:

margin:50px 50px 50px 50px !important;
atgr24869
źródło
-1

Dla szybkiej naprawy spróbuj owinąć elementy potomne w divelement taki jak ten -

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

Margines innerdiv nie spadnie z powodu wypełnienia 1pxmiędzy outeri innerdiv. Więc logicznie będziesz miał 1pxdodatkowe miejsce wraz z istniejącym marginesem innerdiv.

Mithilesh Tipkari
źródło