Gunther: [SASS] Typografie - vertikaler Rhythmus

Beitrag lesen

@@Gunnar:

nuqneH

Ich versuche mich mal daran, das Ganze möglichst "komfortabel" in SASS umzusetzen.

Ich hab' da mal was "gebastelt" ...

Im Ergebnis erhält man die 'font-size' und 'line-height' für body,
sowie für alle Hx-Elemente die 'font-size', 'margin-top + bottom' und 'padding-top + bottom'. Und zwar so, dass jedes Hx-Element

  • einen margin-top hat, der einer Zeilenhöhe der Basis-Schriftgröße (Gridhöhe) entspricht
  • ein ganzzahliges Vielfaches der Gridhöhe einnimmt und vertikal zentriert ist

Dabei bleibt der line-height Faktor jeweils konstant!

  
@function lineHeight($fontSize, $lineWidth) {  
	@if unitless($fontSize) {  
		$fontSize: round($fontSize * $em-base);  
	}  
	@if unitless($lineWidth) {  
		$lineWidth: $lineWidth * $fontSize;  
	}  
	$lineHeightRatio : 1.61803398875 - 0.30901699437492734189635854149791 * (1 - $lineWidth / (pow($fontSize * 1.61803398875, 2)));  
	$lineHeightValue : round($fontSize * $lineHeightRatio);  
	$lineHeightRatio : $lineHeightValue / $fontSize;  
	@return $lineHeightRatio;  
}  
  
@mixin vrHeadings ($baseFontSize, $grid, $lineHeight, $fontSize) {  
	$gridLines: $fontSize * $baseFontSize * $lineHeight / $grid;  
	@if $gridLines == floor($gridLines) {  
		$gridLines: floor($gridLines) + 1;  
	}  
	@else {  
		$gridLines: ceil($gridLines);  
	}  
	$padding: (($grid * $gridLines) - ($fontSize * $baseFontSize * $lineHeight)) / 2 / $fontSize / $baseFontSize;  
	  
	font-size: $fontSize * 1em;  
	margin-top: $lineHeight / $fontSize * 1em;  
	margin-bottom: 0;  
	padding-top: $padding * 1em;  
	padding-bottom: $padding * 1em;  
}  
  
@mixin verticalRhythm($bp) {  
	$list: map-get($typo, $bp);  
	$baseFontSize: nth($list, 1);  
	$lineWidth:    nth($list, 2);  
	$h1FontSize:   nth($list, 3);  
	$h2FontSize:   nth($list, 4);  
	$h3FontSize:   nth($list, 5);  
	$h4FontSize:   nth($list, 6);  
	$h5FontSize:   nth($list, 7);  
	$h6FontSize:   nth($list, 8);  
	$lineHeight: lineHeight($baseFontSize, $lineWidth);  
	$grid: $baseFontSize * $lineHeight;  
	  
	body {  
		font-size: $baseFontSize * 1em;  
		line-height: lineHeight($baseFontSize, $lineWidth);  
	}  
	h1 {@include vrHeadings ($baseFontSize, $grid, $lineHeight, $h1FontSize);}  
	h2 {@include vrHeadings ($baseFontSize, $grid, $lineHeight, $h2FontSize);}  
	h3 {@include vrHeadings ($baseFontSize, $grid, $lineHeight, $h3FontSize);}  
	h4 {@include vrHeadings ($baseFontSize, $grid, $lineHeight, $h4FontSize);}  
	h5 {@include vrHeadings ($baseFontSize, $grid, $lineHeight, $h5FontSize);}  
	h6 {@include vrHeadings ($baseFontSize, $grid, $lineHeight, $h6FontSize);}  
}  

Das Ganze besteht aus einer (Hilfs-)Funktion und zwei Mixins.
Die Werte kommen aus einer Map ('typo'), die wie folgt aussieht (alle Angaben stellen 'em' Werte dar):

  
$typo: (  
	'bp14':		(1.125, 38, 2.5, 2, 1.5, 1.2, 1, 0.87),  
	'bp15':		(1.25, 38, 2.5, 2, 1.5, 1.2, 1, 0.87),  
	'bp16':		(1.375, 38, 2.5, 2, 1.5, 1.2, 1, 0.87),  
);  

Der Key entspricht (meinen) benannten Breakpoints und die Werte sind

  • die Basis-Schriftgröße für body (in r/em)
  • die Zeilenbreite in em
  • die Schriftgrößen H1 - H6 in em

Der Output sieht dann bspw. für 'bp16' so aus:

  
body {  
    font-size: 1.375em;  
    line-height: 1.5;  
}  
  
h1 {  
    font-size: 2.5em;  
    margin-top: 0.6em;  
    margin-bottom: 0;  
    padding-top: 0.15em;  
    padding-bottom: 0.15em;  
}  
  
h2 {  
    font-size: 2em;  
    margin-top: 0.75em;  
    margin-bottom: 0;  
    padding-top: 0.375em;  
    padding-bottom: 0.375em;  
}  
  
h3 {  
    font-size: 1.5em;  
    margin-top: 1em;  
    margin-bottom: 0;  
    padding-top: 0.25em;  
    padding-bottom: 0.25em;  
}  
  
h4 {  
    font-size: 1.2273em;  
    margin-top: 1.2222em;  
    margin-bottom: 0;  
    padding-top: 0.4722em;  
    padding-bottom: 0.4722em;  
}  
  
h5 {  
    font-size: 1em;  
    margin-top: 1.5em;  
    margin-bottom: 0;  
    padding-top: 0.75em;  
    padding-bottom: 0.75em;  
}  
  
h6 {  
    font-size: 0.87em;  
    margin-top: 1.72414em;  
    margin-bottom: 0;  
    padding-top: 0.11207em;  
    padding-bottom: 0.11207em;  
}  

Damit hat man dann einen vertikalen Rhythmus etabliert, dessen Gridhöhe der Basis-Schriftgröße mal dem line-height Faktor entspricht.

Und zwar unabhängig davon, welche Basis-Schriftgröße der User in seinem Browser eingestellt hat.

Sicher geht das alles noch "eleganter", bzw. lässt sich das vereinfachen, bspw. wenn man immer dieselben Größen für seine Hx Elemente verwendet, oder 'margin-bottom' lässt sich "zentral" auslagern.

Aber es soll ja im Wesentlichen auch nur verdeutlichen, wie ich (m)einen vertikalen Rhythmus etabliere.

Nachteile:
Insbesondere wenn man aufgrund von Mehrspaltigkeit im Layout, mehrere vertikale Rhythmen miteinander "harmonisieren" möchte, machen sich die aufgrund der em-basierten Berechnung auftretenden Rundungsdifferenzen im Browser bemerkbar.

Diese könnte man relativ einfach im Mixin 'vrHeadings' abfangen, allerdings muss man dann wiederum einen Pixelwert für die im Browser eingestellte Basis-Schriftgröße "annehmen".

Für (Verbesserungs-)Vorschläge, Tipps oder weitere Ideen meinen besten Dank im Voraus.

Gruß Gunther

PS: Falls das jemand live ausprobieren möchte, braucht er noch eine Pow Funktion. Diese ist u.a. in Compass enthalten, oder ich verwende bspw. diese:

  
@function pow($val, $pow) {  
	$res: 1;  
	@while($pow > 0) {  
		$res: $res * $val;  
		$pow: $pow - 1;  
	}  
	@return $res;  
}