¿Por qué este estilo CSS de margen superior no funciona?

Resuelto lejahmie asked hace 12 años • 14 respuestas

Intenté agregar marginvalores dentro divde otro div. Todo funciona bien excepto el valor superior, que parece ignorarse. ¿Pero por qué?

Lo que esperaba:
Lo que esperaba con margen:50px 50px 50px 50px;

Lo que consigo:
Lo que obtengo con margen:50px 50px 50px 50px;

Código:

#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>
Expandir fragmento

W3Escuelas no tiene explicación de por qué marginse comporta de esta manera.

lejahmie avatar Mar 01 '12 23:03 lejahmie
Aceptado

En realidad, estás viendo que el margen superior del #innerelemento colapsa en el borde superior del #outerelemento, dejando solo el #outermargen intacto (aunque no se muestra en tus imágenes). Los bordes superiores de ambas cajas están alineados entre sí porque sus márgenes son iguales.

Aquí están los puntos relevantes de la especificación W3C:

8.3.1 Márgenes colapsados

En CSS, los márgenes contiguos de dos o más cuadros (que pueden ser hermanos o no) se pueden combinar para formar un único margen. Se dice que los márgenes que se combinan de esta manera colapsan y el margen combinado resultante se denomina margen colapsado .

Los márgenes verticales contiguos colapsan [...]

Dos márgenes son contiguos si y sólo si:

  • ambos pertenecen a cuadros de nivel de bloque de flujo entrante que participan en el mismo contexto de formato de bloque
  • sin cuadros de línea, sin espacio libre, sin relleno y sin borde que los separe
  • ambos pertenecen a bordes de caja verticalmente adyacentes, es decir, forman uno de los siguientes pares:
    • margen superior de una caja y margen superior de su primer hijo entrante

Puede realizar cualquiera de las siguientes acciones para evitar que el margen colapse:

  • Flota cualquiera de tus divelementos
  • Haga cualquiera de sus divelementos en bloques en línea
  • Conjunto overflowde #outeraauto (o cualquier valor distinto de visible)

La razón por la que las opciones anteriores evitan que el margen colapse es porque:

  • Los márgenes entre un cuadro flotante y cualquier otro cuadro no colapsan (ni siquiera entre un cuadro flotante y sus hijos de flujo entrante).
  • Los márgenes de los elementos que establecen nuevos contextos de formato de bloque (como flotantes y elementos con un "desbordamiento" distinto de "visible") no colapsan con sus hijos entrantes.
  • Los márgenes de las cajas de bloques en línea no colapsan (ni siquiera con sus hijos de flujo entrante).

Los márgenes izquierdo y derecho se comportan como se espera porque:

Los márgenes horizontales nunca colapsan.

BoltClock avatar Mar 01 '2012 16:03 BoltClock

Intente usarlo display: inline-block;en el interior div. Al igual que:

#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 avatar Mar 01 '2012 16:03 enderskill

La respuesta de BoltClock es bastante sólida. Aquí solo quiero agregar varias soluciones más para este problema. marque este margen w3c_collapsing . Las partes verdes son la idea potencial de cómo se puede resolver este problema.

Solución 1

Los márgenes entre un cuadro flotante y cualquier otro cuadro no colapsan (ni siquiera entre un cuadro flotante y sus hijos de flujo entrante).

eso significa que puedo agregar float:lefta cualquiera de los dos #outero #inner demo1 .

También tenga en cuenta que eso floatinvalidaría el automargen interior.

Solución 2

Los márgenes de los elementos que establecen nuevos contextos de formato de bloque (como flotantes y elementos con un "desbordamiento" distinto de "visible") no colapsan con sus hijos entrantes.

aparte de visible, pongámoslo overflow: hiddenen #outer. Y de esta manera parece bastante simple y decente. Me gusta.

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

Solución 3

Los márgenes de las cajas absolutamente posicionadas no colapsan (ni siquiera con sus hijos entrantes).

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

o

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

Estos dos métodos romperán el flujo normal dediv

Solución 4

Los márgenes de las cajas de bloques en línea no colapsan (ni siquiera con sus hijos de flujo entrante).

es lo mismo que enderskill

Solución 5

El margen inferior de un elemento a nivel de bloque de flujo entrante siempre colapsa con el margen superior de su siguiente elemento hermano a nivel de bloque de flujo entrante, a menos que ese hermano tenga autorización.

Esto no tiene mucho que ver con la pregunta, ya que se trata del margen de colapso entre hermanos. generalmente significa si un top-box tiene margin-bottom: 30pxy un hermano-box tiene margin-top: 10px. El margen total entre ellos es 30pxen lugar de 40px.

Solución 6

El margen superior de un elemento de bloque de flujo entrante se colapsa con el margen superior de su primer elemento secundario a nivel de bloque de flujo entrante si el elemento no tiene borde superior ni relleno superior y el elemento secundario no tiene espacio libre.

Esto es muy interesante y solo puedo agregar una línea de borde superior.

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

Además, <div>está a nivel de bloque de forma predeterminada, por lo que no es necesario declararlo a propósito. Perdón por no poder publicar más de 2 enlaces e imágenes debido a mi reputación de novato. Al menos sabrás de dónde viene el problema la próxima vez que veas algo similar.

Qiang avatar Jun 09 '2015 22:06 Qiang

No estoy seguro de por qué lo que tienes no funciona, pero puedes agregarlo overflow: auto;al exterior div.

Brandon avatar Mar 01 '2012 16:03 Brandon