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

130

Si observa las especificaciones del modelo de cuadro CSS , observará lo siguiente:

El porcentaje [margen] se calcula con respecto al ancho del bloque que contiene el cuadro generado. 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 que ? ¿Qué demonios obligaría a cualquiera a diseñarlo de esta manera? Es fácil pensar en los escenarios en los que desea, por ejemplo, que una cosa siempre esté un 25% por debajo de 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:

<div style="border: 1px solid red; margin: 0; padding: 0; width: 200px; height: 800px;">
  This div is 200x800.
  <div style="border: 1px solid blue; margin: 10% 0 0 10%;">
    This div has top-margin of 10% and left-margin of 10% with respect to its parent.
  </div>
</div>

http://jsfiddle.net/8JDYD/

mqp
fuente
3
Mi pensamiento inicial es que causaría ambigüedad en cuanto a lo que margin: 25%realmente significa. No sería un margen uniforme, aunque el código lo sugiera. No tengo pruebas para respaldar esto, pero parece razonable.
Ryan Kinal
44
js El violín de mis pensamientos . La altura es mucho más variable que el ancho, por lo que haría que los márgenes cambien de una manera difícil de predecir cada vez que el contenido cambia.
RichardTowers
1
@ Ryan: Eso es cierto, no sería un margen uniforme, pero de nuevo, si dices height: 10%; width: 10%que tampoco obtendrás un elemento cuadrado.
mqp
44
De acuerdo con dev.w3.org/csswg/css3-box/#the-margin-properties , Note that in a horizontal flow, percentages on ‘margin-top’ and ‘margin-bottom’ are relative to the width of the containing block, not the height (and in vertical flow, ‘margin-left’ and ‘margin-right’ are relative to the height, not the width).así lo dice en ambos sentidos
Adam Sweeney
1
@ Ryan Creo que tenemos un ganador. Mira aquí para una demostración - jsFiddle
RichardTowers

Respuestas:

60

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

La altura del elemento se define por la altura de los hijos. Si un elemento tiene padding-top: 10% (en relación con la altura del padre), eso afectará la altura del padre. Como la altura del niño depende de la altura del padre y la altura del padre depende de la altura del niño, tendremos una altura inexacta o un bucle 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 hoja (niño sin hijos) tiene un efecto sobre la altura de todos los elementos por encima, por lo que esto afecta a muchas situaciones diferentes.

Ryan Kinal
fuente
1
Tenga en cuenta que hay excepciones a esta regla: la sección 10.6 de CSS2.1 cubre casi todas las instancias de cálculo de alturas para varios tipos de cuadros. Y, de hecho, los casos que implican una codependencia entre padres e hijos en altura tienden a conducir a un comportamiento indefinido.
BoltClock
1
@sanjaypoyzer Supongo que, en el caso más simple, los navegadores calculan los anchos de bloque desde afuera hacia adentro (raíz a puntas), luego fluyen el contenido hacia esos bloques para determinar sus alturas (puntas a raíz).
sam
9
¿Por qué el W3C hace esto constantemente? Aparentemente 'semántico' para el W3C es el equivalente a tener que atender a personas que no pueden pensar lógicamente, lo que no tiene sentido. Es como quejarse de lo confusas y tontas que son las personas en el mundo y luego esparcir más confusión y estupidez. El razonamiento que ha proporcionado no tiene sentido: el mismo argumento se aplica a los anchos, pero eso funciona bien. Todo lo que se necesitaría es establecer un contexto y una dirección en la que se determinen las alturas, a menos que la altura del padre se establezca en píxeles o algo inmutable, entonces no hay mucho problema.
u353
3
Esa dependencia es una fórmula algebraica que tiene una solución y no dará como resultado un bucle infinito a menos que elija resolverlo de una manera que no respete esto. Digamos que la altura de los padres es h_p. Un relleno superior del 10% hará que la altura del niño h_c = h_ci + 0.1h_p, donde h_cies la altura interior del niño y no dependa de la altura del padre. Para un niño, simplemente encuentra la altura del padre de la ecuación h_p = h_ci + 0.1h_p=> h_p = h_ci / 0.9. Siempre puede hacer esto, sin importar cuántos hijos tenga, incluso para diferentes rellenos. Es solo una incógnita ( h_p) y una ecuación.
jeteon
2
No creo que el cálculo infinito sea la razón. Una razón simple es eso: usar widthresultados en el mismo problema horizontalmente.
Alegría
30

