Jak wyłączyć zwijanie marginesów?

202

Czy istnieje sposób na całkowite wyłączenie zwijania marginesów? Jedyne rozwiązania, które znalazłem (pod nazwą „unollapsing”) wymagają użycia obramowania 1px lub wypełnienia 1px. Uważam to za niedopuszczalne: obcy piksel komplikuje obliczenia bez uzasadnionego powodu. Czy istnieje bardziej rozsądny sposób na wyłączenie tego zwijania marginesów?

kjo
źródło
4
Użyj układu Flex lub Grid, w którym nie występuje zwijanie się marginesów: stackoverflow.com/a/46496701/3597276
Michael Benjamin
Po prostu podaj elementom wartość, margin-bottomale pozostaw margin-topjako 0.
Dan Bray
Zrobiłem pakiet, aby ułatwić obliczenia: npmjs.com/package/collapsed-margin
Owen M

Odpowiedzi:

254

Istnieją dwa główne rodzaje zwinięcia marginesów:

  • Zwijające się marginesy między sąsiadującymi elementami
  • Zwijane marginesy między elementami nadrzędnymi i podrzędnymi

Użycie wypełnienia lub ramki zapobiegnie zawaleniu się tylko w tym drugim przypadku. Ponadto każda wartość overflowinna niż wartość domyślna ( visible) zastosowana do elementu nadrzędnego zapobiegnie zwinięciu. Tak więc, zarówno overflow: autoi overflow: hiddenbędzie miał ten sam efekt. Być może jedyną różnicą podczas używania hiddenjest niezamierzona konsekwencja ukrywania treści, jeśli rodzic ma stałą wysokość.

Inne właściwości, które po zastosowaniu do elementu nadrzędnego mogą pomóc naprawić to zachowanie, to:

  • float: left / right
  • position: absolute
  • display: inline-block / flex

Możesz je przetestować tutaj: http://jsfiddle.net/XB9wX/1/ .

Powinienem dodać, że jak zwykle wyjątek stanowi Internet Explorer. Mówiąc dokładniej, marginesy w IE 7 nie ulegają zwinięciu, gdy dla elementu nadrzędnego określony jest jakiś układ, na przykład width.

Źródła: artykuł Sitepoint Zwijające się marginesy

hqcasanova
źródło
1
zwróć uwagę, że wypełnienie może również wpłynąć na to, jeśli nie jest wartością zerową
Mladen Janjetovic
3
Zauważ, że overflow: automoże to powodować wyświetlanie pasków przewijania w elemencie nadrzędnym, zamiast przepełnienia treści zgodnie z przepisem overflow: visible.
Leo
Wydaje się, że „przepełnienie: automatyczne” nie działa w Chrome v44.
tkane2000,
3
Dzięki za wyświetlenie: inline-block, to mnie uratowało :)
alexcasalboni
3
Każda wartość flexinna niż domyślna spowoduje również wyłączenie
zawijania
60

Możesz również użyć do tego starej dobrej mikro-poprawki.

#container:before, #container:after{
    content: ' ';
    display: table;
}

Zobacz zaktualizowane skrzypce: http://jsfiddle.net/XB9wX/97/

Blackgrid
źródło
Zamieniłem moją odpowiedź w wiki społeczności. Prosimy o rozszerzenie swojej odpowiedzi. Dzięki.
hqcasanova
3
Nie rozumiem, kiedy widzę ten przykład, marginesy się zapadają (tylko 10 pikseli pionowej przestrzeni między divami zamiast 20 pikseli)
Andy
1
Pomaga to tylko w usuwaniu zawalenia między rodzeństwem, które ma tę poprawkę Clearfix. Rozwinąłem przykład, aby to wykazać: jsfiddle.net/dpyuyg07 --- i nawet to nie jest cała historia. Usuwa tylko załamanie marginesów pochodzących od elementów potomnych elementów, w których zastosowano tę poprawkę. Jeśli dodasz margines na samym kontenerze, marginesy nadal zwiną się
NicBright
4
Mogę to ująć jeszcze precyzyjniej: metoda clearfix zapobiega jedynie zawaleniu się marginesu między rodzicami a dziećmi. Nie wpływa na załamanie między sąsiednim rodzeństwem.
NicBright,
Myślę, że teraz rozumiem tendencję Bootstrap do wypełniania DOM elementami :beforei :afterelementami. Mam teraz dodało ten przepis do mojego arkusza stylów: div:before, div:after{content: ' '; display: table;}. Fantastyczny. Nagle rzeczy zaczynają się zachowywać zgodnie z oczekiwaniami.
Stijn de Witt
59

