Fluid Typography clamp() mit nativem CSS und Custom Properties
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