Para que el margen "n%" (y el relleno) sean los mismos para margen superior / margen derecho / margen inferior / margen izquierdo, los cuatro deben ser relativos a la misma base. Si arriba / abajo usara una base diferente a izquierda / derecha ', entonces el margen "n%" (y el relleno) no significarían lo mismo en los cuatro lados.

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

Chuck Kollars
fuente
... una respuesta sorprendentemente simple. Aunque todas las conjeturas anteriores tienen mérito, este es un punto bastante bueno. Parece posiblemente un caso en el que varias soluciones serían correctas, por lo que simplemente eligieron la más probable para ser utilizada ... ¿tal vez?
dudewad
1
Supongo que sería bueno tener un elemento adicional en la sintaxis para poder escribir say padding: n [type]. Por lo tanto, tendría padding: 5% logical(lo que sugiere el OP) en comparación padding: 5% widthcon el segundo parámetro predeterminado en "ancho" para la compatibilidad con versiones anteriores.
jeteon
55
"n% margen (y relleno) no significaría lo mismo en los cuatro lados" - ¿Pero por qué eso sería un problema?
Herbertusz
4

Voto por 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: el uso de widthcaras es el mismo problema de cálculo infinito .

Eche un vistazo a este JSFiddle , la parentpantalla inline-blockes elegible para definir el margen / relleno en él. El childtiene valor de margen 20%. Si seguimos la conjetura de cálculo infinito :

  1. El ancho de la childdepende de laparent
  2. El ancho de la parentdepende de lachild

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

ingrese la descripción de la imagen aquí

Si intenta expandir el panel "resultado" horizontalmente en el JSFiddle, encontrará que el ancho de ellos no cambiará. Tenga en cuenta que el contenido en childestá envuelto en dos líneas (no, por ejemplo, una línea), ¿por qué? Supongo que Chrome solo lo codifica en alguna parte. Si edita el childcontenido para hacerlo más ( JSFiddle ), encontrará que mientras haya espacio adicional horizontalmente, Chrome mantiene el contenido en dos líneas.

Entonces podemos ver: hay alguna forma 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 la lectura / composición tipográfica. Leemos de arriba a abajo, con el ancho fijo y la altura infinita (virtualmente).

Alegría
fuente
Esto se debe a que las páginas web se desplazan verticalmente en una dirección generalmente infinita; entonces el ancho puede calcularse a partir del ancho de la ventana del navegador. La única forma en que los elementos son más anchos que la pantalla es si especifica que su ancho sea mayor. Los elementos de bloque típicos tienen un ancho del 100% y se expanden automáticamente en dirección vertical (desconocido). Es por eso que el ancho no tiene el mismo problema.
Lucent Fox
3

Me doy cuenta de que el OP pregunta por qué la especificación CSS define los porcentajes de margen superior / inferior como un% de ancho (y no, como se supondría, altura), pero pensé que también podría ser útil publicar una solución potencial.

La mayoría de los navegadores modernos admiten vw y vh ahora, lo que le permite especificar números de margen contra el ancho y la altura de la vista.

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 tienen en cuenta 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á o no una barra de desplazamiento, esta solución no funcionará.

Por ejemplo: suponiendo que no haya una barra de desplazamiento horizontal, un margen superior del 50% de la altura podría definirse como "margin-top: 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!).

VKK
fuente
1
Es una solución útil en muchos casos, pero hay muchos ejemplos en los que no funciona (por ejemplo, si está tratando de hacer que el contenido se ajuste proporcionalmente al tamaño de un contenedor flexbox que crece para llenar el espacio disponible mientras hay otra caja con contenido variable).
Julio