Jedną zgrabną sztuczką, aby wyłączyć zwijanie marginesów, która nie ma wpływu wizualnego, o ile wiem, jest ustawienie dopełnienia elementu nadrzędnego na 0.05px:

.parentClass {
    padding: 0.05px;
}

Wypełnienie nie jest już równe 0, więc zapadanie się już nie występuje, ale jednocześnie wypełnienie jest wystarczająco małe, aby wizualnie zaokrąglić w dół do 0.

Jeśli pożądane jest inne wypełnienie, zastosuj wypełnienie tylko w „kierunku”, w którym na przykład nie jest wymagane zawijanie marginesu padding-top: 0.05px;.

Przykład roboczy:

.noCollapse {
  padding: 0.05px;
}

.parent {
  background-color: red;
  width: 150px;
}

.children {
  margin-top: 50px;

  background-color: lime;      
  width: 100px;
  height: 100px;
}
<h3>Border collapsing</h3>
<div class="parent">
  <div class="children">
  </div>
</div>

<h3>No border collapsing</h3>
<div class="parent noCollapse">
  <div class="children">
  </div>
</div>

Edycja: zmieniono wartość z 0.1na 0.05. Jak Chris Morgan wspomniał w komentarzu poniżej, i z tego małego testu wydaje się, że Firefox rzeczywiście bierze 0.1pxpod uwagę dopełnienie. Chociaż 0.05pxwydaje się , że załatwia sprawę.

Nicu Surdu
źródło
2
To jest moje ulubione rozwiązanie. Możesz nawet uwzględnić to jako styl domyślny. Dlaczego nie? *{padding-top:0.1px}. Czy jesteśmy pewni, że działa we wszystkich przeglądarkach?
Nick Manning
Do tej pory działało mi całkiem nieźle, ale nie twierdzę, że gruntownie go przetestowałem w większości przeglądarek.
Nicu Surdu,
2
Bardzo fajne rozwiązanie, wydaje się działać zgodnie z oczekiwaniami w większości przeglądarek. Dzięki za udostępnienie!
wiredolphin
1
To rozwiązanie jest ryzykowna, gdyż nie dodawać dodatkowych pikseli w różnych okolicznościach, ze względu na ekranach o wysokiej rozdzielczości DPI i obliczeń subpikseli. (Firefox tworzy układ subpikseli od wieków, uważam, że inne przeglądarki stosunkowo niedawno podążyły za nim.)
Chris Morgan,
0.05pxwydaje się nadal konkretnym wyborem, a nie przypadkowym numerem podstępnym przeglądarki, wolałbym 0.01px.
Volker E.
22

overflow:hidden zapobiega załamywaniu się marginesów, ale nie jest wolny od skutków ubocznych - mianowicie ... ukrywa przepełnienie.

Oprócz tego i tego, o czym wspomniałeś, musisz po prostu nauczyć się z tym żyć i uczyć się na ten dzień, kiedy są one naprawdę przydatne (przychodzi co 3 do 5 lat).

Litek
źródło
Zamieniłem moją odpowiedź w wiki społeczności. Wydaje mi się, że opisałem efekt uboczny, o którym wspomniałeś w dwóch ostatnich wierszach drugiego akapitu: Być może jedyną różnicą przy używaniu ukrytego jest niezamierzona konsekwencja ukrywania zawartości, jeśli rodzic ma ustaloną wysokość . Ale jeśli uważasz, że wymaga to dalszych wyjaśnień, prosimy o wkład. Dzięki.
hqcasanova
7
overflow: autodobrze jest użyć, aby zapobiec ukrytemu przepełnieniu i nadal zapobiegać zawaleniu się marginesów.
Gavin,
@Gavin, sprawiłem, overflow:auto;że mój obszar zawartości zyskał pasek przewijania na niektórych stronach.
Reed
13

W rzeczywistości istnieje taki, który działa bezbłędnie:

wyświetlacz: flex; kierunek zgięcia: kolumna;

tak długo, jak możesz żyć z obsługą tylko IE10 i nowszych wersji

.container {
  display: flex;
  flex-direction: column;
    background: #ddd;
    width: 15em;
}

.square {
    margin: 15px;
    height: 3em;
    background: yellow;
}
<div class="container">
    <div class="square"></div>
    <div class="square"></div>
    <div class="square"></div>
</div>
<div class="container">
    <div class="square"></div>
    <div class="square"></div>
    <div class="square"></div>
</div>

Daniel Koster
źródło
Aby działało to jako ogólne rozwiązanie, należy dodać dodatkowe <div>w .container, w przeciwnym razie .containerbędzie kontrolować model pudełkowy jego dzieci. Na przykład elementy wbudowane staną się elementami blokowymi o pełnej szerokości; jeśli mają marginesy, zostaną one również zwinięte.
zupa
9

