Tipografia reattiva ai fluidi con dimensionamento fluido CSS Poly

Pubblicato: 2022-03-10
Riepilogo rapido ↬ I layout fluidi sono stati una parte normale dello sviluppo front-end da anni. L'idea di tipografia fluida, tuttavia, è relativamente nuova e deve ancora essere completamente esplorata. Fino ad ora, l'idea di tipografia fluida della maggior parte degli sviluppatori consisteva semplicemente nell'utilizzare le unità Viewport, magari con alcune dimensioni minime e massime. In questo articolo, lo porteremo a un altro livello. Esamineremo come creare una tipografia scalabile e fluida su più punti di interruzione e dimensioni dei caratteri predefinite utilizzando funzionalità del browser ben supportate e alcune algebre di base. La parte migliore è che puoi automatizzare tutto usando Sass.

In questo articolo, lo porteremo a un altro livello. Esamineremo come creare una tipografia scalabile e fluida su più punti di interruzione e dimensioni dei caratteri predefinite utilizzando funzionalità del browser ben supportate e alcune algebre di base. La parte migliore è che puoi automatizzare tutto usando Sass.

Ulteriori letture su SmashingMag:

  • Tipografia veramente fluida con unità vh e vw
  • Modelli tipografici nel design della newsletter e-mail HTML
  • Il buono, il cattivo e i grandi esempi di tipografia web
  • Strumenti e risorse per una tipografia Web più significativa

