Escalar linealmente el tamaño de fuente con CSS Clamp() según la ventana gráfica

Índice
  1. ¿Qué pasa si el usuario cambia el tamaño de fuente de la raíz?
  2. Para aquellos a quienes no les importa ese caso extremo.
  3. Cómo evitar el texto redistribuido
  4. Texto sin flujo dentro de un contenedor
  5. Terminando

La tipografía responsiva se ha probado en el pasado con una serie de métodos como consultas de medios y CSS calc().

Aquí, vamos a explorar una forma diferente de escalar linealmente el texto entre un conjunto de tamaños mínimo y máximo a medida que aumenta el ancho de la ventana gráfica, con la intención de hacer que su comportamiento en diferentes tamaños de pantalla sea más predecible. Todo en una sola línea de CSS. , gracias a clamp().

La función CSS clamp()es un gran bateador. Es útil para una variedad de cosas, pero es especialmente bueno para la tipografía. Así es como funciona. Se necesitan tres valores:

clamp(minimum, preferred, maximum);

El valor que devuelve será el valor preferido, hasta que ese valor preferido sea inferior al valor mínimo (en cuyo momento se devolverá el valor mínimo) o superior al valor máximo (en cuyo momento se devolverá el máximo).

Entonces, ¿no sería siempre el valor preferido, suponiendo que no sea raro y lo establezca entre el mínimo y el máximo? Bueno, se espera que use una fórmula para el valor preferido, como:

.banner {  width: clamp(200px, 50% + 20px, 800px); /* Yes, you can do math inside clamp()! */}

Supongamos que deseamos establecer el mínimo de un elemento font-sizeen 1 rem cuando el ancho de la ventana gráfica es de 360 ​​​​px o menos, y establecer el máximo en 3,5 rem cuando el ancho de la ventana gráfica es de 840 px o más. .

En otras palabras:

1rem  = 360px and belowScaled = 361px - 839px3.5rem = 840px and above

Cualquier ancho de ventana gráfica entre 361 y 839 píxeles necesita un tamaño de fuente escalado linealmente entre 1 y 3,5 rem. ¡Es realmente muy fácil de hacer clamp()! Por ejemplo, con un ancho de ventana gráfica de 600 píxeles, a medio camino entre 360 ​​y 840 píxeles, obtendríamos exactamente el valor medio entre 1 y 3,5 rem, que es 2,25 rem.

Lo que intentamos lograr clamp()se llama interpolación lineal: obtener información intermedia entre dos puntos de datos.

Estos son los cuatro pasos para hacer esto:

Paso 1

Elija los tamaños de fuente mínimo y máximo, y los anchos mínimo y máximo de la ventana gráfica. En nuestro ejemplo, son 1rem y 3,5rem para los tamaños de fuente, y 360px y 840px para los anchos.

Paso 2

Convierta los anchos a rem. Dado que 1rem en la mayoría de los navegadores es 16px de forma predeterminada (más sobre esto más adelante), eso es lo que usaremos. Entonces, ahora los anchos mínimo y máximo de la ventana gráfica serán 22,5rem y 52,5rem, respectivamente.

Paso 3

Aquí, nos inclinaremos un poco hacia el lado de las matemáticas. Cuando se combinan, los anchos de la ventana gráfica y los tamaños de fuente forman dos puntos en un sistema de coordenadas X e Y, y esos puntos forman una línea.

Necesitamos esa línea, o más bien su pendiente y su intersección con el eje Y, para ser más específicos. A continuación se explica cómo calcularlo:

slope = (maxFontSize - minFontSize) / (maxWidth - minWidth)yAxisIntersection = -minWidth * slope + minFontSize

Eso nos da un valor de 0,0833 para la pendiente y -0,875 para la intersección en el eje Y.

Etapa 4

Ahora construimos la clamp()función. La fórmula para el valor preferido es:

preferredValue = yAxisIntersection[rem] + (slope * 100)[vw]

Entonces la función termina así:

.header {  font-size: clamp(1rem, -0.875rem + 8.333vw, 3.5rem);}

Puedes visualizar el resultado en la siguiente demostración:

Adelante, juega con ello. Como puede ver, el tamaño de fuente deja de crecer cuando el ancho de la ventana gráfica es de 840 px y deja de reducirse a 360 px. Todo lo que hay en el medio cambia de forma lineal.

¿Qué pasa si el usuario cambia el tamaño de fuente de la raíz?

Es posible que hayas notado un pequeño defecto en todo este enfoque: solo funciona siempre que el tamaño de fuente de la raíz sea el que cree, que es 16 píxeles en el ejemplo anterior, y nunca cambia.

Estamos convirtiendo los anchos, 360 px y 840 px, a remunidades dividiéndolos por 16 porque asumimos que ese es el tamaño de fuente de la raíz. Si el usuario tiene sus preferencias configuradas en otro tamaño de fuente raíz, digamos 18 px en lugar del 16 px predeterminado, entonces ese cálculo será incorrecto y el texto no cambiará de tamaño como esperábamos.

