Ich habe mir eine kleine Lösung für fluid typography nur mit nativem CSS gebaut. Dabei wollte ich die Schriftgrößen zwischen einem Minimum und einem Maximum dynamisch an die Viewport-Breite anpassen, basierend auf der bekannten Formel:
Code:
slope = (maxFontSize - minFontSize) / (maxWidth - minWidth)
yAxisIntersection = -minWidth * slope + minFontSize
preferredValue = yAxisIntersection[rem] + (slope * 100)[vw]
Link zur Beschreibung bei CSS-Tricks: https://css-tricks.com/linearly-scal...-the-viewport/
Tokens im :root
Zuerst definiere ich die Fontgrößen und Breakpoints als Custom Properties.
Dabei gibt es zwei Varianten pro Wert:
- einmal mit Einheit (rem) ? für die direkte Verwendung in clamp()
- einmal ohne Einheit (nur Zahl) ? damit ich im calc() rechnen kann.
Beispiel:
Code:
:root {
/* font sizes */
--font-size-heading-lg-min: 2.125rem;
--font-size-heading-lg-max: 2.5rem;
--font-size-heading-lg-min-no-unit: 2.125;
--font-size-heading-lg-max-no-unit: 2.5;
--font-size-heading-xl-min: 2.65rem;
--font-size-heading-xl-max: 3.625rem;
--font-size-heading-xl-min-no-unit: 2.65;
--font-size-heading-xl-max-no-unit: 3.625;
--font-size-heading-xxl-min: 2.875rem;
--font-size-heading-xxl-max: 6rem;
--font-size-heading-xxl-min-no-unit: 2.875;
--font-size-heading-xxl-max-no-unit: 6;
/* breakpoints for fluid typography */
--fluid-breakpoint-min: 26.25rem; /* 420px */
--fluid-breakpoint-max: 90rem; /* 1440px */
--fluid-breakpoint-min-no-unit: 26.25; /* 420px */
--fluid-breakpoint-max-no-unit: 90; /* 1440px */
}
Warum das?
CSS erlaubt es nicht, Einheiten zu „wegzudividieren“. Man kann keine Länge durch eine Länge teilen (10rem / 2rem ist ungültig).
Darum trenne ich die Zahlen (unitless) und die Längen.
Anwendung in h1 und h2
Für jedes Heading berechne ich lokal die Parameter:
Code:
h1 {
/* fluid typography parameters */
--min-font-size: var(--font-size-heading-xxl-min);
--max-font-size: var(--font-size-heading-xxl-max);
--min-font-size-no-unit: var(--font-size-heading-xxl-min-no-unit);
--max-font-size-no-unit: var(--font-size-heading-xxl-max-no-unit);
/* fluid typography */
--slope: calc(
(var(--max-font-size-no-unit) - var(--min-font-size-no-unit)) /
(var(--fluid-breakpoint-max-no-unit) - var(--fluid-breakpoint-min-no-unit))
);
--intercept: calc(
var(--min-font-size) - (var(--max-font-size-no-unit) - var(--min-font-size-no-unit)) /
(var(--fluid-breakpoint-max-no-unit) - var(--fluid-breakpoint-min-no-unit)) * var(--fluid-breakpoint-min)
);
font-size: var(--font-size-heading-xl-min); /* Fallback */
font-size: clamp(var(--min-font-size), calc(var(--intercept) + var(--slope) * 100vw), var(--max-font-size));
}
h2 {
/* fluid typography parameters */
--min-font-size: var(--font-size-heading-xl-min);
--max-font-size: var(--font-size-heading-xl-max);
--min-font-size-no-unit: var(--font-size-heading-xl-min-no-unit);
--max-font-size-no-unit: var(--font-size-heading-xl-max-no-unit);
/* fluid typography */
--slope: calc(
(var(--max-font-size-no-unit) - var(--min-font-size-no-unit)) /
(var(--fluid-breakpoint-max-no-unit) - var(--fluid-breakpoint-min-no-unit))
);
--intercept: calc(
var(--min-font-size) - (var(--max-font-size-no-unit) - var(--min-font-size-no-unit)) /
(var(--fluid-breakpoint-max-no-unit) - var(--fluid-breakpoint-min-no-unit)) * var(--fluid-breakpoint-min)
);
font-size: var(--font-size-heading-xl-min); /* Fallback */
font-size: clamp(var(--min-font-size), calc(var(--intercept) + var(--slope) * 100vw), var(--max-font-size));
}
- clamp() sorgt dafür, dass die Schrift nie kleiner als das Minimum und nie größer als das Maximum wird.
- Der mittlere Teil (intercept + slope * 100vw) gibt den fließenden Übergang zwischen den beiden Werten.
- Die erste font-size-Zeile ist ein Fallback für alte Browser, die clamp() nicht verstehen.
Alternativ gibt es auch Apps zum Berechnen der Werte: https://fluid.style