Quando si lavora con designer creativi sui progetti di pagine Web, è abbastanza comune ricevere più tavole da disegno/layout di Sketch o Photoshop, uno per ogni punto di interruzione. In quel progetto, gli elementi (come un'intestazione h1 ) avranno generalmente dimensioni diverse a ciascun punto di interruzione. Per esempio:

Altro dopo il salto! Continua a leggere sotto ↓
  1. L' h1 nel layout piccolo potrebbe essere 22px
  2. L' h1 con il layout medio potrebbe essere 24px
  3. L' h1 nel layout grande potrebbe essere 34px

Il CSS minimo indispensabile per questo utilizza media query:

 h1 { font-size: 22px; } @media (min-width:576px) { h1 { font-size: 22px; } } @media (min-width:768px) { h1 { font-size: 24px; } } @media (min-width:992px) { h1 { font-size: 34px; } }

Questo è un buon primo passo, ma stai limitando la font-size del carattere solo a ciò che è stato specificato dal designer nei punti di interruzione forniti. Cosa direbbe il designer se chiedessi: "Quale dovrebbe essere la font-size del carattere in una finestra ampia 850 px?" La risposta nella maggior parte dei casi è che sarebbe tra 24px e 34px. Ma in questo momento, è solo 24px secondo il tuo CSS, che probabilmente non è ciò che il designer aveva immaginato.

La tua opzione a questo punto è calcolare quale dovrebbe essere quella dimensione e aggiungere un altro punto di interruzione. È abbastanza facile. Ma che dire di tutte le altre risoluzioni? Quale dovrebbe essere la font-size del carattere a 800 px di larghezza? E 900px? E 935px? Ovviamente il designer non ti fornirà un layout completo per ogni singola risoluzione possibile. Anche se lo facessero, dovresti aggiungere dozzine (o centinaia) di punti di interruzione per tutte le diverse font-sizes dei caratteri desiderate dal designer? Ovviamente no.

Il tuo layout si sta già ridimensionando in modo fluido con la larghezza della tua finestra. Non sarebbe bello se la tua tipografia si adattasse in modo prevedibile al tuo layout fluido? Cos'altro possiamo fare per migliorare questo aspetto?

Unità Viewport in soccorso?

Le unità Viewport sono un altro passo nella giusta direzione. Consentono al tuo testo di ridimensionarsi in modo fluido con i tuoi layout. E il supporto del browser è ottimo in questi giorni.

Posso usare Viewport?
(Visualizza versione grande)

Ma la fattibilità delle unità Viewport dipende molto dai progetti creativi originali per una pagina web. Sarebbe fantastico impostare la font-size del carattere usando vw e il gioco è fatto:

 h1 { font-size: 2vw; } 

Ma questo funziona solo se le tue tavole da disegno creative ne tengono conto. Il designer ha scelto una dimensione del testo che corrispondesse esattamente al 2% della larghezza di ciascuna delle sue tavole da disegno? Ovviamente no. Calcoliamo quale dovrebbe essere il valore vw per ciascuno dei nostri punti di interruzione:

Dimensioni 22px @ 576px larghezza = 22576 *100 = 24px Dimensioni 24px @ 768px larghezza = 24768 *100 = 34px Dimensioni 34px @ 992px larghezza = 34992 *100 = 3.43vw

Sono vicini ma non sono tutti uguali. Quindi dovresti comunque utilizzare le query multimediali per passare tra le dimensioni del testo e ci sarebbero comunque dei salti. E considera questo strano effetto collaterale:

@ 767px, il 3,82% della larghezza della finestra è 29px. Se il viewport è più largo di 1 pixel, la font-size del carattere torna improvvisamente a 24px . Questa animazione di una finestra che viene ridimensionata dimostra questo effetto collaterale indesiderabile:

Questo drastico cambiamento nella dimensione del carattere non è quasi sicuramente ciò che il designer aveva immaginato. Allora come risolviamo questo problema?

Regressione lineare statistica?

Attesa. Che cosa? Sì, questo è un articolo sui CSS, ma un po' di matematica di base può fare molto verso una soluzione elegante al nostro problema.

Innanzitutto, tracciamo le nostre risoluzioni e le dimensioni del testo corrispondenti su un grafico:

Grafico a dispersione della dimensione del carattere e della larghezza della finestra corrispondente
Grafico a dispersione della font-size del carattere e della larghezza della finestra di visualizzazione corrispondente (fogli di lavoro di Google) (Visualizza versione grande)

Qui puoi vedere un grafico a dispersione delle dimensioni del testo specificate dal designer alle larghezze della finestra definite. L'asse x è la larghezza della finestra e l'asse y è la font-size del carattere. Vedi quella linea? Si chiama trendline . È un modo per trovare un valore interpolato font-size per qualsiasi larghezza della finestra, in base ai dati forniti.

La Trendline è la chiave di tutto questo

Se potessi impostare la font-size del carattere in base a questa linea di tendenza, avresti un h1 che si adatta senza problemi a tutte le risoluzioni che si avvicinerebbero a corrispondere a ciò che il designer intendeva. Per prima cosa, diamo un'occhiata alla matematica. La retta è definita da questa equazione:

Definizione di equazioni lineari
Definizione di equazioni lineari
  • m = pendenza
  • b = l'intercetta y
  • x = la larghezza della finestra corrente
  • y = la font-size risultante

Esistono diversi metodi per determinare la pendenza e l'intercetta y. Quando sono coinvolti più valori, un metodo comune è l'adattamento dei minimi quadrati:

Minimi quadrati

Una volta eseguiti questi calcoli, hai la tua equazione della linea di tendenza.

Come lo uso nei CSS?

Ok, la matematica sta diventando piuttosto pesante. Come utilizziamo effettivamente questa roba nello sviluppo web front-end? La risposta è CSS calc() ! Ancora una volta, una tecnologia CSS abbastanza nuova che è molto ben supportata.

Posso usare Calc?
(Visualizza versione grande)

Puoi usare l'equazione della linea di tendenza in questo modo:

 h1 { font-size: calc({slope}*100vw + {y-intercept}px); }

Una volta trovata la pendenza e l'intercettazione a y, basta collegarli!

Nota: devi moltiplicare la pendenza per 100 poiché la stai utilizzando come unità vw che è 1/100 della larghezza della finestra.

Può essere automatizzato?

Ho portato il metodo di adattamento ai minimi quadrati in una funzione Sass facile da usare:

 /// least-squares-fit /// Calculate the least square fit linear regression of provided values /// @param {map} $map - A Sass map of viewport width and size value combinations /// @return Linear equation as a calc() function /// @example /// font-size: least-squares-fit((576px: 24px, 768px: 24px, 992px: 34px)); /// @author Jake Wilson <[email protected]> @function least-squares-fit($map) { // Get the number of provided breakpoints $length: length(map-keys($map)); // Error if the number of breakpoints is < 2 @if ($length < 2) { @error "leastSquaresFit() $map must be at least 2 values" } // Calculate the Means $resTotal: 0; $valueTotal: 0; @each $res, $value in $map { $resTotal: $resTotal + $res; $valueTotal: $valueTotal + $value; } $resMean: $resTotal/$length; $valueMean: $valueTotal/$length; // Calculate some other stuff $multipliedDiff: 0; $squaredDiff: 0; @each $res, $value in $map { // Differences from means $resDiff: $res - $resMean; $valueDiff: $value - $valueMean; // Sum of multiplied differences $multipliedDiff: $multipliedDiff + ($resDiff * $valueDiff); // Sum of squared resolution differences $squaredDiff: $squaredDiff + ($resDiff * $resDiff); } // Calculate the Slope $m: $multipliedDiff / $squaredDiff; // Calculate the Y-Intercept $b: $valueMean - ($m * $resMean); // Return the CSS calc equation @return calc(#{$m*100}vw + #{$b}); }

Funziona davvero? Apri questo CodePen e ridimensiona la finestra del browser. Funziona! Le dimensioni dei caratteri sono abbastanza vicine a quelle richieste dal design originale e si adattano perfettamente al tuo layout.

Test SCSS Least Squares Fit user="jakobud"]Guarda il test SCSS Pen Least Squares Fit di Jake Wilson (@jakobud) su CodePen.

