¿Cómo deshabilitar el colapso de margen?

203

¿Hay alguna manera de desactivar el colapso de margen por completo? Las únicas soluciones que he encontrado (por el nombre de "colapso") implican usar un borde de 1px o un relleno de 1px. Esto me parece inaceptable: el píxel extraño complica los cálculos sin una buena razón. ¿Hay alguna forma más razonable de desactivar este colapso de margen?

kjo
fuente
44
Use el diseño Flex o Grid, donde el colapso del margen no existe: stackoverflow.com/a/46496701/3597276
Michael Benjamin
Simplemente dale un valor a los elementos margin-bottompero déjalo margin-topcomo 0.
Dan Bray
Hice un paquete para facilitar el cálculo: npmjs.com/package/collapsed-margin
Owen M

Respuestas:

255

Hay dos tipos principales de colapso del margen:

  • Colapso de márgenes entre elementos adyacentes.
  • Colapso de márgenes entre elementos primarios y secundarios

El uso de un relleno o borde evitará el colapso solo en el último caso. Además, cualquier valor overflowdiferente de su valor predeterminado ( visible) aplicado al padre evitará el colapso. Por lo tanto, tanto overflow: autoy overflow: hiddentendrá el mismo efecto. Quizás la única diferencia cuando se usa hiddenes la consecuencia involuntaria de ocultar contenido si el padre tiene una altura fija.

Otras propiedades que, una vez aplicadas al padre, pueden ayudar a corregir este comportamiento son:

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

Puede probarlos todos aquí: http://jsfiddle.net/XB9wX/1/ .

Debo agregar que, como de costumbre, Internet Explorer es la excepción. Más específicamente, en IE 7 los márgenes no colapsan cuando se especifica algún tipo de diseño para el elemento padre, como width.

Fuentes: artículo de Sitepoint Márgenes colapsados

hqcasanova
fuente
1
tenga en cuenta que el relleno también puede afectar esto si no es un valor cero
Mladen Janjetovic
3
Tenga en cuenta que overflow: autopuede hacer que aparezcan barras de desplazamiento en el elemento primario, en lugar de permitir que el contenido se desborde, según lo establecido overflow: visible.
Leo
'desbordamiento: automático' no parece funcionar en Chrome v44.
tkane2000
3
Gracias por mostrar: bloque en línea, me salvó :)
alexcasalboni
3
Cualquier valor flexdiferente de su valor predeterminado también deshabilitará el colapso del margen
Oly
60

También puede usar el buen micro clearfix para esto.

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

Ver violín actualizado: http://jsfiddle.net/XB9wX/97/

Rejilla negra
fuente
He convertido mi respuesta en una wiki comunitaria. Por favor, siéntase libre de extenderlo con su respuesta. Gracias.
hqcasanova
3
No lo entiendo, cuando veo ese ejemplo, los márgenes se están colapsando (solo 10px de espacio vertical entre los divs en lugar de 20px)
Andy
1
Esto solo ayuda a eliminar el colapso entre hermanos a los que se les ha aplicado este clearfix. Bifurqué el ejemplo para demostrar esto: jsfiddle.net/dpyuyg07 --- e incluso esa no es toda la historia. Solo elimina el colapso de los márgenes derivados de los elementos secundarios en los que ha aplicado esa corrección. Si agregara un margen en el contenedor, los márgenes se colapsarían, lo que se puede ver en esta bifurcación: jsfiddle.net/oew7qsjx
NicBright
44
Puedo poner esto aún más precisamente: el método clearfix solo evita el colapso del margen entre padres e hijos. No afecta el colapso entre hermanos adyacentes.
NicBright
Creo que ahora entiendo la tendencia de Bootstrap para llenar el DOM con :beforey :afterelementos. Ahora he añadido esta regla a mi hoja de estilo: div:before, div:after{content: ' '; display: table;}. Fantástico. De repente, las cosas comienzan a comportarse como se esperaba.
Stijn de Witt
60

Un buen truco para deshabilitar el colapso del margen que no tiene impacto visual, que yo sepa, es configurar el relleno del padre para 0.05px:

.parentClass {
    padding: 0.05px;
}

El relleno ya no es 0, por lo que el colapso ya no ocurrirá, pero al mismo tiempo el relleno es lo suficientemente pequeño como para que visualmente se redondee a 0.

Si se desea algún otro relleno, aplique el relleno solo en la "dirección" en la que no se desea el colapso del margen, por ejemplo padding-top: 0.05px;.

Ejemplo de trabajo:

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

Editar: cambió el valor de 0.1a 0.05. Como Chris Morgan mencionó en un comentario a continuación, y de esta pequeña prueba , parece que, de hecho, Firefox toma 0.1pxen cuenta el relleno. Sin embargo, 0.05pxparece hacer el truco.

