Unidades de Medida en CSS: Porcentajes

Lupita Code 🌄
15 min readOct 6, 2021

--

¡Hola gente bonita!👋

En este articulo voy a explicar sobre los porcentajes, estos son una unidad muy importante en el responsive web design (RWD) ya que nos permiten crear layouts fluidos.

👉Cuando especificamos un porcentaje como valor en un elemento, este se calcula en base a la medida del elemento padre, y para que esto funcione, la medida del elemento padre debe estar especificada.

Por ejemplo, si usas el porcentaje en la propiedad width, este será un porcentaje basado en el ancho (width ) del elemento padre.

Veamos un ejemplo:

.parent {
width: 500px;
height: 100px;
border: 5px solid rebeccapurple;
}
.px {
width: 100px;
}
.percent {
width: 50%;
}
<div class="box percent">50%</div>
<div class="box px">100%</div>
<div class="parent">
<div class="box percent">50%</div>
<div class="box px">100%</div>
</div>

Como puedes darte cuenta al primer <div> le asigne un 50% de ancho. Sin embargo no he especificado un elemento padre que lo contenga, por lo tanto el <div> se coloca respecto al <body> ya que es el elemento padre mas cercano. Entonces width:50% equivale a la mitad del ancho de la ventana. Esto es muy útil ya que hay ocasiones en los que queremos que los elementos se ajusten al tamaño del viewport.

Ocurre lo contrario con el elemento <div> que se encuentra dentro del contenedor, el elemento <div> tiene un valor de 50%, por lo tanto este <div> se coloca respecto a su contenedor padre. Entonces width:50% equivale a la mitad del ancho de su contenedor principal.

Si te fijas el contenedor padre .parent tiene una medida fija de 500px, entonces el 50% de 500px serian 250px que es por obvias razones la mitad del tamaño del contenedor.

👉Recuerda que los porcentajes también se computan o se traducen a valores de pixel. Para ver estos valores computados por el navegador, abre la DevTools y haz click en la pestaña “Computed”.

En el ejemplo también coloque dos divs con medidas en pixeles, el primero esta afuera del contenedor y el segundo adentro y esto lo hice para que notes la diferencia entre pixeles y porcentajes. La diferencia es que los pixeles tendrán un ancho fijo que siempre será el mismo sin importar donde se defina y un porcentaje será en realidad un porcentaje que se basa en el tamaño de su ancestro.

Hasta aquí todo funciona bien, el problema es cuando empiezas a asignarles márgenes a los elementos o a los contenedores y en un momento te explico porque.

width:auto vs. width:100%

Lo primero que tienes que saber es que el ancho (width) inicial de los elementos HTML de bloque como <div> o <p> es auto (automático), esto hace que se expandan y ocupen todo el espacio horizontal disponible de su bloque contenedor.

La palabra clave auto usada en la propiedad width, significa que el navegador va a calcular automáticamente el ancho de un elemento en función del espacio que tenga disponible de su bloque contenedor sin llegar a desbordarse. Te lo explico con el siguiente ejemplo:

.parent {
width: 700px; 👈
height: 200px;
border: 5px solid rebeccapurple;
}
.child {
width: 100%; 👈
height: 40%;
background-color: skyblue;
}<div class="parent">
<div class="child">100%</div>
</div>

En este ejemplo al elemento hijo .child le asigne un ancho del 100%, que como puedes ver ocupa todo el ancho de su contenedor padre:

width: 100%

También vamos a asignar al elemento .child un padding y observa lo que sucede:

.child {
padding: 20px;
}
padding: 20px

Al establecer un padding de 20px sucede que una parte del elemento .child salga del contenedor padre y como puedes notar, el elemento .child también creció mas que el contenedor padre. ¿Sabes porque? Una de las razones es que NO se ha añadido la declaración box-sizing: border-box.

Si aun no sabes como funciona esta propiedad, te recomiendo leer mi articulo donde lo explico a detalle.

Voy a añadir la siguiente declaración al código de ejemplo:

* {
box-sizing: border-box;
}

Como puedes notar el elemento hijo adopta todo el ancho del contenedor padre sin desbordarse o salirse del contenedor.

box-sizing: border-box

Ahora vamos a asignar al elemento .child un margin-left y observa lo que sucede:

.child {
margin-left: 3rem;
}

Al establecer un margin-left de 3rem el elemento .child se desplaza lo cual provoca que una parte salga del contenedor padre, pero tenga en cuenta que el elemento hijo sigue conservando el 100% del contenedor padre:

margin-left: 3rem

Para solucionar este problema, reemplazamos el width:100% del elemento .child por el valor width:auto y con esto dejamos que el navegador sea quien calcule el ancho y que el elemento hijo se extienda en función del espacio que tenga disponible:

.child {
width: auto; ✅
}
width: auto