Test SCSS Least Squares Fit utente=“jakobud”]Vedi il test SCSS Pen Least Squares Fit di Jake Wilson (@jakobud) su CodePen.

Ora, devo ammettere, non è perfetto. I valori sono vicini al design originale ma non corrispondono del tutto. Ciò è dovuto al fatto che una linea di tendenza lineare è un'approssimazione di dimensioni di caratteri specifiche a larghezze di visualizzazione specifiche. Questo è ereditario della regressione lineare. C'è sempre qualche errore nei tuoi risultati. È un compromesso tra semplicità e precisione. Inoltre, tieni presente che più le dimensioni del tuo testo sono varie, maggiore sarà l'errore nella tua linea di tendenza.

Possiamo fare di meglio?

Minimi quadrati polinomiali Fit

Per ottenere una linea di tendenza più accurata, è necessario esaminare argomenti più avanzati, come una linea di tendenza di regressione polinomiale che potrebbe assomigliare a questa:

Linea di tendenza della regressione polinomiale
Linea di tendenza della regressione polinomiale (fogli di lavoro di Google) (Visualizza versione grande)

Ora è più così ! Molto più preciso della nostra linea retta. Un'equazione di regressione polinomiale di base è simile alla seguente:

Un'equazione polinomiale di 3° grado
Un'equazione polinomiale di 3° grado

Più precisa vuoi la tua curva, più complicata diventa l'equazione. Sfortunatamente, non puoi farlo in CSS . calc() semplicemente non può fare questo tipo di matematica avanzata. In particolare, non puoi calcolare gli esponenti:

 font-size: calc(3vw * 3vw); /* This doesn't work in CSS */

Quindi, finché calc() non supporta questo tipo di matematica non lineare, siamo bloccati solo con equazioni lineari . C'è qualcos'altro che possiamo fare per migliorare questo aspetto?

Punti di interruzione ed equazioni lineari multiple

E se calcolassimo solo una linea retta tra ogni coppia di punti di interruzione? Qualcosa come questo:

Linee di tendenza della regressione lineare tra più coppie di valori
Linee di tendenza della regressione lineare tra più coppie di valori (fogli di lavoro di Google) (Visualizza versione grande)

Quindi in questo esempio calcoleremo la linea retta tra 22px e 24px e poi un'altra tra 24px e 34px . Il Sass sarebbe così:

 // SCSS h1 { @media (min-width:576px) { font-size: calc(???); } @media (min-width:768px) { font-size: calc(???); } }

Potremmo usare il metodo di adattamento dei minimi quadrati per quei valori calc() ma poiché è solo una linea retta tra 2 punti, la matematica potrebbe essere notevolmente semplificata. Ricordi l'equazione per una retta?

Definizione di equazioni lineari
Definizione di equazioni lineari

Poiché ora stiamo parlando di soli 2 punti, trovare la pendenza (m) e l'intercetta y (b) è banale:

Trovare la pendenza e l'intercetta y di un'equazione lineare
Trovare la pendenza e l'intercetta y di un'equazione lineare

Ecco una funzione Sass per questo:

 /// linear-interpolation /// Calculate the definition of a line between two points /// @param $map - A Sass map of viewport widths and size value pairs /// @returns A linear equation as a calc() function /// @example /// font-size: linear-interpolation((320px: 18px, 768px: 26px)); /// @author Jake Wilson <[email protected]> @function linear-interpolation($map) { $keys: map-keys($map); @if (length($keys) != 2) { @error "linear-interpolation() $map must be exactly 2 values"; } // The slope $m: (map-get($map, nth($keys, 2)) - map-get($map, nth($keys, 1)))/(nth($keys, 2) - nth($keys,1)); // The y-intercept $b: map-get($map, nth($keys, 1)) - $m * nth($keys, 1); // Determine if the sign should be positive or negative $sign: "+"; @if ($b < 0) { $sign: "-"; $b: abs($b); } @return calc(#{$m*100}vw #{$sign} #{$b}); }

Ora, usa semplicemente la funzione di interpolazione lineare su più punti di interruzione nel tuo Sass. Inoltre, aggiungiamo alcune font-sizes :

 // SCSS h1 { // Minimum font-size font-size: 22px; // Font-size between 576 - 768 @media (min-width:576px) { $map: (576px: 22px, 768px: 24px); font-size: linear-interpolation($map); } // Font-size between 768 - 992 @media (min-width:768px) { $map: (768px: 24px, 992px: 34px); font-size: linear-interpolation($map); } // Maximum font-size @media (min-width:992px) { font-size: 34px; } }

E genera questo CSS:

 h1 { font-size: 22px; } @media (min-width: 576px) { h1 { font-size: calc(1.04166667vw + 16px); } } @media (min-width: 768px) { h1 { font-size: calc(4.46428571vw - 10.28571429px); } } @media (min-width: 992px) { h1 { font-size: 34px; } } 

Il Santo Graal del dimensionamento CSS?

Avvolgiamo tutto questo in un bel mixin Sass (per i pigri ed efficienti!). Sto coniando questo metodo Poly Fluid Sizing :

 /// poly-fluid-sizing /// Generate linear interpolated size values through multiple break points /// @param $property - A string CSS property name /// @param $map - A Sass map of viewport unit and size value pairs /// @requires function linear-interpolation /// @requires function map-sort /// @example /// @include poly-fluid-sizing('font-size', (576px: 22px, 768px: 24px, 992px: 34px)); /// @author Jake Wilson <[email protected]> @mixin poly-fluid-sizing($property, $map) { // Get the number of provided breakpoints $length: length(map-keys($map)); // Error if the number of breakpoints is < 2 @if ($length < 2) { @error "poly-fluid-sizing() $map requires at least values" } // Sort the map by viewport width (key) $map: map-sort($map); $keys: map-keys($map); // Minimum size #{$property}: map-get($map, nth($keys,1)); // Interpolated size through breakpoints @for $i from 1 through ($length - 1) { @media (min-width:nth($keys,$i)) { $value1: map-get($map, nth($keys,$i)); $value2: map-get($map, nth($keys,($i + 1))); // If values are not equal, perform linear interpolation @if ($value1 != $value2) { #{$property}: linear-interpolation((nth($keys,$i): $value1, nth($keys,($i+1)): $value2)); } @else { #{$property}: $value1; } } } // Maxmimum size @media (min-width:nth($keys,$length)) { #{$property}: map-get($map, nth($keys,$length)); } }