Solo hay un enfoque que podemos usar aquí, y es (1) hacer los cálculos necesarios en el código al cargar la página, (2) escuchar los cambios en el tamaño de fuente de la raíz y (3) volver a calcular todo si se producir algún cambio. .

Aquí hay una función de JavaScript útil para hacer los cálculos:

// Takes the viewport widths in pixels and the font sizes in remfunction clampBuilder( minWidthPx, maxWidthPx, minFontSize, maxFontSize ) {  const root = document.querySelector( "html" );  const pixelsPerRem = Number( getComputedStyle( root ).fontSize.slice( 0,-2 ) );  const minWidth = minWidthPx / pixelsPerRem;  const maxWidth = maxWidthPx / pixelsPerRem;  const slope = ( maxFontSize - minFontSize ) / ( maxWidth - minWidth );  const yAxisIntersection = -minWidth * slope + minFontSize  return `clamp( ${ minFontSize }rem, ${ yAxisIntersection }rem + ${ slope * 100 }vw, ${ maxFontSize }rem )`;}// clampBuilder( 360, 840, 1, 3.5 ) - "clamp( 1rem, -0.875rem + 8.333vw, 3.5rem )"

Estoy omitiendo deliberadamente cómo inyectar la cadena devuelta en el CSS porque hay muchas maneras de hacerlo dependiendo de tus necesidades y de si estás usando CSS básico, una biblioteca CSS-in-JS u otra cosa. Además, no existe un evento nativo para los cambios en el tamaño de fuente, por lo que tendríamos que verificarlo manualmente. Podríamos utilizar setIntervalcomprobar cada segundo, pero eso podría tener un costo de rendimiento.

Este es más bien un caso extremo. Muy pocas personas cambian el tamaño de fuente de su navegador y aún menos lo cambiarán precisamente mientras visitan su sitio. Pero si desea que su sitio sea lo más responsivo posible, este es el camino a seguir.

Para aquellos a quienes no les importa ese caso extremo.

¿Crees que puedes vivir sin que sea perfecto? Entonces tengo algo para ti. Crea una pequeña herramienta para hacer los cálculos rápidos y sencillos.

Todo lo que tiene que hacer es ingresar los anchos y tamaños de fuente en la herramienta y la función se calculará para usted. Copie y pegue el resultado en su CSS. No es lujoso y estoy seguro de que se puede mejorar mucho, pero, para el propósito de este artículo, es más que suficiente. Siéntete libre de bifurcar y modificar al contenido de tu corazón.

Cómo evitar el texto redistribuido

Tener un control tan preciso sobre las dimensiones de la tipografía nos permite hacer otras cosas interesantes, como evitar que el texto fluya en diferentes anchos de ventana gráfica.

Así es como se comporta normalmente el texto.

Pero ahora, con el control que tenemos, podemos hacer que el texto mantenga el mismo número de líneas, dividiéndose siempre en la misma palabra, en cualquier ancho de ventana gráfica que le arrojemos.

¿Entonces como hacemos esto? Para empezar, la relación entre los tamaños de fuente y el ancho de la ventana gráfica debe permanecer igual. En este ejemplo, pasamos de 1rem a 320px a 3rem a 960px.

320 / 1 = 320960 / 3 = 320

Si usamos la clampBuilder()función que creamos anteriormente, se convierte en:

const text = document.querySelector( "p" );text.style.fontSize = clampBuilder( 320, 960, 1, 3 );

Mantiene la misma relación ancho-fuente. La razón por la que hacemos esto es porque necesitamos asegurarnos de que el texto tenga el tamaño correcto en cada ancho para que pueda mantener el mismo número de líneas. Seguirá refluyendo en diferentes anchos, pero hacerlo es necesario para lo que haremos a continuación.

Ahora tenemos que obtener ayuda de la chunidad de caracteres CSS () porque tener el tamaño de fuente correcto no es suficiente. Una chunidad equivale al ancho del glifo “0” en la fuente de un elemento. Queremos hacer que el cuerpo del texto sea tan ancho como la ventana gráfica, no estableciendo width: 100%sino con width: Xch, donde Xestá la cantidad de chunidades (o ceros) necesarias para llenar la ventana gráfica horizontalmente.

Para encontrar X, debemos dividir el ancho mínimo de la ventana gráfica, 320 px, por el chtamaño del elemento en cualquier tamaño de fuente cuando la ventana gráfica tiene 320 px de ancho. Eso es 1rem en este caso.

No te preocupes, aquí tienes un fragmento para calcular chel tamaño de un elemento:

// Returns the width, in pixels, of the "0" glyph of an element at a desired font sizefunction calculateCh( element, fontSize ) {  const zero = document.createElement( "span" );  zero.innerText = "0";  zero.style.position = "absolute";  zero.style.fontSize = fontSize;  element.appendChild( zero );  const chPixels = zero.getBoundingClientRect().width;  element.removeChild( zero );  return chPixels;}

Ahora podemos proceder a establecer el ancho del texto:

function calculateCh( element, fontSize ) { ... }const text = document.querySelector( "p" );text.style.fontSize = clampBuilder( 320, 960, 1, 3 );text.style.width = `${ 320 / calculateCh(text, "1rem" ) }ch`; 

Vaya, espera. Algo malo sucedio. ¡Hay una barra de desplazamiento horizontal que arruina las cosas!

Cuando hablamos de 320px, nos referimos al ancho de la ventana gráfica, incluida la barra de desplazamiento vertical. Entonces, el ancho del texto se establece en el ancho del área visible, más el ancho de la barra de desplazamiento, lo que hace que se desborde horizontalmente.

Entonces, ¿por qué no utilizar una métrica que no incluya el ancho de la barra de desplazamiento vertical? No podemos y es por la vwunidad CSS. Recuerde, estamos usando vwin clamp()para controlar el tamaño de fuente. Verá, vwincluye el ancho de la barra de desplazamiento vertical, lo que hace que la fuente se escale a lo largo del ancho de la ventana gráfica, incluida la barra de desplazamiento. Si queremos evitar cualquier reflujo, entonces el ancho debe ser proporcional al ancho de la ventana gráfica, incluida la barra de desplazamiento.

¿Asi que que hacemos? Cuando hacemos esto:

text.style.width = `${ 320 / calculateCh(text, "1rem") }ch`;

…podemos reducir el resultado multiplicándolo por un número menor que 1. 0,9 es suficiente. Eso significa que el ancho del texto será el 90% del ancho de la ventana gráfica, lo que compensará con creces la pequeña cantidad de espacio que ocupa la barra de desplazamiento. Podemos hacerlo más estrecho usando un número aún más pequeño, como 0,6.

function calculateCh( element, fontSize ) { ... }const text = document.querySelector( "p" );text.style.fontSize = clampBuilder( 20, 960, 1, 3 );text.style.width = `${ 320 / calculateCh(text, "1rem" ) * 0.9 }ch`;

Es posible que tengas la tentación de simplemente restar algunos píxeles de 320 para ignorar la barra de desplazamiento, así:

text.style.width = `${ ( 320 - 30 ) / calculateCh( text, "1rem" ) }ch`;

¡El problema con esto es que trae de vuelta el problema del reflujo! Esto se debe a que restar 320 rompe la relación ventana gráfica-fuente.

El ancho del texto siempre debe ser un porcentaje del ancho de la ventana gráfica. Otra cosa a tener en cuenta es que debemos asegurarnos de cargar la misma fuente en todos los dispositivos que utilizan el sitio. Esto suena obvio ¿no? Bueno, aquí hay un pequeño detalle que podría alterar tu texto. Hacer algo así font-family: sans-serifno garantizará que se utilice la misma fuente en todos los navegadores. sans-serifconfigurará Arial en Chrome para Windows, pero Roboto en Chrome para Android. Además, la geometría de algunas fuentes puede provocar un reflujo incluso si haces todo bien. Las fuentes monoespaciadas tienden a dar los mejores resultados. Así que asegúrese siempre de que sus fuentes estén perfectas.

Consulte este ejemplo sin reflujo en la siguiente demostración:

Texto sin flujo dentro de un contenedor

Todo lo que tenemos que hacer ahora es aplicar el tamaño y el ancho de la fuente al contenedor en lugar de a los elementos de texto directamente. El texto que contiene solo deberá configurarse en width: 100%. Esto no es necesario en el caso de párrafos y encabezados, ya que de todos modos son elementos a nivel de bloque y llenarán el ancho del contenedor automáticamente.

Una ventaja de aplicar esto en un contenedor principal es que sus hijos reaccionarán y cambiarán de tamaño automáticamente sin tener que configurar los tamaños y anchos de fuente uno por uno. Además, si necesitamos cambiar el tamaño de fuente de un solo elemento sin afectar a los demás, todo lo que tendríamos que hacer es cambiar su tamaño de fuente a cualquier emcantidad y, naturalmente, será relativo al tamaño de fuente del contenedor.

El texto sin redistribución es complicado, pero es un efecto sutil que puede darle un toque agradable a un diseño.

Terminando

Para finalizar, preparé una pequeña demostración de cómo podría verse todo esto en un escenario de la vida real.

En este ejemplo final, también puedes cambiar el tamaño de fuente raíz y la clamp()función se recalculará automáticamente para que el texto pueda tener el tamaño correcto en cualquier situación.

Aunque el objetivo de este artículo es utilizar clamp()tamaños de fuente, esta misma técnica podría usarse en cualquier propiedad CSS que reciba una unidad de longitud. Ahora, no estoy diciendo que debas usar esto en todas partes. Muchas veces, font-size: 1remtodo lo que necesitas es un buen viejo. Sólo estoy tratando de mostrarte cuánto control puedes tener cuando lo necesitas.

Personalmente, creo que clamp()es una de las mejores cosas que ha llegado a CSS y no puedo esperar a ver qué otros usos se le ocurren a la gente a medida que se generaliza cada vez más.

SUSCRÍBETE A NUESTRO BOLETÍN 
No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir

Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion