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

321

Intento agregar valores de margen en un div dentro de otro div. Todo funciona bien, excepto el valor superior, parece ser ignorado. ¿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>

W3Schools no tiene explicación de por qué el margen se comporta de esta manera.

jamietelin
fuente
44
¿Intentaste flotar el interior?
Gallo
66
hum .. Con float:left;esto funciona ... pero ¿por qué es esto necesario? No quiero que flote. ¿Y por qué funciona el margen para izquierda / derecha?
jamietelin 01 de
44
¡Bienvenido al divertido mundo del algoritmo de colapso del margen CSS!
GordonM
10
W3Schools vs. W3CDocs ... Creo que tenemos un ganador. : D
enderskill 01 de
15
jsFiddle, para salvar al siguiente chico 25 segundos jsfiddle.net/kLeu9
CodyBugstein

Respuestas:

453

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

Estos son los puntos relevantes de la especificación W3C:

8.3.1 Colapso de márgenes

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

Márgenes verticales adyacentes colapso [...]

Dos márgenes son contiguos si y solo si:

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

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

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

  • Los márgenes entre una caja flotante y cualquier otra caja no colapsan (ni siquiera entre una caja flotante y sus elementos secundarios en flujo).
  • Los márgenes de elementos que establecen nuevos contextos de formato de bloque (como flotantes y elementos con 'desbordamiento' que no sea 'visible') no colapsan con sus elementos secundarios en flujo.
  • Los márgenes de los cuadros de bloque en línea no se contraen (ni siquiera con sus elementos secundarios en flujo).

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

Los márgenes horizontales nunca colapsan.

BoltClock
fuente
12
Aparentemente, no eres el único que piensa que es estúpido ...
BoltClock
2
¡Esta respuesta es genial! Solo algo para agregar. Su cita de w3c lo dice pero solo me di cuenta ahora. Entonces, para ser claros para los demás, también podría darle a #outer un borde.
Driechel
El enlace en flotante parece estar roto.
EP
@episanty: Eso es lo que sucede cuando haces un enlace a un comentario. Desvinculado
BoltClock
Lo sé, solo quería hacerte saber. Como estás habilitado para ♦, pensé que querrías resucitar el comentario o cambiar tu publicación en consecuencia. Gracias por la buena respuesta, por cierto.
EP
92

Intenta usar display: inline-block;en el div interno.

#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
fuente
66
Buena respuesta. Sería mejor si explicara por qué este cambio soluciona el problema.
JohnFx
1
Ok, eso es extraño! ¿Por qué funciona eso? ¿Cuál es la explicación lógica de por qué no funciona como cabría esperar? El margen izquierdo / derecho funciona sin display:inline-block;. También retrasado para cuando se usa display:inline-block;es que pierde el ancho del 100% en el div.
jamietelin 01 de
3
cambiarlo a bloque en línea obliga al navegador a reevaluar el tamaño del div después de que se coloque y se apliquen otras reglas.
Gallo
Probé para mi problema, hizo un efecto de escalera.
Jonny
1
display:inline-blocktrabajó para mi. Muchas gracias.
starkeen el
24

Lo que @BoltClock mencionó es bastante sólido. Y aquí solo quiero agregar varias soluciones más para este problema. verifique este margen de colapso de w3c . Las partes verdes son el pensamiento potencial de cómo se puede resolver este problema.

Solución 1

Los márgenes entre una caja flotante y cualquier otra caja no colapsan (ni siquiera entre una caja flotante y sus elementos secundarios en flujo).

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

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

Solución 2

Los márgenes de elementos que establecen nuevos contextos de formato de bloque (como flotantes y elementos con 'desbordamiento' que no sea 'visible') no colapsan con sus elementos secundarios en flujo.

aparte de visible, pongamos 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 posicionadas absolutamente no colapsan (ni siquiera con sus hijos en flujo).

#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 de div

Solución 4

Los márgenes de los cuadros de bloque en línea no se contraen (ni siquiera con sus elementos secundarios en flujo).

es lo mismo que @enderskill

Solución 5

El margen inferior de un elemento de nivel de bloque en flujo siempre colapsa con el margen superior de su próximo hermano de nivel de bloque en flujo, a menos que ese hermano tenga espacio libre.

Esto no tiene mucho trabajo que ver con la pregunta, ya que es el margen de colapso entre hermanos. generalmente significa si una caja superior tiene margin-bottom: 30pxy una caja hermana tiene margin-top: 10px. El margen total entre ellos es en 30pxlugar de 40px.

Solución 6

El margen superior de un elemento de bloque en flujo se contrae con el primer margen superior del niño a nivel de bloque en flujo si el elemento no tiene borde superior, sin relleno superior y el niño 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;

}

Y también <div>está en el nivel de bloque predeterminado, por lo que no tiene que 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 sabes de dónde viene el problema la próxima vez que veas algo similar.

Qiang
fuente
14

No estoy seguro de por qué lo que tienes no funciona, pero puedes agregar

overflow: auto;

a la div exterior.

Brandon
fuente
Un montón de diferentes soluciones a este problema. ¡Gracias! Esta respuesta combinada con la respuesta de @ BoltClock proporciona buena información sobre por qué esta solución funciona.
jamietelin 01 de
12

Si agrega algún relleno #outer, funciona.

Manifestación

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:block;
    padding-top:1px;
}
bookcasey
fuente
11

No estoy seguro de por qué, pero cambiando el CSS interno a

display:inline-block;

parece funcionar;

harriyott
fuente
3

No responde el "por qué" (tiene que ser algo con un margen de colapso), pero parece que la forma más fácil / lógica de hacer lo que está tratando de hacer sería agregar padding-topal div externo :

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

Nota menor: no debería ser necesario establecer un div a display:block;menos que haya algo más en su código que le indique que no se bloquee.

Dave
fuente
3

prueba esto:

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

Buena suerte

Mustafa M Jalal
fuente
2

Supongo que establecer la propiedad de posición del #inner div en relativo también puede ayudar a lograr el efecto. Pero de todos modos probé el código original pegado en la Pregunta en IE9 y la última versión de Google Chrome y ya dan el efecto deseable sin ninguna modificación.

viditkothari
fuente
2

Uso padding-top:50pxpara div externo. Algo como esto:

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

Nota: el relleno aumentará el tamaño de tu div. En este caso, si el tamaño de su div es importante, quiero decir si debe tener una altura específica. disminuir la altura en 50 px .:

#outer {
    width:500px; 
    height:150px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:table;}
Ata Iravani
fuente
1

¿Has intentado! Importante antes de todo, forzará todo:

margin:50px 50px 50px 50px !important;
atgr24869
fuente
-1

Solo para una solución rápida, intente envolver los elementos secundarios en un divelemento como este:

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

El margen de innerdiv no colapsará debido al relleno de 1pxintermedios outery innerdiv. Entonces, lógicamente, tendrá 1pxespacio adicional junto con el margen existente de innerdiv.

Mithilesh Tipkari
fuente