En CSS, line-height
es probablemente uno de los atributos más incomprendidos, pero más utilizados. Como diseñadores y desarrolladores, cuando pensamos en line-height
, podríamos pensar en el concepto de liderazgo a partir del diseño de impresión, un término, curiosamente, que proviene literalmente de poner trozos de plomo entre líneas de tipografía.
Liderando y line-height
, aunque similares, tienen algunas diferencias importantes. Para entender esas diferencias, primero tenemos que entender un poco más sobre tipografía.
Una descripción general de los términos de tipografía
En el diseño tipográfico occidental tradicional, una línea de texto se compone de varias partes:
- Base: Ésta es la línea imaginaria sobre la que se asienta el tipo. Cuando escribe en un cuaderno rayado, la línea de base es la línea en la que escribe.
- Descender: Esta línea se encuentra justo debajo de la línea de base. Es la línea que algunos caracteres, como minúsculas
g
,j
,q
,y
yp
– toque debajo de la línea de base. - Altura X: Esta es (como era de esperar) la altura de una minúscula normal
x
en una línea de texto. Generalmente, esta es la altura de otras letras minúsculas, aunque algunas pueden tener partes de sus caracteres que excederán la altura de la x. A todos los efectos, sirve como la altura percibida de las letras minúsculas. - Altura de la tapa: Esta es la altura de la mayoría de las letras mayúsculas en una línea de texto determinada.
- Ascendente: Una línea que a menudo aparece justo encima de la altura del límite donde algunos caracteres como minúsculas
h
ob
puede exceder la altura normal de la tapa.
Cada una de las partes del texto descritas anteriormente son intrínsecas a la fuente en sí. Una fuente se diseña teniendo en cuenta cada una de estas partes; sin embargo, hay algunas partes de la tipografía que se dejan en manos del autor de la tipografía (¡como tú y yo!) en lugar del diseñador. Uno de ellos es el líder.
El adelanto se define como la distancia entre dos líneas de base en un conjunto de tipos.
Un desarrollador de CSS podría pensar: “Está bien, liderar es el line-height
, Vamonos.” Si bien los dos están relacionados, también son diferentes en algunos aspectos muy importantes.
Tomemos un documento en blanco y agreguemos un “restablecimiento de CSS” clásico:
* {
margin: 0;
padding: 0;
}
Esto elimina el margen y el relleno de cada elemento.
También usaremos Lato de Google Fonts como nuestro font-family
.
Necesitaremos algo de contenido, así que creemos un <h1>
etiqueta con un poco de texto y establezca el line-height
a algo odiosamente enorme, como 300px. El resultado es una sola línea de texto con una sorprendente cantidad de espacio tanto por encima como por debajo de la única línea de texto.
Cuando un navegador encuentra el line-height
propiedad, lo que realmente hace es tomar la línea de texto y colocarla en el medio de un “cuadro de línea” que tiene una altura que coincide con la altura de la línea del elemento. En lugar de establecer el interlineado en una fuente, obtenemos algo parecido a rellenar uno a cada lado del cuadro de línea.
Como se ilustra arriba, el cuadro de línea se envuelve alrededor de una línea de texto donde se crea el interlineado usando el espacio debajo de una línea de texto y arriba de la siguiente. Esto significa que por cada elemento de texto en una página habrá la mitad del encabezado por encima de la primera línea de texto y después de la última línea de texto en un bloque de texto en particular.
Lo que podría ser más sorprendente es que establecer explícitamente el line-height
y font-size
en un elemento con el mismo valor dejará espacio adicional por encima y por debajo del texto. Podemos ver esto agregando un color de fondo a nuestros elementos.
Esto se debe a que aunque el font-size
está configurado en 32px, el tamaño real del texto es algo menor que ese valor debido al espaciado generado.
Conseguir que CSS trate la altura de la línea como interlineado
Si queremos que CSS use un estilo de configuración de tipo más tradicional en lugar del cuadro de línea, queremos que una sola línea de texto no tenga espacio ni arriba ni abajo, pero permitamos que los elementos de varias líneas mantengan su totalidad line-height
valor.
Es posible enseñar a CSS sobre liderazgo con un poco de esfuerzo. Michael Taranto lanzó una herramienta llamada Basekick que resuelve este mismo problema. Lo hace aplicando un margen superior negativo a la ::before
pseudoelemental y un translateY
al elemento en sí. El resultado final es una línea de texto sin ningún espacio adicional a su alrededor.
La versión más actualizada de la fórmula de Basekick se puede encontrar en el código fuente del Braid Design System de SEEK. En el siguiente ejemplo, estamos escribiendo un mixin de Sass para hacer el trabajo pesado por nosotros, pero la misma fórmula se puede usar con JavaScript, Less, mixins de PostCSS o cualquier otra cosa que proporcione este tipo de funciones matemáticas.
@function calculateTypeOffset($lh, $fontSize, $descenderHeightScale) {
$lineHeightScale: $lh / $fontSize;
@return ($lineHeightScale - 1) / 2 + $descenderHeightScale;
}
@mixin basekick($typeSizeModifier, $baseFontSize, $descenderHeightScale, $typeRowSpan, $gridRowHeight, $capHeight) {
$fontSize: $typeSizeModifier * $baseFontSize;
$lineHeight: $typeRowSpan * $gridRowHeight;
$typeOffset: calculateTypeOffset($lineHeight, $fontSize, $descenderHeightScale);
$topSpace: $lineHeight - $capHeight * $fontSize;
$heightCorrection: 0;
@if $topSpace > $gridRowHeight {
$heightCorrection: $topSpace - ($topSpace % $gridRowHeight);
}
$preventCollapse: 1;
font-size: #{$fontSize}px;
line-height: #{$lineHeight}px;
transform: translateY(#{$typeOffset}em);
padding-top: $preventCollapse;
&::before {
content: "";
margin-top: #{-($heightCorrection + $preventCollapse)}px;
display: block;
height: 0;
}
}
A primera vista, este código definitivamente parece una gran cantidad de números mágicos improvisados. Pero se puede descomponer considerablemente si se piensa en el contexto de un sistema en particular. Echemos un vistazo a lo que necesitamos saber:
$baseFontSize
: Este es el normalfont-size
para nuestro sistema alrededor del cual se gestionará todo lo demás. Usaremos 16px como valor predeterminado.$typeSizeModifier
: Este es un multiplicador que se usa junto con el tamaño de fuente base para determinar elfont-size
regla. Por ejemplo, un valor de 2 junto con nuestro tamaño de fuente base de 16px nos daráfont-size: 32px
.$descenderHeightScale
: Esta es la altura del descendente de la fuente expresada como una proporción. Para Lato, esto parece estar alrededor de 0,11.$capHeight
: Esta es la altura de la tapa específica de la fuente expresada como una proporción. Para Lato, esto es alrededor de 0,75.$gridRowHeight
: Los diseños generalmente se basan en un ritmo vertical predeterminado para crear una experiencia de lectura agradable y uniformemente espaciada. Por ejemplo, todos los elementos de una página pueden estar separados en múltiplos de cuatro o cinco píxeles. Usaremos 4 como valor porque se divide fácilmente en nuestro $ baseFontSize de 16px.$typeRowSpan
: Me gusta$typeSizeModifier
, esta variable sirve como un multiplicador que se utilizará con la altura de la fila de la cuadrícula para determinar la reglaline-height
valor. Si nuestra altura de fila de cuadrícula predeterminada es 4 y nuestro intervalo de fila de tipo es 8, eso nos dejaría con una altura de línea: 32px.
Ahora podemos insertar esos números en la fórmula de Basekick anterior (con la ayuda de funciones SCSS y mixins) y eso nos dará el resultado a continuación.
Eso es justo lo que estamos buscando. Para cualquier conjunto de elementos de bloque de texto sin márgenes, los dos elementos deben chocar entre sí. De esta manera, los márgenes establecidos entre los dos elementos serán perfectos en píxeles porque no estarán peleando con el espaciado del cuadro de línea.
Refinando nuestro código
En lugar de volcar todo nuestro código en una sola mezcla de SCSS, organicémoslo un poco mejor. Si pensamos en términos de sistemas, notaremos que hay tres tipos de variables con las que estamos trabajando:
Tipo de variable | Descripción | Variables de mezcla |
---|---|---|
Nivel del sistema | Estos valores son propiedades del sistema de diseño con el que estamos trabajando. | $baseFontSize $gridRowHeight |
Nivel de fuente | Estos valores son intrínsecos a la fuente que estamos usando. Puede haber algunas conjeturas y ajustes involucrados para obtener los números perfectos. | $descenderHeightScale $capHeight |
Nivel de regla | Estos valores serán específicos de la regla CSS que estamos creando. | $typeSizeMultiplier $typeRowSpan |
Pensar en estos términos nos ayudará a escalar nuestro sistema mucho más fácilmente. Consideremos a cada grupo por turno.
En primer lugar, las variables a nivel del sistema se pueden configurar globalmente, ya que es poco probable que cambien durante el transcurso de nuestro proyecto. Eso reduce la cantidad de variables en nuestro mixin principal a cuatro:
$baseFontSize: 16;
$gridRowHeight: 4;
@mixin basekick($typeSizeModifier, $typeRowSpan, $descenderHeightScale, $capHeight) {
/* Same as above */
}
También sabemos que las variables de nivel de fuente son específicas de su familia de fuentes determinada. Eso significa que sería bastante fácil crear un mixin de orden superior que los establezca como constantes:
@mixin Lato($typeSizeModifier, $typeRowSpan) {
$latoDescenderHeightScale: 0.11;
$latoCapHeight: 0.75;
@include basekick($typeSizeModifier, $typeRowSpan, $latoDescenderHeightScale, $latoCapHeight);
font-family: Lato;
}
Ahora, sobre una base de reglas, podemos llamar al Lato
mezclando con poco alboroto:
.heading--medium {
@include Lato(2, 10);
}
Esa salida nos da una regla que usa la fuente Lato con un font-size
de 32px y un line-height
de 40px con todas las traducciones y márgenes relevantes. Esto nos permite escribir reglas de estilo simples y utilizar la consistencia de la cuadrícula a la que los diseñadores están acostumbrados cuando usan herramientas como Sketch y Figma.
Como resultado, podemos crear fácilmente diseños de píxeles perfectos con poco esfuerzo. Vea qué tan bien se alinea el ejemplo con nuestra cuadrícula base de 4px a continuación. (Es probable que tenga que acercar la imagen para ver la cuadrícula).
Hacer esto nos da un superpoder único cuando se trata de crear diseños en nuestros sitios web: podemos, por primera vez en la historia, crear páginas con píxeles perfectos. Combine esta técnica con algunos componentes básicos de diseño y podemos comenzar a crear páginas de la misma manera que lo haríamos en una herramienta de diseño.
Avanzando hacia un estándar
Si bien enseñar CSS a comportarse más como nuestras herramientas de diseño requiere un poco de esfuerzo, hay buenas noticias en el horizonte. Se ha propuesto una adición a la especificación CSS para alternar este comportamiento de forma nativa. La propuesta, tal como está ahora, agregaría una propiedad adicional a los elementos de texto similar a line-height-trim
o leading-trim
.
Una de las cosas asombrosas de los lenguajes web es que todos tenemos la capacidad de participar. Si le parece una característica que le gustaría ver como parte de CSS, tiene la posibilidad de ingresar y agregar un comentario a ese hilo para que se escuche su voz.