Vertical Rhythm and Font Baselines with Styled Components
12px vertical rhythm with correctly aligned baselines
Beautifully aligned type with Styled Components
npm i @ceteio/styled-components-rhythm
or, with yarn:
yarn add @ceteio/styled-components-rhythm
import { ThemeProvider, injectGLobal }, styled from 'styled-components';
import styledComponentsRhythm from '@ceteio/styled-components-rhythm';
const rhythm = styledComponentsRhythm({
baseFontSize: 1, // 1rem. Browser default makes this 16px
baseLineHeight: 1.2, // unitless line-height, see: https://css-tricks.com/almanac/properties/l/line-height/#comment-1587658
rhythmHeight: 0.75, // rem units. With browser default, this is 16px * 0.75rem == 12px
capHeights: {
// Calculated with https://codepen.io/sebdesign/pen/EKmbGL?editors=0011
Lato: 0.72,
},
debug: true,
});
injectGLobal`
/* Reset global margins and padding */
h1, p {
margin: 0;
padding: 0;
}
/* Using Lato font https://fonts.google.com/specimen/Lato */
@import url('https://fonts.googleapis.com/css?family=Lato')
${rhythm.global()}
`;
const H1 = styled.h1`
${props => props.theme.setFontWithRhythm('Lato', 3)}
margin-top: ${props => props.theme.rhythmSizing(3)}rem;
`;
const Paragraph = styled.p`
${props => props.theme.setFontWithRhythm('Lato', 1)}
margin-top: ${props => props.theme.rhythmSizing(2)}rem;
`;
export default () => (
<ThemeProvider theme={rhythm.theme}>
<H1>Hello world</H1>
<Paragraph>How are you today?</Paragraph>
<Paragraph>Feeling quite <em>aligned</em>!</Paragraph>
</ThemeProvider>
);
The main export is a function which returns a rhythm object suitable for
adding to a Styled Components <ThemeProvider>
:
import styledComponentsRhythm from '@ceteio/styled-components-rhythm';
const rhythm = styledComponentsRhythm(options);
// { theme: ..., global: ... }
options
(Object
)baseFontSize
(Number
): The rem
font size of your root element (ie; the <body>
).rhythmHeight
(Number
): The rem
vertical grid size, to which text will have its baseline aligned. Works best when it divides evenly into (baseFontSize
* defaultLineHeight
).capHeights
(Object
): Map of font-family
font name -> proportional height of capital letters. Heights can be calculated with this tool.
For example:
{
Lato: 0.72,
}
defaultLineHeight
(Number
): Default for setFontWithRhythm()
below. Must be a unitless value, which will be relative to the font size of an element.debug
(Boolean
): Will inject red horizontal lines to body for visually debugging alignments.defaultOutputType
(String
): Set the output type of setFontWithRhythm()
& global()
. 'string'
: Return a css string . 'object'
: Return a css style object. Default: 'string'
.There are two pieces to the puzzle, both of which must be used to have effective
vertical rhythm; rhythm.theme
, and rhythm.global
:
import styledComponentsRhythm from '@ceteio/styled-components-rhythm';
import { injectGlobal, ThemeProvider } from 'styled-components';
const rhythm = styledComponentsRhythm(options);
injectGlobal`${rhythm.global()}`;
return <ThemeProvider theme={rhythm.theme}>...</ThemeProvider>;
theme
(Object
)Pass this object to a Styled Components ThemeProvider
as the theme:
const rhythm = styledComponentsRhythm(options);
return <ThemeProvider theme={rhythm.theme}>...</ThemeProvider>;
global([outputType]) => String
A string containing global CSS that needs to be applied. Best done using
styled-component's injectGlobal
:
const rhythm = styledComponentsRhythm(options);
injectGlobal`${rhythm.global()}`;
or Emotion's <Global>
component:
<Global styles={rhythm.global('object')} />
Parameters
outputType
(String
): 'string'
: Return a css string. 'object'
: Return a
css style object. Default: the value of defaultOutputType
.You now have access to the following via the theme
prop within a styled
component:
rhythmHeight
The value as passed when creating the theme object.
setFontWithRhythm(fontName, fontSizeRem[, desiredLineHeight[, outputType]]) => String
The main function which will generate the CSS necessary to correctly align the font to a rhythm baseline.
This function makes 2 assumptions:
padding-top
or margin-bottom
on this element.Parameters
fontName
(String
): Should match the font name as you would declare it in the CSS
property font-family
.fontSizeRem
(Number
): A multiple of baseFontSize
.desiredLineHeight
(Number
): Will be rounded to the nearest rhythm line so you
don't have to worry.outputType
(String
): 'string'
: Return a css string. 'object'
: Return a
css style object. Default: the value of defaultOutputType
.The output is the CSS string to add to the component:
const H1 = styled.h1`
${props => props.theme.setFontWithRhythm('Lato', 3)}
`;
Or as an object using the css prop (in both Styled Components & Emotion):
const H1 = props => (
<h1 css={theme => theme.setFontWithRhythm('Lato', 3, 1, 'object')} />
);
rhythmSizing(multiple) => Number
A simple helper to calculate multiple * rhythmHeight
.
Works great for setting margins or padding:
const H1 = styled.h1`
margin-top: ${props => props.theme.rhythmSizing(3)}rem;
`;
capsize
by Seek: "Using font metadata, text can now be sized according to the height of its capital letters while trimming the space above capital letters and below the baseline."
basekick
by Michael Taranto is another implementation of the same thing, targeted at LESS.