@ceteio/styled-components-rhythm

Vertical Rhythm and Font Baselines with Styled Components

Usage no npm install needed!

<script type="module">
  import ceteioStyledComponentsRhythm from 'https://cdn.skypack.dev/@ceteio/styled-components-rhythm';
</script>

README

12px vertical rhythm with correctly aligned baselines

Styled Components Rhythm

Beautifully aligned type with Styled Components

Installation

npm i @ceteio/styled-components-rhythm

or, with yarn:

yarn add @ceteio/styled-components-rhythm

Usage

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

API

Creating Rhythm

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'.

Setting the theme

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.

Using the theme values

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:

  1. All previous elements on the page are also correctly aligned to your vertical rhythm.
  2. You will not manually set 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;
`;

Related Projects

  • 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.
  • https://www.w3.org/TR/css-rhythm-1/ is a proposal to support vertical rhythm directly in CSS.