Fluid Responsive Typografie mit CSS Poly Fluid Sizing

Veröffentlicht: 2022-03-10
Kurze Zusammenfassung ↬ Flüssige Layouts sind seit Jahren ein normaler Bestandteil der Frontend-Entwicklung. Die Idee der fließenden Typografie ist jedoch relativ neu und muss noch vollständig erforscht werden. Bis jetzt besteht die Vorstellung der meisten Entwickler von flüssiger Typografie einfach darin, Viewport-Einheiten zu verwenden, möglicherweise mit einigen minimalen und maximalen Größen. In diesem Artikel werden wir es auf eine andere Ebene bringen. Wir werden untersuchen, wie man mithilfe von gut unterstützten Browserfunktionen und etwas grundlegender Algebra skalierbare, flüssige Typografie über mehrere Haltepunkte und vordefinierte Schriftgrößen hinweg erstellt. Das Beste daran ist, dass Sie alles mit Sass automatisieren können.

In diesem Artikel werden wir es auf eine andere Ebene bringen. Wir werden untersuchen, wie man mithilfe von gut unterstützten Browserfunktionen und etwas grundlegender Algebra skalierbare, flüssige Typografie über mehrere Haltepunkte und vordefinierte Schriftgrößen hinweg erstellt. Das Beste daran ist, dass Sie alles mit Sass automatisieren können.

Weiterführende Literatur zu SmashingMag:

  • Wirklich fließende Typografie mit vh- und vw-Einheiten
  • Typografische Muster im HTML-E-Mail-Newsletter-Design
  • Die guten, die schlechten und die großartigen Beispiele für Web-Typografie
  • Tools und Ressourcen für eine aussagekräftigere Web-Typografie

Bei der Arbeit mit kreativen Designern an Webseitendesigns ist es ziemlich üblich, mehrere Sketch- oder Photoshop-Zeichenflächen/-Layouts zu erhalten, eine für jeden Haltepunkt. In diesem Design haben Elemente (wie eine h1 -Überschrift) normalerweise an jedem Haltepunkt unterschiedliche Größen. Zum Beispiel:

Mehr nach dem Sprung! Lesen Sie unten weiter ↓
  1. Das h1 beim kleinen Layout könnte 22px sein
  2. Das h1 beim mittleren Layout könnte 24px sein
  3. Das h1 beim großen Layout könnte 34px sein

Das absolute Minimum an CSS dafür sind Medienabfragen:

 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; } }

Dies ist ein guter erster Schritt, aber Sie beschränken die font-size nur auf das, was vom Designer an den bereitgestellten Haltepunkten angegeben wurde. Was würde der Designer sagen, wenn Sie ihn fragen würden: „Wie sollte die font-size bei einem 850 Pixel breiten Darstellungsbereich sein?“ Die Antwort lautet in den meisten Fällen, dass es irgendwo zwischen 24px und 34px liegen würde. Aber im Moment sind es laut Ihrem CSS nur 24 Pixel, was wahrscheinlich nicht das ist, was sich der Designer vorgestellt hat.

An dieser Stelle haben Sie die Möglichkeit, zu berechnen, wie groß diese Größe sein sollte, und einen weiteren Haltepunkt hinzuzufügen. Das ist einfach genug. Aber was ist mit all den anderen Auflösungen? Welche font-size sollte bei einer Breite von 800 Pixeln verwendet werden? Was ist mit 900px? Was ist mit 935px? Offensichtlich wird der Designer Ihnen kein vollständiges Layout für jede einzelne mögliche Auflösung zur Verfügung stellen. Selbst wenn dies der Fall wäre, sollten Sie Dutzende (oder Hunderte) von Haltepunkten für all die verschiedenen font-sizes hinzufügen, die vom Designer gewünscht werden? Natürlich nicht.

Ihr Layout wird bereits fließend mit der Breite Ihres Darstellungsbereichs skaliert. Wäre es nicht schön, wenn Ihre Typografie vorhersehbar mit Ihrem fließenden Layout skaliert würde? Was können wir noch tun, um dies zu verbessern?

Viewport-Einheiten zur Rettung?

Viewport-Einheiten sind ein weiterer Schritt in die richtige Richtung. Sie ermöglichen es Ihrem Text, die Größe fließend an Ihre Layouts anzupassen. Und die Browserunterstützung ist heutzutage großartig.

