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

Si nos fijamos en el Especificaciones del modelo de caja CSS, observará lo siguiente:

El porcentaje de [margen] se calcula con respecto al anchura del bloque contenedor de 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, entonces el diseño resultante no está definido en CSS 2.1. (énfasis mío)

Esto es cierto. Pero el porqué? ¿Qué diablos obligaría a alguien a diseñarlo de esta manera? Es fácil pensar en escenarios en los que desee, por ejemplo, que cierta cosa esté siempre 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.

He aquí 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/

preguntado el 12 de junio de 12 a las 20:06

Mi pensamiento inicial es que causaría ambigüedad en cuanto a lo que margin: 25% en realidad significa. No sería un margen uniforme, aunque el código sugiere que lo es. No tengo evidencia para respaldar esto, pero parece razonable. -

jsEl violín de mis pensamientos. La altura es mucho más variable que el ancho, por lo que haría que los márgenes cambiaran de manera difícil de predecir cada vez que cambiara el contenido. -

@Ryan: Eso es cierto, no sería un margen uniforme, pero, de nuevo, si dices height: 10%; width: 10% tampoco obtendrás un elemento cuadrado. -

Según dev.w3.org/csswg/css3-box/#the-margin-properties afirma 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). Por lo tanto, va en ambos sentidos -

@Ryan Creo que tenemos un ganador. Mire aquí para una demostración - jsviolín -

5 Respuestas

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

La altura del elemento se define por la altura de los niños. Si un elemento tiene padding-top: 10% (relativo a la altura principal), eso afectará la altura del elemento principal. Dado que la altura del hijo depende de la altura del padre, y la altura del padre depende de la altura del hijo, tendremos una altura inexacta o un ciclo infinito. Claro, esto solo afecta el caso donde el padre compensado === padre, 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 hoja (hijo sin hijos) tiene un efecto sobre la altura de todos los elementos por encima de él, por lo que afecta a muchas situaciones diferentes.

Respondido el 12 de junio de 12 a las 22:06

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 cajas. Y, de hecho, los casos que involucran una codependencia entre padre e hijo en altura tienden a conducir a un comportamiento indefinido. - PernoReloj

@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

¿Por qué el W3C constantemente hace esto? Aparentemente 'semántico' para el W3C es el equivalente a tener que atender a personas que no pueden pensar lógicamente, lo cual no tiene sentido. Es como quejarse de lo confusa y tonta que es la gente en el mundo y luego difundir más confusión y estupidez. El razonamiento que ha proporcionado no tiene sentido: el mismo argumento se aplica a los anchos, pero 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

Esa dependencia es una fórmula algebraica que tiene una solución y será no dar como resultado un ciclo infinito a menos que elija resolverlo de una manera que no respete esto. Digamos que la altura de los padres es h_p. Un acolchado superior del 10% hará que el niño sea alto h_c = h_ci + 0.1h_p, Donde h_ci es la altura interior del niño y no depende de la altura de los padres. Para un niño, simplemente encuentre la altura de los padres 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 niños tenga, incluso para diferentes rellenos. Es solo una incógnita (h_p) y una ecuación. - jeteon

No creo que el cálculo infinito sea la razón. Una razón simple es que: usar width resulta en el mismo problema horizontalmente. - Joy

Para que el margen "n%" (y el relleno) sea el mismo para margin-top/margin-right/margin-bottom/margin-left, los cuatro deben ser relativos a la misma base. Si la parte superior/inferior usara una base diferente a la izquierda/derecha, entonces el margen (y el relleno) "n%" no significaría lo mismo en los cuatro lados.

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

Respondido 18 ago 13, 03:08

... una respuesta sorprendentemente simple. Aunque todas las conjeturas anteriores tienen mérito, este es un buen punto. Posiblemente, parece un caso en el que varias soluciones serían correctas, por lo que simplemente eligieron la que tenía más probabilidades de ser utilizada... ¿quizás? - amigo

Supongo que sería bueno tener un elemento extra en la sintaxis para que pudieras escribir, digamos padding: n [type]. Entonces tu tendrías padding: 5% logical (lo que sugiere el OP) en lugar de padding: 5% width con el segundo parámetro predeterminado en "ancho" para compatibilidad con versiones anteriores. - jeteon

"n% de margen (y relleno) no significaría lo mismo en los cuatro lados" - Pero, ¿por qué eso sería un problema? - Herbertusz

Voto por la respuesta de @ChuckKollars después de jugar con esto JSFiddle (en Chrome 46.0.2490.86) y refiriéndose a esta publicación (escrito en chino).


