El margen en el elemento hijo mueve el elemento padre

415

Tengo un div( padre ) que contiene otro div( hijo ). Parent es el primer elemento bodysin un estilo CSS particular. Cuando configuro

.child
{
    margin-top: 10px;
}

El resultado final es que la parte superior de mi hijo todavía está alineada con el padre. En lugar de que el niño se mueva 10px hacia abajo, mi padre se mueve 10px hacia abajo.

Mi DOCTYPEestá configurado para XHTML Transitional.

¿Que me estoy perdiendo aqui?

edit 1
Mi padre necesita tener dimensiones estrictamente definidas porque tiene un fondo que se debe mostrar debajo de arriba a abajo (píxel perfecto). Por lo tanto, establecer márgenes verticales es imposible .

edit 2
Este comportamiento es el mismo en FF, IE y CR.

Robert Koritnik
fuente
188
Este comportamiento no tiene ningún sentido. Se supone que el margen debe permanecer dentro del padre. No mover al padre. ¿Quién escribe estas reglas?
Muhammad Umer
10
+2 para el último comentario. En serio, esta regla me molesta. "El 60% de las veces funciona todo el tiempo", eso es un margen.
Casey Dwayne
29
Estoy totalmente de acuerdo con los dos últimos comentaristas. Esto es una locura. Lo interesante es que agregar un borde de 1px al padre hace que funcione correctamente, sin embargo, esto significa que tiene un borde ... si este es el comportamiento esperado, entonces esto es ridículo
erdomester
1
Esto también puede ayudarte :) stackoverflow.com/questions/35337043/…
Bhojendra Rauniyar
55
Esto me recuerda la regla de tamaño de caja predeterminada: " Necesitamos enviar una caja. La caja no debe ser mayor de 100 cm. Necesitamos 10 cm de relleno dentro de la caja para garantizar que nuestro contenido no se rompa durante el envío. Hagamos la caja de 120cm! "Que broma.
Nolonar

Respuestas:

492

Encontró una alternativa en elementos secundarios con márgenes dentro de DIV También puede agregar:

.parent { overflow: auto; }

o:

.parent { overflow: hidden; }

Esto evita que los márgenes colapsen . El borde y el relleno hacen lo mismo. Por lo tanto, también puede usar lo siguiente para evitar un colapso del margen superior:

.parent {
    padding-top: 1px;
    margin-top: -1px;
}

Actualización por solicitud popular: el objetivo de contraer los márgenes es manejar el contenido textual. Por ejemplo:

h1, h2, p, ul {
  margin-top: 1em;
  margin-bottom: 1em;
}
<h1>Title!</h1>
<div class="text">
  <h2>Title!</h2>
  <p>Paragraph</p>
</div>
<div class="text">
  <h2>Title!</h2>
  <p>Paragraph</p>
  <ul>
    <li>list item</li>
  </ul>
</div>

Debido a que el navegador contrae los márgenes, el texto aparecería como era de esperar, y las <div>etiquetas del contenedor no influyen en los márgenes. Cada elemento asegura que tiene espacio alrededor, pero el espacio no se duplicará. Los márgenes de <h2>y <p>no se suman, pero se deslizan entre sí (colapsan). Lo mismo sucede para el elemento <p>y <ul>.

Lamentablemente, con diseños modernos, esta idea puede morderte cuando quieres explícitamente un contenedor. Esto se llama un nuevo contexto de formato de bloque en CSS speak. El overflowtruco o margen te dará eso.

vdboor
fuente
41
Quiero saber por qué sucede esto, qué bien le hace esto a alguien. En qué situación se suponía que debía estar esta 'característica'.
Muhammad Umer
2
@MuhammadUmer, bueno, esto tiene que ver con el contenido del texto. Por ejemplo, una serie de <h2>, <p>, <ul>no obtendrá lagunas extrañas o márgenes "doble" de esta manera.
vdboor
77
¿Podrías dar algún ejemplo? Digamos que tengo div como fondo. Con h1, h2 y p en él. Ahora quiero mover h1 un poco hacia abajo para que no esté tan cerca del borde superior del div de fondo, pero no expandir el elemento h1 en sí. Creo que añadir margen superior. Lo cual es obvio. pero cuando hago eso, el glorioso fondo decide moverse hacia abajo con él. Cómo esta es una característica. Cómo esto ayuda en el espacio entre h1, h2 y p. Ayúdame a ver lo que estás diciendo.
Muhammad Umer
1
He agregado un ejemplo para usted
vdboor
3
esperaría que agregue más margen. colapsar los márgenes es, con mucho, lo más molesto en mi carrera de desarrollo. si pongo 2 divs uno al lado del otro con margin: 5px 10px;id, espere 2 divs 5 px desde la parte superior y 20 px entre ellos, no 5 px desde la parte superior y 10 px entre ellos. si quisiera 10 px entre ellos, la id lo habría especificado margin: 5px 5px;. Sinceramente, desearía que hubiera una regla raíz que pudiera colocar que detuviera todo colapso de margen Odio tener que duplicar el tamaño de los márgenes en papel para hacer que realmente hagan lo que quiero en la pantalla. y lo mejor ... qué desastre
JL Griffin
50