Un breve resumen para que quede mas claro:

Si usted especifica width:100% el ancho total del elemento será el 100% del bloque que lo contiene, es decir, el elemento hijo ocupa todo el ancho del elemento contenedor. Sin embargo la propiedad width por defecto no tiene en cuenta el margin, padding y border, si alguna de estas propiedades tiene un valor distinto de cero, el tamaño final del elemento será superior al de su contenedor y como resultado el elemento hijo se sale de su contenedor padre.

A menos que añada la declaración básica box-sizing: border-box en cuyo caso solo afectan los márgenes al elemento hijo, lo cual genera que este elemento salga del elemento que lo contiene. Si añadiste un margen al elemento hijo entonces la solución es aplicar width:auto .

Lo que estoy explicando tiene que ver con el modelo de caja y el box-sizing dos conceptos básicos, que llegado al tema de porcentajes, usted ya debería entender.

Veamos otro ejemplo:

En este segundo ejemplo tengo un elemento .header al cual le asigne un width:100% que como puedes ver ocupa todo el ancho de la pantalla, pero al asignar un margin-left: 3rem se habilita una barra de scroll horizontal.

* { box-sizing: border-box; }.header {
width: 100%; 👈
height: 100px;
margin-left: 3rem; 👈
background-color: khaki;
}
width:100%

☑️De nuevo para solucionar este problema podemos reemplazar el width:100% por width:auto. Sencillo y efectivo.

height:auto vs. height:100%

La MDN define los porcentajes usados en la propiedad height de la siguiente manera:

La propiedad height establece la altura de los elementos de bloque.
Si se declara en porcentaje, hace referencia a la altura del elemento en el que se encuentra (a su padre). Si este elemento contenedor no tiene establecida una altura de forma explícita (es decir, depende de la altura del contenido) y si este elemento NO tiene position absolute, se ignora la altura en porcentaje y se sustituye por el valor auto. Una altura declarada en porcentaje en el elemento raíz (html) es relativa al bloque inicial de contención (viewport).

La palabra clave auto usada en la propiedad height, significa que el navegador va a calcular el alto de un elemento en base al contenido de dicho elemento.

Cuando tienes un elemento dentro de un contenedor, es decir, una relacion padre-hijo, este contenedor padre debe tener un alto (height ) declarado, ya que si la caja contenedora no tiene un alto definido no se podrá calcular el porcentaje. Te lo explico en el siguiente ejemplo:

.parent {
width: 500px;
height: 200px; 👈
background-color: rebeccapurple;
}
.child {
width: 50%;
height: 50%;
background-color: skyblue;
}
<div class="parent">
<div class="child"></div>
</div>

Como puedes observar el contenedor padre tiene una altura definida de 200px

.parent { height: 200px; }

Si eliminas la propiedad height del contenedor padre, ambas cajas desaparecen y por lo tanto el valor de height es cero. Esto sucede porque no tiene contenido el elemento. Es decir, si existen dos cajas, pero ambas están vacías. Entonces vamos a añadir algo de texto al elemento padre:

.parent {
width: 500px;
background-color: rebeccapurple;
}
<div class="parent"> 👇
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Similique,iure.
<div class="child"></div>
</div>

Al añadir texto al contenedor principal, ahora la altura por defecto es auto, height: auto, lo que quiere decir que la altura del elemento es en base al contenido. Si añades mas texto, la caja seguirá creciendo. Y esto lejos de ser un problema es algo útil, ya que si colocas una medida fija en la altura independientemente de la unidad de medida que uses, el texto se desborda o se sale del contenedor principal.

height: auto

Este es uno de los motivos por los que debes tener cuidado al usar la propiedad height, en muchas ocasiones es mejor dejar que el contenido determine el alto del elemento. Si en realidad necesitas una altura es mejor utilizar min-height o tal vez padding-bottom.

html, body { height: 100% }

Cuando se trata del ancho y el alto de la página ¿Sabes qué configurar del elemento html? ¿Y del elemento body? o ¿Simplemente colocas los estilos en ambos elementos y esperas lo mejor?

No es raro ver las propiedades CSS aplicadas tanto al elemento html como al elemento body de la siguiente manera:

html, body { 
height: 100%;
}

Es probable que también hayas aplicado este estilo o uno similar a ambos elementos sin considerar tal vez lo que estas haciendo. Te lo explico con este ejemplo:

Primero voy a establecer un color de fondo a ambos elementos (html, body). No voy a asignar medidas a estos elementos, solo queremos saber cual es el color que se va a pintar en pantalla.

html {
background-color: rebeccapurple;
}
body {
background-color: skyblue;
}

Como puedes ver el viewport (la ventana grafica) se pinto del color purpura, que corresponde al elemento html