Kann ich Ansichtsfenster verwenden?
(Große Version anzeigen)

Die Lebensfähigkeit von Viewport-Einheiten hängt jedoch stark von den ursprünglichen kreativen Designs für eine Webseite ab. Es wäre großartig, einfach Ihre font-size mit vw und fertig:

 h1 { font-size: 2vw; } 

Dies funktioniert jedoch nur, wenn Ihre kreativen Zeichenflächen dies berücksichtigen. Hat der Designer eine Textgröße gewählt, die genau 2 % der Breite jeder seiner Zeichenflächen entspricht? Natürlich nicht. Lassen Sie uns berechnen, wie hoch der vw Wert für jeden unserer Haltepunkte sein müsste:

22px Größe bei 576px Breite = 22576 *100 = 3,82vw 24px Größe bei 768px Breite = 24768 *100 = 3,13vw 34px Größe bei 992px Breite = 34992 *100 = 3,43vw

Sie sind nah dran, aber sie sind nicht alle gleich. Sie müssten also immer noch Medienabfragen verwenden, um zwischen Textgrößen zu wechseln, und es gäbe immer noch Sprünge. Und bedenken Sie diesen seltsamen Nebeneffekt:

@ 767px, 3,82% der Viewport-Breite beträgt 29px. Wenn der Viewport 1 Pixel breiter ist, sinkt die font-size plötzlich wieder auf 24px . Diese Animation eines Ansichtsfensters, dessen Größe geändert wird, demonstriert diesen unerwünschten Nebeneffekt:

Diese dramatische Änderung der Schriftgröße ist mit ziemlicher Sicherheit nicht das, was sich der Designer vorgestellt hat. Wie lösen wir also dieses Problem?

Statistische lineare Regression?

Warte ab. Was? Ja, dies ist ein Artikel über CSS, aber etwas grundlegende Mathematik kann einen großen Beitrag zu einer eleganten Lösung unseres Problems leisten.

Lassen Sie uns zunächst unsere Auflösungen und die entsprechenden Textgrößen in einem Diagramm darstellen:

Streudiagramm der Schriftgröße und der entsprechenden Ansichtsfensterbreite
Streudiagramm der font-size Breite (Google Spreadsheets) (Große Version anzeigen)

Hier sehen Sie ein Streudiagramm der vom Designer angegebenen Textgrößen bei den definierten Ansichtsfensterbreiten. Die x-Achse ist die Ansichtsfensterbreite und die y-Achse ist die font-size . Sehen Sie diese Zeile? Das nennt man Trendlinie . Es ist eine Möglichkeit, basierend auf den bereitgestellten Daten einen interpolierten font-size für jede Ansichtsfensterbreite zu finden.

Die Trendlinie ist der Schlüssel zu all dem

Wenn Sie Ihre font-size gemäß dieser Trendlinie einstellen könnten, hätten Sie ein h1, das sich reibungslos auf alle Auflösungen skaliert , die dem entsprechen würden, was der Designer beabsichtigt hat. Schauen wir uns zunächst die Mathematik an. Die Gerade wird durch diese Gleichung definiert:

Definition linearer Gleichungen
Definition linearer Gleichungen
  • m = Steigung
  • b = der y-Achsenabschnitt
  • x = die aktuelle Ansichtsfensterbreite
  • y = die resultierende font-size

Es gibt mehrere Methoden zur Bestimmung der Steigung und des y-Achsenabschnitts. Wenn mehrere Werte beteiligt sind, ist eine gängige Methode die Anpassung nach der Methode der kleinsten Quadrate:

Kleinsten Quadrate

Sobald Sie diese Berechnungen durchgeführt haben, haben Sie Ihre Trendliniengleichung.

Wie verwende ich das in CSS?

Okay, das wird ziemlich schwer für die Mathematik. Wie verwenden wir dieses Zeug eigentlich in der Front-End-Webentwicklung? Die Antwort ist CSS calc() ! Wieder einmal eine ziemlich neue CSS-Technologie, die sehr gut unterstützt wird.

Kann ich Calc verwenden?
(Große Version anzeigen)

Sie können die Trendliniengleichung wie folgt verwenden:

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

Sobald Sie Ihre Steigung und Ihren y-Achsenabschnitt gefunden haben, schließen Sie sie einfach an!

Hinweis: Sie müssen die Steigung mit 100 multiplizieren, da Sie sie als vw Einheit verwenden, die 1/100 der Viewport-Breite beträgt.

Kann dies automatisiert werden?

Ich habe die Methode der kleinsten Quadrate in eine einfach zu verwendende Sass-Funktion portiert:

 /// 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}); }

Funktioniert das wirklich? Öffnen Sie diesen CodePen und ändern Sie die Größe Ihres Browserfensters. Es klappt! Die Schriftgrößen sind ziemlich nah an dem, was das ursprüngliche Design verlangte, und sie skalieren nahtlos mit Ihrem Layout.

Least Squares Fit SCSS-Test user="jakobud"]Siehe den Pen Least Squares Fit SCSS-Test von Jake Wilson (@jakobud) auf CodePen.

Least Squares Fit SCSS-Test user="jakobud"]Siehe den Pen Least Squares Fit SCSS-Test von Jake Wilson (@jakobud) auf CodePen.

Nun, zugegeben, es ist nicht perfekt. Die Werte liegen nahe am Originaldesign, stimmen aber nicht ganz überein. Dies liegt daran, dass eine lineare Trendlinie eine Annäherung an bestimmte Schriftgrößen bei bestimmten Darstellungsfensterbreiten ist. Dies ist ein Erbe der linearen Regression. Es gibt immer einen Fehler in Ihren Ergebnissen. Es ist ein Kompromiss zwischen Einfachheit und Genauigkeit. Denken Sie auch daran, je vielfältiger Ihre Textgrößen sind, desto mehr Fehler wird es in Ihrer Trendlinie geben.

Können wir es besser machen?

Polynom-Least-Squares-Fit

Um eine genauere Trendlinie zu erhalten, müssen Sie sich mit fortgeschritteneren Themen befassen, wie z. B. einer Polynomregressions-Trendlinie, die etwa so aussehen könnte:

Trendlinie der polynomialen Regression
Trendlinie der Polynomregression (Google Spreadsheets) (Große Version anzeigen)

Das ist jetzt eher so! Viel genauer als unsere Gerade. Eine grundlegende polynomiale Regressionsgleichung sieht folgendermaßen aus:

Eine Polynomgleichung 3. Grades
Eine Polynomgleichung 3. Grades

Je genauer Sie Ihre Kurve haben wollen, desto komplizierter wird die Gleichung. Leider ist dies in CSS nicht möglich . calc() kann diese Art von fortgeschrittener Mathematik einfach nicht ausführen. Insbesondere können Sie keine Exponenten berechnen:

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

Bis calc() diese Art von nichtlinearer Mathematik unterstützt, bleiben wir also nur bei linearen Gleichungen hängen. Können wir noch etwas tun, um dies zu verbessern?

Haltepunkte und mehrere lineare Gleichungen

Was wäre, wenn wir nur eine gerade Linie zwischen jedem Paar von Haltepunkten berechnen würden? Etwas wie das:

Trendlinien der linearen Regression zwischen mehreren Wertepaaren
Trendlinien der linearen Regression zwischen mehreren Wertepaaren (Google Spreadsheets) (Große Version anzeigen)

In diesem Beispiel würden wir also die gerade Linie zwischen 22px und 24px und dann eine weitere zwischen 24px und 34px . Der Sass würde so aussehen:

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

Wir könnten die Methode der kleinsten Quadrate für diese calc() Werte verwenden, aber da es nur eine gerade Linie zwischen 2 Punkten ist, könnte die Mathematik stark vereinfacht werden. Erinnerst du dich an die Gleichung für eine gerade Linie?

Definition linearer Gleichungen
Definition linearer Gleichungen

Da wir jetzt nur über 2 Punkte sprechen, ist es trivial, die Steigung (m) und den y-Achsenabschnitt (b) zu finden:

Ermitteln der Steigung und des y-Achsenabschnitts einer linearen Gleichung
Ermitteln der Steigung und des y-Achsenabschnitts einer linearen Gleichung

Hier ist eine Sass-Funktion dafür:

 /// 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}); }

Verwenden Sie jetzt einfach die lineare Interpolationsfunktion an mehreren Haltepunkten in Ihrem Sass. Lassen Sie uns auch einige minimale und maximale font-sizes einwerfen:

 // 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; } }

Und es generiert dieses 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; } } 

Der heilige Gral der CSS-Größenanpassung?

Lassen Sie uns das alles in einem netten Sass-Mixin zusammenfassen (für die Faulen und Effizienten!). Ich präge diese Methode 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)); } }

Dieses Sass-Mixin erfordert einige Sass-Funktionen in den folgenden Github-Gists:

  • lineare Interpolation
  • Kartensortierung
  • Listensortierung
  • Liste entfernen

Das Mixin poly-fluid-sizing() führt eine lineare Interpolation für jedes Paar von Ansichtsfensterbreiten durch und legt eine minimale und maximale Größe fest. Sie können dies in jedes Sass-Projekt importieren und einfach verwenden, ohne die Mathematik dahinter kennen zu müssen. Hier ist der letzte CodePen, der diese Methode verwendet.

Poly Fluid Sizing mit linearen Gleichungen, Viewport-Einheiten und calc() user="jakobud"]Sehen Sie sich den Pen Poly Fluid Sizing mit linearen Gleichungen, Viewport-Einheiten und calc() an von Jake Wilson (@jakobud) auf CodePen.

Poly Fluid Sizing mit linearen Gleichungen, Viewport-Einheiten und calc() user="jakobud"]Sehen Sie sich den Pen Poly Fluid Sizing mit linearen Gleichungen, Viewport-Einheiten und calc() an] Poly Fluid Sizing mit linearen Gleichungen, Viewport-Einheiten und calc() von Jake Wilson (@jakobud) auf CodePen.

Ein paar Anmerkungen

  • Offensichtlich gilt diese Methode nicht nur für die font-size sondern für alle Einheiten-/Längeneigenschaften ( margin , padding usw.). Sie übergeben den gewünschten Eigenschaftsnamen als Zeichenfolge an das Mixin.
  • Die Sass-Karte der Viewport-Breite + Größe-Wertepaare kann in beliebiger Reihenfolge an das poly-fluid-sizing() Mixin übergeben werden. Die Karte wird automatisch nach Ansichtsfensterbreite von der niedrigsten zur höchsten sortiert . Sie könnten also eine Karte wie diese übergeben, und es würde gut funktionieren:
 $map: (576px: 22px, 320px: 18px, 992px: 34px, 768px: 24px); @include poly-fluid-sizing('font-size', $map);
  • Eine Einschränkung für diese Methode besteht darin, dass Sie keine gemischten Einheiten an das Mixin übergeben können. Zum Beispiel 3em @ 576px Breite. Sass wird einfach nicht wirklich wissen, was er da mathematisch machen soll.

Fazit

Ist das das Beste, was wir tun können? Ist Poly Fluid Sizing der Heilige Gral der flüssigen Einheitsgröße in CSS? Vielleicht. CSS unterstützt derzeit nichtlineare Animations- und Übergangszeitfunktionen, also besteht vielleicht die Möglichkeit, dass calc() dies eines Tages ebenfalls unterstützt. In diesem Fall könnte die nichtlineare, polynomiale Regression erneut einen Blick wert sein. Aber vielleicht auch nicht… Lineare Skalierung könnte sowieso überlegen sein.

Ich begann Anfang 2017 mit der Erforschung dieser Idee und entwickelte schließlich die obige Lösung. Seitdem habe ich einige Entwickler gesehen, die ähnliche Ideen und verschiedene Teile dieses Puzzles hatten. Ich dachte, es wäre an der Zeit, meine Methode und meinen Weg dorthin zu teilen. Viewport-Einheiten. Berechne(). Sass. Haltepunkte. Keines dieser Dinge ist neu. Dies sind alles Browserfunktionen, die es seit Jahren gibt (mit unterschiedlichem Unterstützungsgrad). Ich habe sie nur auf eine Weise zusammen verwendet, die noch nicht vollständig erforscht war. Scheuen Sie sich nicht, sich die Tools anzusehen, die Sie jeden Tag verwenden, und denken Sie über den Tellerrand hinaus, wie Sie sie besser nutzen und Ihre Fähigkeiten erweitern können.