Este es un comportamiento normal (al menos entre las implementaciones del navegador). El margen no afecta la posición del niño en relación con su padre, a menos que el padre tenga relleno, en cuyo caso la mayoría de los navegadores agregarán el margen del niño al relleno del padre.

Para obtener el comportamiento que desea, necesita:

.child {
    margin-top: 0;
}

.parent {
    padding-top: 10px;
}
Ben James
fuente
3
La adición de frontera para el padre afectará margen del niño también, tratar.parent {border: solid 1px;}
okw
1
El margen no se agrega al relleno ... se aplica por separado. Pero el efecto visual es el mismo.
Brilliand
1
¿Qué pasa si quieres un margen superior ...? Realmente no es una solución.
feeela
3
Como dijo Feeela: esta no es realmente una solución si se requiere un margen superior. La respuesta de vdboor se adapta mejor.
Joey Morani
1
Hay un montón de soluciones, solo necesitas ser lo suficientemente creativo. Salud. :-)
Slavik Meltser
24

Aunque todas las respuestas solucionan el problema, vienen con compensaciones / ajustes / compromisos como

  • floats, Usted tiene que flotar elementos
  • border-top, Esto empuja al padre al menos 1px hacia abajo, que luego debe ajustarse introduciendo -1pxmargen al elemento padre en sí. Esto puede crear problemas cuando el padre ya tiene margin-topunidades relativas.
  • padding-top, el mismo efecto que usar border-top
  • overflow: hidden, No se puede usar cuando el padre debe mostrar contenido desbordado, como un menú desplegable
  • overflow: auto, Presenta barras de desplazamiento para el elemento principal que tiene (intencionalmente) contenido desbordado (como sombras o triángulo de información sobre herramientas)

El problema se puede resolver utilizando pseudo elementos CSS3 de la siguiente manera

.parent::before {
  clear: both;
  content: "";
  display: table;
  margin-top: -1px;
  height: 0;
}

https://jsfiddle.net/hLgbyax5/1/

Ejaz
fuente
margin-top: -1pxParece ser innecesario. Pero me gusta esto.
Flimm
3
En realidad, ambos margin-top: -1pxy height: 0parece innecesario. Probado en cromo. Pero la mejor solución.
NinjaFart
Este método funciona principalmente, pero no respetará el margen inferior para el último elemento dentro del contenedor. No es una solución igual al desbordamiento: oculto; por ejemplo.
Michael Giovanni Pumo el
1
@MichaelGiovanniPumo la respuesta puede ser modificado para trabajar con margen inferior del último elemento mediante el uso.parent:after...
Ejaz
Esta es definitivamente la respuesta correcta hoy en día. Funciona sin problemas (póntelo tanto antes como después), ¡espero que la gente se atreva a pasar a los demás!
fgblomqvist
13

agregar estilo display:inline-blockal elemento hijo

Атанас Димитров
fuente
9

el elemento padre no debe estar vacío al menos &nbsp;antes del elemento hijo.

George SEDRA
fuente
2
sí, a veces solo esto puede ayudar ... o mejor poner algo como esto: <div style = 'width: 0; height: 0'> & nbsp; </div>
Pigalev Pavel
2

Descubro que, dentro de su .css> si configura la propiedad de visualización de un elemento div para bloquear en línea , soluciona el problema. y el margen funcionará como se espera.

Vincent Thorpe
fuente
2

Solución ordenada solo para CSS

Use el siguiente código para anteponer un primer hijo sin contenido al div que se mueve involuntariamente:

.parent:before
{content: '';position: relative;height: 0px;width: 0px;overflow: hidden;white-space: pre;}