Każda przeglądarka internetowa powinna obsługiwać właściwości -webkit-margin-collapse . Istnieją również właściwości podrzędne, aby ustawić go tylko dla górnego lub dolnego marginesu. Możesz nadać mu wartość zwinięcia (domyślnie), odrzucić (ustawia margines na 0, jeśli istnieje sąsiedni margines) i oddzielić (zapobiega zwinięciu marginesu).

Testowałem, że działa to w 2014 r. Wersjach Chrome i Safari. Niestety nie sądzę, że będzie to obsługiwane w IE, ponieważ nie jest oparte na webkit.

Zapoznaj się z dokumentacją CSS Safari firmy Apple, aby uzyskać pełne wyjaśnienie.

Jeśli sprawdzisz stronę z rozszerzeniami CSS Mozilli, podają one te właściwości jako zastrzeżone i zalecają ich nie używać. Wynika to z faktu, że prawdopodobnie nie zamierzają w najbliższym czasie przejść do standardowego CSS i będą obsługiwane tylko przeglądarki oparte na pakiecie internetowym.

Dan Carter
źródło
Jest to miłe, ponieważ pomaga nam wyeliminować niespójność w sposobie, w jaki Safari i Chrome radzą sobie z marżami.
bjudson,
8

Wiem, że jest to bardzo stary post, ale chciałem tylko powiedzieć, że użycie Flexboksa na elemencie nadrzędnym wyłączałoby zwijanie marginesów dla jego elementów potomnych.

Genzo
źródło
Nie tylko dla elementów potomnych - zapobiega również zawaleniu się marginesu między rodzicem a pierwszym i ostatnim dzieckiem.
Sven Marnach
2

Miałem podobny problem z załamaniem się marginesu, ponieważ rodzic positionustawił na krewnego. Oto lista poleceń, których można użyć do wyłączenia zwijania marginesów.

TU JEST PLAC ZABAW DO TESTOWANIA

Wystarczy spróbować przypisać dowolną parent-fix*klasę do div.containerelementu lub dowolnej klasy children-fix*do div.margin. Wybierz ten, który najlepiej odpowiada Twoim potrzebom.

Kiedy

  • Zwijanie marginesów jest wyłączone , div.absolutea czerwone tło zostanie umieszczone u góry strony.
  • margines jest zwinięty div.absolute zostanie ustawiony na tej samej współrzędnej Y codiv.margin

html, body { margin: 0; padding: 0; }

.container {
  width: 100%;
  position: relative;
}

.absolute {
  position: absolute;
  top: 0;
  left: 50px;
  right: 50px;
  height: 100px;
  border: 5px solid #F00;
  background-color: rgba(255, 0, 0, 0.5);
}

.margin {
  width: 100%;
  height: 20px;
  background-color: #444;
  margin-top: 50px;
  color: #FFF;
}

/* Here are some examples on how to disable margin 
   collapsing from within parent (.container) */
.parent-fix1 { padding-top: 1px; }
.parent-fix2 { border: 1px solid rgba(0,0,0, 0);}
.parent-fix3 { overflow: auto;}
.parent-fix4 { float: left;}
.parent-fix5 { display: inline-block; }
.parent-fix6 { position: absolute; }
.parent-fix7 { display: flex; }
.parent-fix8 { -webkit-margin-collapse: separate; }
.parent-fix9:before {  content: ' '; display: table; }

/* Here are some examples on how to disable margin 
   collapsing from within children (.margin) */
.children-fix1 { float: left; }
.children-fix2 { display: inline-block; }
<div class="container parent-fix1">
  <div class="margin children-fix">margin</div>
  <div class="absolute"></div>
</div>

Oto jsFiddle z przykładem, który możesz edytować

Buksy
źródło
1

W nowszej przeglądarce (z wyjątkiem IE11) można zastosować proste rozwiązanie zapobiegające zwijaniu marginesów rodzic-dziecko display: flow-root. Jednak nadal potrzebujesz innych technik, aby zapobiec zapadnięciu się sąsiedniego elementu.

DEMO (wcześniej)

.parent {
  background-color: grey;
}

.child {
  height: 16px;
  margin-top: 16px;
  margin-bottom: 16px;
  background-color: blue;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>

DEMO (po)

.parent {
  display: flow-root;
  background-color: grey;
}

.child {
  height: 16px;
  margin-top: 16px;
  margin-bottom: 16px;
  background-color: blue;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>

Chuanqi Sun
źródło
0

Dla twojej informacji możesz użyć siatki, ale z efektami ubocznymi :)

.parent {
  display: grid
}
Whisher
źródło