Si eliminamos la propiedad background-color del html y solo nos quedamos con el color de fondo del body, ahora el viewport se pinta del color azul ¿Curioso verdad?

body { background-color: skyblue }

En un giro extraño, el elemento html asume el background-colordel elemento body . ¿Herencia inversa?

Nos da la impresión de que el body es tan grande como el viewport, es decir, que ocupa todo el ancho y alto de la pantalla, sin embargo esto no es así. Cuando verificamos los estilos en las herramientas del desarrollador, el body tiene una altura de cero, pero si tiene un ancho que se extiende horizontalmente en toda la pantalla esto es porque body es un elemento de bloque. Miremos la siguiente captura de pantalla de la DevTools del navegador:

Como puedes ver el body tiene por defecto un margen de 8px indicado por la barra en la parte superior, pero la altura tiene valor de 0.

Esto sucede porque la altura del body crece conforme haya contenido, es decir, inicialmente la altura del body es 0, pero conforme vas añadiendo elementos como texto, imágenes, encabezados, etc, la altura del body va a ir aumentando.

Vamos a comprobarlo añadiendo texto, y también voy a reestablecer los colores de fondo para ambos elementos:

html { background-color: rebeccapurple;}
body { background-color: skyblue; }
<body>
<main>
<h1> Lupita Code </h1>
<p>Lorem...</p>
</main>
</body>

Con esto comprobamos lo que explique anteriormente, la altura del body crece conforme haya contenido, por lo tanto, la altura es auto: height: auto Si añades mas elementos, el body seguirá creciendo pero si no hay contenido o hay etiquetas vacías la altura del body es cero.

Ahora queremos que el elemento body ocupe todo el ancho y el alto de la pantalla, entonces vamos a asignar un alto del 100%

body { height: 100%;}

Sin embargo, esto no funciona…

La razón es porque el elemento body también tiene un elemento padre que es <html> . El <html>pese a no tener declarado un valor para la propiedad height aparenta ocupar todo el alto de la ventana del navegador en todo momento, pero solo es eso, “una apariencia”, ya que su altura no es toda la ventana, la altura por defecto del <html> es auto lo que significa que su altura crece según el contenido que haya en body, y en ausencia de contenido y/u otras propiedades que lo modifiquen es 0 (cero).

Entonces, ¿Por qué el color de fondo purpura del <html> ocupa toda la ventana?, esta pregunta viene seguida por otra pregunta:

¿Te has preguntado si el elemento <html> tiene un padre? Según la especificacion el elemento raíz no tiene ningún padre. Sin embargo si tiene un bloque contenedor.

Al asignar medidas en porcentajes al elemento html, este se basa en el bloque de contención inicial, es decir el viewport. Como lo dice expresamente la especificación:

Una altura declarada en porcentaje en el elemento raíz (html) es relativa al bloque inicial de contención (viewport).

html {
width: 50%;
height: 50%;
border: 5px solid white;
background-color: rebeccapurple;
}
<body>
<p>lorem...</p>
</body>

Como puedes ver el html ocupa el 50% de alto y ancho del viewport, el texto esta delimitado por el tamaño del html. A pesar de esto el color de fondo purpura del html sigue ocupando toda la ventana, cuando debería ocupar solo el 50%. El color de fondo del html (elemento raíz) es “heredado” por su caja de contención (el viewport).

Entonces para colocar el body al 100% de alto, hace falta que su ancestro (<html>) también tenga un alto especificado. Recuerda que el uso de un porcentaje como tamaño necesita usar como referencia el elemento padre en el que basar el porcentaje.

Entonces para ambos elementos establecemos una altura del 100%

html,body { 
height: 100%;👈
}

Y ahora el <body> ocupa todo lo alto del viewport ☑️

¿Qué pasaría si en lugar de establecer height: 100% lo reemplazamos por una altura mínima en ambos elementos?:

html,body { 
min-height: 100%;👈
}

Establecer la altura mínima al 100% en ambos elementos NO permite que el elemento body llene la pagina como cabria esperar, pero el elemento html si tiene una altura igual a la parte visible de la pagina en el navegador, es decir, al viewport.

En el codigo solo establecimos el min-height del elemento html... NO un valor a la propiedad height. Por lo tanto, el elemento body no tiene un elemento padre al que hacer referencia cuando establece la propiedad igual al 100%. Entonces podemos re-definir esto de la siguiente manera:

html {
height: 100%
}
body {
min-height: 100%;👈
}

Esto permite al elemento html hacer referencia al viewport y que tenga un valor de altura igual al 100%. Con el elemento html recibiendo un valor de altura, el min-height asignado al elemento body le da una altura inicial que coincide con el elemento html. Esto también permite que el bodycrezca más alto si el contenido supera el tamaño de lo visible de la página.

El único inconveniente es que el elemento html no crezca más allá de la altura de la ventana gráfica visible. Sin embargo, se ha permitido que el elemento bodysupere el elemento html.