La ventaja de este método es que no necesita cambiar el CSS de ningún elemento existente y, por lo tanto, tiene un impacto mínimo en el diseño. Junto a esto, el elemento que se agrega es un pseudo-elemento, que no está en el árbol DOM.

El soporte para pseudo-elementos está muy extendido: Firefox 3+, Safari 3+, Chrome 3+, Opera 10+ e IE 8+. Esto funcionará en cualquier navegador moderno (tenga cuidado con el más nuevo ::before, que no es compatible con IE8).

Contexto

Si el primer hijo de un elemento tiene un margin-top, el padre ajustará su posición como una forma de contraer márgenes redundantes. ¿Por qué? Es así como así.

Dado el siguiente problema:

<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}
</style>

<div class="parent"><!--This div moves 40px too-->
    <div class="child">Hello world!</div>
</div>

Puede solucionarlo agregando un elemento secundario con contenido, como un espacio simple. Pero todos odiamos agregar espacios para lo que es un problema de solo diseño. Por lo tanto, use la white-spacepropiedad para falsificar contenido.

<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}
.fix {position: relative;white-space: pre;height: 0px;width: 0px;overflow: hidden;}
</style>

<div class="parent"><!--This div won't move anymore-->
    <div class="fix"></div>
    <div class="child">Hello world!</div>
</div>

Donde position: relative;asegura el correcto posicionamiento de la solución. Y white-space: pre;hace que no tenga que agregar ningún contenido, como un espacio en blanco, a la solución. Y height: 0px;width: 0px;overflow: hidden;se asegura de que nunca verás la solución.

Es posible que deba agregar line-height: 0px;o max-height: 0px;asegurarse de que la altura sea realmente cero en los navegadores IE antiguos (no estoy seguro). Y, opcionalmente, puede agregarlo <!--dummy-->en los antiguos navegadores IE, si no funciona.

En resumen, puede hacer todo esto solo con CSS (lo que elimina la necesidad de agregar un elemento secundario real al árbol DOM de HTML):

<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}

.parent:before {content: '';position: relative;height: 0px;width: 0px;overflow: hidden;white-space: pre;}
</style>

<div class="parent"><!--This div won't move anymore-->
    <div class="child">Hello world!</div>
</div>
Yeti
fuente
Solo use esta solución si está desesperado y no puede configurar ningún CSS personalizado para los elementos existentes; de lo contrario, use la solución real: establecer overflow: hidden;para el padre.
Yeti
2

Para evitar "Div parent" use el margen de "div child":
En parent use estos css:

  • Flotador
  • Relleno
  • Frontera
  • Desbordamiento
bingo
fuente
1

La marginmayoría de los elementos contenidos dentro .childestán colapsando.

<html>
<style type="text/css" media="screen">
    #parent {background:#dadada;}
    #child {background:red; margin-top:17px;}
</style>
<body>
<div id="parent">

    <p>&amp;</p>

    <div id="child">
        <p>&amp;</p>    
    </div>

</div>
</body>
</html>

En este ejemplo, precibe un marginestilo predeterminado del navegador. El valor predeterminado del navegador font-sizesuele ser de 16 píxeles. Al tener margin-topmás de 16px #child, comienzas a notar su movimiento de posición.

25 horas
fuente
1

También tuve este problema, pero preferí evitar hacks de márgenes negativos, así que puse un

<div class="supercontainer"></div>

a su alrededor todo lo que tiene rellenos en lugar de márgenes. Por supuesto, esto significa más divitis, pero probablemente sea la forma más limpia de hacerlo correctamente.

Zyl
fuente
1

Curiosamente, mi solución favorita para este problema aún no se menciona aquí: usar flotadores.

html:

<div class="parent">
    <div class="child"></div>
</div>

css:

.parent{width:100px; height:100px;}
.child{float:left; margin-top:20px; width:50px; height:50px;}

Véalo aquí: http://codepen.io/anon/pen/Iphol

tenga en cuenta que en caso de que necesite altura dinámica en el padre, también tiene que flotar, así que simplemente reemplácelo height:100px;porfloat:left;

schellmax
fuente
1

Una solución alternativa que encontré antes de saber la respuesta correcta era agregar un borde transparente al elemento padre.

Sin embargo, su caja utilizará píxeles adicionales ...

.parent {
    border:1px solid transparent;
}
SandRock
fuente
0

Usar en toplugar de margin-topes otra posible solución, si corresponde.

lamplightdev
fuente