¿Por qué los porcentajes de margen / relleno en CSS siempre se calculan contra el ancho?

Si mira las especificaciones del modelo de caja de CSS , observará lo siguiente:

El porcentaje de [margen] se calcula con respecto al ancho del bloque que contiene la caja generada. Tenga en cuenta que esto también es cierto para ‘margin-top’ y ‘margin-bottom’. Si el ancho del bloque contenedor depende de este elemento, el diseño resultante no está definido en CSS 2.1. (énfasis mío)

Esto es de hecho cierto. Pero por qué ? ¿Qué demonios obligaría a alguien a diseñarlo de esta manera? Es fácil pensar en los escenarios en los que desea, por ejemplo, una cierta cantidad siempre será un 25% inferior desde la parte superior de la página, pero es difícil encontrar alguna razón por la que desee que el relleno vertical sea relativo al tamaño horizontal de el padre.

Aquí hay un ejemplo del fenómeno al que me refiero:

This div is 200x800.
This div has top-margin of 10% and left-margin of 10% with respect to its parent.

http://jsfiddle.net/8JDYD/

Transfiriendo mi comentario a una respuesta, porque tiene un sentido lógico. Sin embargo, tenga en cuenta que esto es una conjetura infundada. El razonamiento real de por qué la especificación se escribe de esta manera todavía es, técnicamente, desconocido.

La altura del elemento se define por la altura de los niños. Si un elemento tiene relleno superior: 10% (relativo a la altura de los padres), eso afectará la altura del elemento principal. Dado que la altura del elemento secundario depende de la altura del componente principal y la altura del elemento primario depende de la altura del elemento secundario, tendremos una altura inexacta o un ciclo infinito. Claro, esto solo afecta el caso donde offset parent === parent, pero aún así. Es un caso extraño que es difícil de resolver.

Actualización: las últimas dos oraciones pueden no ser del todo precisas. La altura del elemento de la hoja (niño sin hijos) tiene un efecto en la altura de todos los elementos que están encima de ella, por lo que esto afecta a muchas situaciones diferentes.

Para que el margen “n%” (y el relleno) sean los mismos para margin-top / margin-right / margin-bottom / margin-left, los cuatro tienen que ser relativos a la misma base. Si la parte superior / inferior usa una base diferente a la izquierda / derecha ‘, entonces el margen “n%” (y el relleno) no significa lo mismo en los cuatro lados.

(También tenga en cuenta que tener el margen superior / inferior relativo al ancho habilita un hack CSS extraño que le permite especificar un cuadro con una relación de aspecto inmutable … incluso si se vuelve a escalar el cuadro).

Voto la respuesta de @ChuckKollars después de jugar con este JSFiddle (en Chrome 46.0.2490.86) y hacer referencia a esta publicación (escrita en chino).


Una razón importante contra la conjetura de cálculo infinito es que: usar width enfrenta el mismo problema de cálculo infinito .

Eche un vistazo a este JSFiddle , la pantalla parent es en inline-block , que es elegible para definir margen / relleno en él. El child tiene un valor de margen del 20% . Si seguimos la conjetura de cálculo infinito :

  1. El ancho del child depende del parent
  2. El ancho del parent depende del child

Pero como resultado, Chrome detiene el cálculo en alguna parte, lo que resulta en:

enter image description here

Si intenta expandir horizontalmente el panel “resultado” en JSFiddle, verá que el ancho de los mismos no cambiará. Tenga en cuenta que el contenido del child está envuelto en dos líneas (por ejemplo, una línea), ¿por qué? Creo que Chrome solo lo codifica en alguna parte. Si edita el contenido child para hacerlo más ( JSFiddle ), encontrará que siempre que haya espacio extra horizontalmente, Chrome mantiene el contenido en dos líneas.

Entonces podemos ver: hay alguna manera de evitar el cálculo infinito .


Estoy de acuerdo con la conjetura de que: este diseño es solo para mantener los cuatro valores de margen / relleno basados ​​en la misma medida.

esta publicación (escrita en chino) también propone otra razón es que: se debe a la orientación de lectura / tipografía. Leemos de arriba a abajo, con el ancho fijo y la altura infinita (prácticamente).

Me doy cuenta de que OP está preguntando por qué la especificación CSS define porcentajes de margen superior / inferior como% de ancho (y no, como se supondría, alto), pero pensé que también podría ser útil publicar una posible solución.

La mayoría de los navegadores modernos ahora admiten vw y vh, lo que le permite especificar los números de margen en función del ancho de la ventana gráfica y la altura de la ventana gráfica.

100vw / 100vh equivale a 100% de ancho / 100% de altura (respectivamente) si no hay barra de desplazamiento; si hay una barra de desplazamiento, los números de la ventana gráfica no representan esto (mientras que los números% sí). Afortunadamente, casi todos los navegadores usan tamaños de barra de desplazamiento de 17px ( ver aquí ), por lo que puede usar la función css calc para dar cuenta de esto. Si no sabe si aparecerá una barra de desplazamiento o no, esta solución no funcionará.

Por ejemplo: suponiendo que no haya una barra de desplazamiento horizontal, un margen superior del 50% de la altura se podría definir como “margen superior: 50vh”. Con una barra de desplazamiento horizontal, esto podría definirse como “margin-top: calc (0.5 * (100vh – 17px));” (¡recuerde que los operadores menos y más en calc requieren espacios en ambos lados!).