Una de las principales razones en contra de la calculo infinito conjetura es que: usando width se enfrenta a lo mismo calculo infinito problema.

Echa un vistazo a esto JSFiddle, la parent pantalla es inline-block, que es elegible para definir margen/relleno en él. El child tiene valor de margen 20%. Si seguimos el calculo infinito conjetura:

  1. El ancho de la child depende de parent
  2. El ancho de la parent depende de child

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

enter image description here

Si intenta expandir el panel de "resultados" horizontalmente en el JSFiddle, encontrará que el ancho de ellos no cambiará. Tenga en cuenta que el contenido de la child está envuelto en dos lineas (no, digamos, una línea), ¿por qué? Supongo que Chrome simplemente lo codificó en alguna parte. Si editas el child contenido para hacerlo más (JSFiddle), encontrará que siempre que 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 (escrito en chino) también propone otra razón: es por la orientación de lectura/composición tipográfica. Leemos de arriba hacia abajo, con el ancho fijo y la altura infinita (virtualmente).

respondido 26 nov., 15:03

Esto se debe a que las páginas web se desplazan verticalmente en una dirección generalmente infinita; por lo que el ancho se puede calcular 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 la dirección vertical (desconocido). Es por eso que el ancho no tiene el mismo problema. - Zorro Lucent

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

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 ventana gráfica.

100vw/100vh equivale a 100 % de ancho/100 % de alto (respectivamente) si no hay barra de desplazamiento; si hay una barra de desplazamiento, los números de la ventana gráfica no tienen esto en cuenta (mientras que los números % sí). Afortunadamente, casi todos los navegadores usan tamaños de barra de desplazamiento de 17px (mire 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 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!).

Respondido el 05 de enero de 16 a las 17:01

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 de caja flexible que crece para llenar el espacio disponible mientras hay otra caja con contenido variable). - Jules

Sé que esta pregunta es un poco antigua, pero me gustaría actualizarla para CSS3. Si bien es cierto que la especificación CSS2.1 dice que el porcentaje de relleno y el margen se definen en relación con el ancho del bloque contenedor, esto no es así. siempre el caso. Depende del modo de escritura. Esto viene directamente de la Especificaciones CSS3:

Como corolario, los porcentajes de las propiedades de margen y relleno, que siempre se calculan con respecto al ancho del bloque contenedor en CSS2.1, se calculan con respecto al tamaño en línea del bloque contenedor en CSS3.

Cubro esto en mi tutorial sobre relaciones de aspecto con CSS.

Específicamente, hay una sección sobre Porcentaje de relleno en modos de escritura horizontal frente a vertical. Por defecto, un elemento tiene un modo de escritura horizontal, donde el texto fluye horizontalmente (en la dirección "en línea") de izquierda a derecha. Sin embargo, usando el writing-mode propiedad CSS, en realidad puede configurar el modo para que sea vertical (con el texto fluyendo de derecha a izquierda o de izquierda a derecha). Aquí hay algunos diagramas de los modos de escritura horizontal y vertical:

Un modo de escritura horizontal, con texto que fluye verticalmente de arriba a abajo. Una flecha apunta de izquierda a derecha en la parte superior del documento y está etiquetada como la dirección en línea. Otra flecha apunta de arriba hacia abajo y está etiquetada como la dirección del bloque.

Un modo de escritura vertical, con texto que fluye horizontalmente. El eje horizontal está etiquetado como la dirección del bloque, mientras que el eje vertical ahora está etiquetado como la dirección en línea. El texto se representa de lado.

Estos son tomados de la Documentos de MDN sobre modos de escritura.

En los modos de escritura vertical, el porcentaje de relleno será relativo a la altura del bloque contenedor, no al ancho.

Aquí tienes la prueba:

.document {
  writing-mode: vertical-rl;
  width: 100%;
  height: 100vh;
}

.parent {
   width: 100%;
   height: 200px;
   background-color: black;
   color: white;
}

.child {
  padding: 10%;
  background-color: white;
  color: black;
  border: solid 1px;
}
<div class="document">
  <div class="parent">
    <div class="child">
      Child
    </div>
  </div>
</div>

El niño obtiene 20 px de relleno, que es el 10 % de la altura del bloque que lo contiene (200 px).

En cuanto al por qué en la pregunta, esto se cubrió bien en las otras publicaciones aquí.

Respondido el 24 de Septiembre de 20 a las 13:09

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.