Durante años esta fue la configuración de altura ideal para una página full responsive, pero ahora hay otra opción mas moderna:

body { min-height: 100vh; } ☑️

En esta configuración usamos como unidad vh (viewport height) para permitir que el body establezca una altura mínima basada en la altura completa del viewport.

Al igual que lo que pasaba con la propiedad background-color, si nosotros NO asignamos un valor de altura máxima al elemento html, asumirá el mismo valor de la altura del elemento body.

Por lo tanto, esta solución evita el desbordamiento del elemento htmlpresente en la solución anterior y ambos elementos crecen con su contenido.

En otra extraña serie de eventos, puede que tu página tenga instantáneamente una barra de scroll horizontal, supongo que te ha pasado. Este problema surge cuando cualquier elemento, no solo los elementos html o body- se establecen con 100vw (viewport width).

Las unidades de viewport no tienen en cuenta los 10 píxeles aproximados que ocupa la barra de scroll vertical. Por lo tanto, cuando se activa la barra de scroll vertical, también se obtiene una barra de scroll horizontal.

Si establecemos el ancho al 100% en el elemento body, tendrá un ancho de página completo. Esto es equivalente a no establecer un valor de ancho y permitir el valor predeterminado.

Si deseamos utilizar el elemento del body como un contenedor más pequeño y dejar que el elemento HTML llene la página, podemos establecer un valor de ancho máximo en el body. Aquí un ejemplo:

html { background-color: #000; } 
body {
min-height: 100vh;
max-width: 400px;
background-color: papayawhip;
margin: 0 auto;
}

En resumen: establezca el min-height del elemento body en 100vh. Si estableces el ancho de página, elije el 100% sobre 100vw para evitar el scroll horizontal.

Todas las opciones que vimos anteriormente están resumidas en este Tweet de Elad Shechter donde el elemento <body> ocupa toda la ‘altura’ de la pantalla, la opción mas nueva es agregar el valor fill-available. Esto impide que el footer del sitio web quede oculto por la barra de menú del navegador Safari en dispositivos como el iPhone.

img { max-width: 100%}

Es común establecer a las imagenes un max-width: 100%. Esto se hace para evitar que las imágenes grandes se desborden si se colocan en un contenedor que no es lo suficientemente ancho para contenerlas.

La mayoría de los elementos de bloque crecerán o se encogerán automáticamente para adaptarse a su contenedor padre, pero los elementos como <img> son especiales: se les conoce como replaced elements y no siguen las mismas reglas.

Si una imagen tiene un tamaño de 800×600, el elemento <img> también tendrá exactamente 800px de ancho, aunque lo coloquemos en un elemento padre de 500px de ancho.

Esta regla evitará que la imagen crezca más allá de su contenedor.

Porcentajes como valor en la propiedad font-size

No es común establecer porcentajes como tamaño de fuente, aunque si se puede establecer como base en el html, por ejemplo html{ font-size: 100% } esto equivale a 16px.

Pero usar porcentajes en el font-size de todos los elementos es poco frecuente, porque para eso están las unidades de tipografía como em y rem. Sin embargo no esta de mas explicar como funciona los porcentajes en la propiedad font-size, aquí un ejemplo:

li {
font-size: 80%;
}
<ul>
<li>One</li>
<li>Two</li>
<li>Three
<ul>
<li>Three A</li>
<li>Three B
<ul>
<li>Three B 2</li>
</ul>
</li>
</ul>
</li>
</ul>

Cada elemento <li> tiene un font-size del 80%, por lo tanto, los elementos de la lista anidada se vuelven progresivamente más pequeños a medida que heredan su tamaño del elemento padre.

¿Dónde utilizar porcentajes?

Los porcentajes se usan frecuentemente en la propiedad width, se usa sobre todo para dar tamaño a elementos grandes y distribuir los elementos en pantalla. También se usan junto a unidades absolutas como los pixeles.

.container {
width: 90%;
min-width: 300px;
}

Como pudiste notar en los ejemplos las unidades en porcentajes no siempre funcionan como se espera cuando se configura la altura en un elemento, asi que es mejor usarlas solo para el ancho. Si te ves forzado a utilizar la altura en los elementos, te recomiendo que uses min-height en lugar de height, solo si es necesario, pero es mejor dejar que el contenido determine la altura de los elementos.

📚 Lecturas Recomendadas

Gracias por leer 🦸🏻‍♀️
Mis redes sociales donde comparto notas de código:

--

--

Lupita Code 🌄
Lupita Code 🌄

Written by Lupita Code 🌄

🎓System Engineer 🚀 Frontend Developer 📚 Learning AI & Machine Learning 👩‍💻 Content Creator ⬇️ My youtube channel | My opinions are my own.

Responses (2)