Questo mixin Sass richiede alcune funzioni Sass nei seguenti concetti Github:

  • interpolazione lineare
  • map-sort
  • elenco-ordinamento
  • lista-rimozione

Il mixin poly-fluid-sizing() eseguirà l'interpolazione lineare su ciascuna coppia di larghezze della finestra e imposterà una dimensione minima e massima. Puoi importarlo in qualsiasi progetto Sass e utilizzarlo facilmente senza dover conoscere la matematica dietro di esso. Ecco l'ultimo CodePen che utilizza questo metodo.

Dimensionamento del fluido polivalente utilizzando equazioni lineari, unità di visualizzazione e calc() user="jakobud"]Visualizza il ridimensionamento del fluido polivalente utilizzando equazioni lineari, unità di visualizzazione e calc()"] Ridimensionamento del fluido polivalente utilizzando equazioni lineari, unità di visualizzazione e calc() di Jake Wilson (@jakobud) su CodePen.

Dimensionamento del fluido polivalente utilizzando equazioni lineari, unità di visualizzazione e calc() user=“jakobud”]Guarda il ridimensionamento del fluido polivalente utilizzando equazioni lineari, unità di visualizzazione e calc()“] Ridimensionamento del fluido polivalente utilizzando equazioni lineari, unità di visualizzazione e calc() di Jake Wilson (@jakobud) su CodePen.

Alcune note

  • Ovviamente questo metodo si applica non solo alla font-size ma a qualsiasi proprietà di unità/lunghezza ( margin , padding , ecc.). Si passa il nome della proprietà desiderata nel mixin come una stringa.
  • La mappa Sass delle coppie di valori di larghezza + dimensione della finestra può essere passata in qualsiasi ordine nel mixin poly-fluid-sizing() . Ordina automaticamente la mappa in base alla larghezza del Viewport dal più basso al più alto . Quindi potresti passare una mappa come questa e funzionerebbe bene:
 $map: (576px: 22px, 320px: 18px, 992px: 34px, 768px: 24px); @include poly-fluid-sizing('font-size', $map);
  • Una limitazione per questo metodo è che non puoi passare in unità miste nel mixin. Ad esempio, 3em @ 576px larghezza. Sass non saprà davvero cosa fare matematicamente lì.

Conclusione

È questo il meglio che possiamo fare? Il Poly Fluid Sizing è il Santo Graal del dimensionamento dell'unità fluida nei CSS? Forse. I CSS attualmente supportano le funzioni di animazione non lineare e tempo di transizione, quindi forse c'è la possibilità che anche calc() lo supporti un giorno. Se ciò accade, vale la pena dare un'occhiata di nuovo alla regressione polinomiale non lineare. Ma forse no... Il ridimensionamento lineare potrebbe comunque essere superiore.

Ho iniziato a esplorare questa idea all'inizio del 2017 e alla fine ho sviluppato la soluzione di cui sopra. Da allora, ho visto alcuni sviluppatori elaborare idee simili e diversi pezzi di questo puzzle. Ho pensato che fosse giunto il momento per me di condividere il mio metodo e come ci sono arrivato. Unità Viewport. Calc(). Sass. Punti di interruzione. Nessuna di queste cose è nuova. Sono tutte funzionalità del browser che esistono da anni (con vari gradi di supporto). Li ho usati insieme solo in un modo che non era stato ancora completamente esplorato. Non aver mai paura di guardare gli strumenti che usi ogni giorno e pensare fuori dagli schemi a come utilizzarli meglio e far crescere il tuo set di abilità.