Nicu Surdu
fuente
2
Esta es mi solución favorita. Incluso podría incluir esto como un estilo predeterminado. Por qué no? *{padding-top:0.1px}. ¿Estamos seguros de que funciona en todos los navegadores?
Nick Manning
Hasta ahora funcionó bastante bien para mí, pero no pretendo haberlo probado exhaustivamente en la mayoría de los navegadores.
Nicu Surdu
2
Muy buena solución, parece funcionar como se esperaba en la mayoría de los navegadores. ¡Gracias por compartirlo!
wiredolphin
1
Esta es una solución poco fiables, ya que no añadir píxeles extra en diversas circunstancias, debido a la alta DPI pantallas y cálculos subpíxeles. (Firefox ha hecho un diseño de subpíxeles durante años, creo que otros navegadores han seguido el mismo camino en comparación).
Chris Morgan
0.05pxTodavía parece una opción específica, no un número de truco aleatorio del navegador, preferiría 0.01px.
Volker E.
22

overflow:hidden evita el colapso de los márgenes, pero no está libre de efectos secundarios, es decir, oculta el desbordamiento.

Aparte de esto y de lo que has mencionado, solo tienes que aprender a vivir con él y aprender para el día en que realmente sean útiles (viene cada 3 a 5 años).

Litek
fuente
He convertido mi respuesta en una wiki comunitaria. Creo que cubrí el efecto secundario que mencionó en las últimas dos líneas del segundo párrafo: Quizás la única diferencia cuando se usa oculto es la consecuencia no intencional de ocultar contenido si el padre tiene una altura fija . Pero si cree que necesita más aclaraciones, no dude en contribuir. Gracias.
hqcasanova
77
overflow: autoes bueno para evitar desbordamientos ocultos y aún así evitar márgenes de colapso.
Gavin
@Gavin, overflow:auto;hizo que mi área de contenido ganara una barra de desplazamiento en algunas páginas.
Reed
13

En realidad, hay uno que funciona perfectamente:

pantalla: flex; dirección flexible: columna;

siempre que pueda vivir con soporte solo para IE10 y hasta

.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
fuente
Para que esto funcione como una solución genérica, uno tiene que agregar un extra <div>dentro de .container, de lo contrario .containercontrolará el modelo de caja de sus hijos. Por ejemplo, los elementos en línea se convertirán en elementos de bloque de ancho completo; si tienen márgenes, también se colapsarán.
zupa
9

Todos los navegadores basados ​​en webkit deberían admitir las propiedades -webkit-margin-collapse. También hay subpropiedades para configurarlo solo para el margen superior o inferior. Puede darle el colapso de los valores (predeterminado), descartar (establece el margen en 0 si hay un margen adyacente) y separarlo (evita el colapso del margen).

He probado que esto funciona en las versiones 2014 de Chrome y Safari. Desafortunadamente, no creo que esto sea compatible con IE porque no está basado en webkit.

Lea la referencia CSS de Safari de Apple para obtener una explicación completa.

Si revisa la página de extensiones de webkit CSS de Mozilla , enumeran estas propiedades como propietarias y recomiendan no usarlas. Esto se debe a que probablemente no entrarán en CSS estándar en el corto plazo y solo los navegadores basados ​​en webkit los admitirán.

Dan Carter
fuente
Esto es bueno porque nos ayuda a resolver una inconsistencia en cómo Safari y Chrome manejan los márgenes.
bjudson
8

Sé que esta es una publicación muy antigua, pero solo quería decir que usar flexbox en un elemento primario deshabilitaría el colapso de margen para sus elementos secundarios.

Genzo
fuente
No solo para sus elementos secundarios, sino que también evita el colapso del margen entre el padre y el primer y último hijo.
Sven Marnach
2

Tuve un problema similar con el colapso del margen debido a que los padres se positionestablecieron en relativo. Aquí hay una lista de comandos que puede usar para deshabilitar el colapso de márgenes.

AQUÍ HAY JUEGO PARA PRUEBA

Solo intenta asignar cualquier parent-fix*clase a un div.containerelemento, o cualquier clase children-fix*a div.margin. Elija el que mejor se adapte a sus necesidades.

Cuando

  • el colapso del margen está deshabilitado , div.absolutecon el fondo rojo se colocará en la parte superior de la página.
  • el margen se contrae se div.absolute colocará en la misma coordenada Y quediv.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>

Aquí está jsFiddle con un ejemplo que puedes editar

Buksy
fuente
1

En el navegador más nuevo (excluyendo IE11), se usa una solución simple para evitar el colapso del margen padre-hijo display: flow-root. Sin embargo, aún necesitaría otras técnicas para evitar el colapso de elementos adyacentes.

DEMO (antes)

.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 (después)

.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
fuente
0

Para su información, podría usar la cuadrícula pero con efectos secundarios :)

.parent {
  display: grid
}
Whisher
fuente