Margen superior empuje hacia abajo div div

126

Tengo un div de encabezado como primer elemento en mi div de contenedor, pero cuando agrego un margen superior a un h1 dentro del div de encabezado, empuja hacia abajo todo el div de encabezado. Me doy cuenta de que esto sucede cada vez que aplico un margen superior al primer elemento visible en una página.

Aquí hay un fragmento de código de muestra. ¡Gracias!

div#header{
	width: 100%;
	background-color: #eee;
	position: relative;
}

div#header h1{
	text-align: center;
	width: 375px;
	height: 50px;
	margin: 50px auto;
	font-size: 220%;
	background: url('../../images/name_logo.png') no-repeat;
}
<div id="header">
	<h1>Title</h1>
	<ul id="navbar"></ul>
</div>

Danny
fuente

Respuestas:

193

poner overflow:autoen el padre div
ver más en este enlace

Juan Pablo
fuente
29
overflow:hiddenes mejor para el 90% de los casos.
vsync
1
¿Por qué desbordar: oculto sería mejor?
Peter
55
@peterchon - porque auto puede causar barras de desplazamiento
vsync
3
ya no funciona, la respuesta de @ SW4 en este enlace es mejor
am05mhz
1
overflow: hiddeno overflow: autopuede causar efectos secundarios no deseados, algunos de los cuales puede que no vea a primera vista. Descubrí que cambiar margina paddinghace el truco, como sugiere la respuesta a continuación. Sin embargo, todavía no entiendo por qué ocurre todo el problema.
Gilad Barner
34

No tengo una explicación sólida de por qué sucede esto, pero lo arreglé cambiando el top-margina top-paddingo agregando display: inline-blockal estilo del elemento.

EDITAR: Esta es mi teoría

Tengo la sensación de que tiene algo que ver con cómo se colapsan (combinan) los márgenes.

de los márgenes de colapso del W3C :

En esta especificación, los márgenes de colapso de la expresión significan que los márgenes adyacentes (sin contenido no vacío, relleno o áreas de borde o espacio separado) de dos o más cuadros (que pueden estar uno al lado del otro o anidados) se combinan para formar un margen único .

Mi teoría es que dado que su primer elemento está al lado del cuerpo, los dos márgenes se combinan y se aplican al cuerpo: esto obliga al contenido del cuerpo a comenzar por debajo del margen colapsado aplicado de acuerdo con el modelo de caja .

Hay situaciones en las que los márgenes no colapsan con los que podría valer la pena jugar (desde Márgenes contraídos ):

* floated elements
* absolutely positioned elements
* inline-block elements
* elements with overflow set to anything other than visible (They do not collapse margins with their children.)
* cleared elements (They do not collapse their top margins with their parent block’s bottom margin.)
* the root element
soñador digital
fuente
3
Además, el relleno o borde en el elemento con margen contraído (el interior) lo destrabará.
Anónimo
Esto funcionó para mí: tenía elementos absolutos (un menú desplegable) en mi contenedor, así que desbordamiento: auto no funcionó.
mwilcox
17

Estas son algunas de las formas de evitar el colapso del margen entre los elementos padre-hijo. Use el que mejor se adapte al resto de su estilo:

  • Establecer displayen otro que block.
  • Establecer floaten otro que none.
  • Elimine el margen y utilícelo en su lugar padding. Por ejemplo, si tuviera margin-top: 10px, reemplace con padding-top: 10px;.
  • Retire el margen, y usar en su lugar position( absoluteo relative) con los atributos top, bottometc. Por ejemplo, si tiene margin-top: 10px, reemplazar con position: relative; top: 10px;.
  • Agregue a paddingo a borderen el lado donde se contraen los márgenes, al elemento padre . El borde puede ser 1px y transparente.
  • Establecer overflowen otro que no sea visibleel elemento padre .
Jesús Carrera
fuente
5

Sé que este es un problema antiguo, lo he encontrado muchas veces. El problema es que todas las soluciones aquí son hacks que podrían tener consecuencias no deseadas.

En primer lugar, hay una explicación fácil para el problema raíz. Debido a la forma en que funciona el colapso del margen, si el primer elemento dentro de un contenedor tiene un margen superior, ese margen superior se aplica efectivamente al contenedor principal. Puede probar esto por su cuenta haciendo lo siguiente:

<div>
    <h1>Test</h1>
</div>

En un depurador, abra esto y desplace el div. Notarás que el div en sí se coloca donde se detiene el margen superior del elemento H1 . Este comportamiento está previsto por el navegador.

Entonces, hay una solución fácil para esto sin tener que recurrir a hacks extraños, como lo hacen la mayoría de las publicaciones aquí (sin insultos, es solo la verdad) - simplemente regrese a la explicación original - ...if the first element inside a container has a top margin...- Después de eso, necesitaría El primer elemento en un contenedor que NO tiene un margen superior. De acuerdo, pero ¿cómo lo haces sin agregar elementos que no interfieran semánticamente con tu documento?

¡Fácil! Pseudo-elementos! Puede hacerlo a través de una clase o un mixin predefinido. Añadir un :beforepseudo-elemento:

CSS a través de una clase:

.top-margin-fix:before {   
    content: ' ';
    display: block;
    width: 100%;
    height: .0000001em;
}

Con esto, siguiendo el ejemplo de marcado anterior, modificaría su div como tal:

<div class="top-margin-fix">
    <h1>Test</h1>
</div>

¿Por qué funciona esto?

El primer elemento en un contenedor, si no tiene margen superior, establece la posición del inicio del margen superior del siguiente elemento. Al agregar un :beforepseudo-elemento, el navegador agrega un elemento no semántico (en otras palabras, bueno para SEO) en el contenedor principal antes de su primer elemento.

P. ¿Por qué la altura: .0000001em?

A. Se requiere una altura para que el navegador empuje el elemento de margen hacia abajo. Esta altura es efectivamente cero, pero aún le permitirá agregar relleno al contenedor principal. Como es efectivamente cero, tampoco tendrá un efecto en el diseño del contenedor. Hermoso.

Ahora puede agregar una clase (¡o mejor, en SASS / LESS, un mixin!) Para solucionar este problema en lugar de agregar estilos de visualización extraños que causarán consecuencias inesperadas cuando desee hacer otras cosas con sus elementos, eliminando deliberadamente los márgenes en los elementos y / o reemplazarlo con relleno, o estilos extraños de posición / flotación que realmente no están destinados a resolver este problema.

amigo
fuente
2
El .0000001em realmente se redondea a cero en IE11, rompiendo su solución. Sin embargo, cuando lo cambio a .01em funciona.
Esger
1
Me imagino que .01em será suficiente para seguir siendo efectivamente cero. Buen punto. Por el lado positivo, ahora que es 2018, muchos de nosotros dejaremos de admitir IE11 pronto, especialmente con el reciente anuncio de que MS volverá a construir un nuevo navegador (excepto esta vez, basado en cromo, lo que significa que, en teoría - No apestará totalmente). : D
dudewad
2

display: flexFuncionará en este caso. Proporcione el elemento principal display: flex;y luego otorgue margen según su requisito para la h1etiqueta.

Bijay
fuente
0

Se encuentra con este problema hoy.

overflow: hidden no funcionó como se esperaba cuando me siguieron más elementos.

¡Así que intenté cambiar la propiedad de visualización del div padre y display: flexfuncioné!

Espero que esto pueda ayudar a alguien. :)

Libin
fuente
0

Agregar un poco de relleno al elemento principal superior puede solucionar este problema.

.parent{
  padding-top: 0.01em;
}

Esto es útil si necesita que un elemento dentro del elemento primario sea visible fuera del elemento primario, como si está creando un efecto superpuesto.

adamspruijt
fuente
0

Esto sucede debido al colapso del margen. Cuando el elemento hijo toca el límite del elemento padre y cualquiera de ellos se aplica con márgenes, entonces:

  1. El margen que sea más grande ganará (aplicado).

  2. si alguno de ellos tiene margen, ambos compartirán lo mismo.

Soluciones

  1. aplica un borde al padre que hace que el padre y el niño se separen.
  2. aplique relleno al padre, lo que hace que el padre y el niño se separen.
  3. aplicar desbordamiento en lugar de visible en el padre.
  4. use antes o después para crear un elemento virtual en el elemento primario div que puede diferir en el margen aplicado secundario y primario.
  5. crear un elemento html entre el margen aplicado secundario y primario también puede separarlos.
Ishu
fuente