@typographist/postcss

Toolkit for the rapid construction of interfaces with high quality typography.

Usage no npm install needed!

<script type="module">
  import typographistPostcss from 'https://cdn.skypack.dev/@typographist/postcss';
</script>

README

Demo

Typographist

Documentation

Introduction

What is a Typographist?

The Typographist is a mobile first progressive toolkit for web designers and developers that allows you to build interfaces with responsive graphics. Having absorbed the best qualities of Sassline and Gutenberg, it significantly simplifies the process of improving typography on the web. The framework's objective is to provide developers with the most simple, powerful and flexible tool that will take over all the routine work in the form of complex calculations. The Typographist builds a basic grid to establish the correct vertical rhythm on the basis of rem, and also establishes macro-tipography, which allows paying special attention to micro-tipographic details. Also the toolkit is perfectly combined with css grid layout.

Base type * line-height = leading

The correct vertical rhythm leads to a constant distance between the elements, which helps to clarify the structure and order of the contents and to associate it with other elements. The ultimate goal of the program is to draw the reader's attention to the text and improve the readability in general.

Root font-size = ½ leading

Typographist works by setting the root font-size as half the line-height of the standard paragraph text. The height of the baseline grid is then effectively set at 2, with increments at each 1rem. This makes it a pleasant and easy tool for creating harmony of content in your layout and typography. This is based off a technique for setting text in print documents.

Getting Started

Installation

To install the stable version:

yarn

yarn add postcss @typographist/postcss -D

npm

npm i postcss  @typographist/postcss

Configuration

  1. Connect Typographist

requireJs

const { typographist, ratios } = require('@typographist/postcss');

es6 modules

import { typographist, ratios } from ' @typographist/postcss';

Base

  1. Set font size for standard paragraph text. For example, I set 16px, but you can choose one that you like. Feel free to constantly experiment. Base is set for each breakpoint.
typographist({
  base: '16px',
});

Line-height

  1. Set the line-height. For example, I set 1.4. It is not necessary to specify at each breakpoint. Each next breakpoint inherits the value of line-height from the previous breakpoint.
typographist({
  base: '16px',
  lineHeight: 1.4,
});

Ratio

  1. Set the ratio. To do this, we use Tim Brown's Modular Scale. For example, I set a ratio equal to the minor second (~1.067) Let's see what happened. It is not necessary to specify at each breakpoint. Each next breakpoint inherits the value of line-height from the previous breakpoint.
typographist({
  base: '16px',
  lineHeight: 1.4,
  ratio: ratios.MINOR_SECOND,
});
Ratios
function ratio decimal value
AUGMENTED_FOURTH 1:√2 1.41421
DOUBLE_OCTAVE 1:4 4
GOLDEN_SECTION 1:1.618 1.618034
MAJOR_ELEVENTH 3:8 2.666666667
MAJOR_SECOND 8:9 1.125
MAJOR_SEVENTH 8:15 1.875
MAJOR_SIXTH 3:5 1.666666667
MAJOR_TENTH 2:5 2.5
MAJOR_THIRD 4:5 1.25
MAJOR_TWELFTH 1:3 3
MINOR_SECOND 15:16 1.066666667
MINOR_SEVENTH 9:16 1.777777778
MINOR_THIRD 5:6 1.2
OCTAVE 1:2 2
PERFECT_FIFTH 2:3 1.5
PERFECT_FOURTH 3:4 1.333333333
PHI 1:1.618 1.618034

Breakpoint

  1. Set the breakpoint name and breakpoint value.
typographist({
  base: '16px',
  lineHeight: 1.4,
  ratio: ratios.MINOR_SECOND,
  tablet: {
    breakpoint: '768px',
  },
});

You are free to choose any breakpoint name, and you can specify just how many breakpoints you need. If you are used to naming breakpoints as in bootstrap, nothing prevents you from using the usual names.

typographist({
  base: '16px',
  lineHeight: 1.4,
  ratio: ratios.MINOR_SECOND,
  sm: {
    // your code
  },
  md: {
    // your code
  },
  lg: {
    // your code
  },
  xl: {
    // you code
  },
});
  1. Let's set base, line-height, and ratio for each breakpoint. For the tablet, I set the ratio to a major second = 1.125. For the desktop it will be equal to the minor third = 1.2.
typographist({
  base: '16px',
  lineHeight: 1.4,
  ratio: ratios.MINOR_SECOND,
  tablet: {
    breakpoint: '768px',
    base: '17px',
    ratio: ratios.MAJOR_SECOND,
  },
  desktop: {
    breakpoint: '992px',
    base: '18px',
    ratio: ratios.MINOR_THIRD,
  },
  lgDesktop: {
    breakpoint: '1200px',
    base: '20px',
  },
}),

You probably noticed that I did not set a ratio for a breakpoint named lgDesktop. It's all right. As mentioned earlier, this value will be inherited from the previous breakpoint.

I hope it was not difficult for you. The idea of such a simple configuration I borrowed from Skott Kellum and his remarkable project modularscale-sass. Well? Fasten your seat belts. This is where the fun begins.)

Typographist with Webpack

You need to create a postcss.config.js or .postcssrc.js

const { typographist, ratios } = require('typographist');

module.exports = () => ({
  plugins: [
    typographist({
      base: '16px',
      lineHeight: 1.4,
      ratio: ratios.MINOR_SECOND,
      tablet: {
        breakpoint: '768px',
        base: '17px',
        ratio: ratios.MAJOR_SECOND,
      },
      desktop: {
        breakpoint: '992px',
        base: '18px',
        ratio: ratios.MINOR_THIRD,
      },
      lgDesktop: {
        breakpoint: '1200px',
        base: '20px',
      },
    }),
  ],
});

Typographist with Gulp

const gulp = require('gulp');
const gulpIf = require('gulp-if');
const postcss = require('gulp-postcss');
const sourcemaps = require('gulp-sourcemaps');
const rename = require('gulp-rename');
const cssnano = require('gulp-cssnano');
const notify = require('gulp-notify');
const combine = require('stream-combiner2').obj;
const { typographist, ratios } = require('typographist');

const processors = [
  typographist({
    base: '16px',
    lineHeight: 1.4,
    ratio: ratios.MINOR_SECOND,
    tablet: {
      breakpoint: '768px',
      base: '17px',
      ratio: ratios.MAJOR_SECOND,
    },
    desktop: {
      breakpoint: '992px',
      base: '18px',
      ratio: ratios.MINOR_THIRD,
    },
    lgDesktop: {
      breakpoint: '1200px',
      base: '20px',
    },
  }),
];

const IS_DEVELOPMENT =
  !process.env.NODE_ENV || process.env.NODE_ENV === 'development';

gulp.task('styles', () =>
  combine(
    gulp.src('./entryDir/entry.css'),
    gulpIf(IS_DEVELOPMENT, sourcemaps.init()),
    postcss(processors),
    gulpIf(IS_DEVELOPMENT, sourcemaps.write()),
    gulpIf(!IS_DEVELOPMENT, combine(cssnano())),
    rename('main.css'),
    gulp.dest('./outputDir/'),
  ).on('error', notify.onError()),
);

CSS

Postcss syntax hightlight

If you use vscode as the code editor. To avoid conflicts with the linter and to correctly postcss syntax highlighting, install the plugin PostCSS syntax.

Root font size

Input Set the root font-size.

:root {
  @root;
}

Output

:root {
  --tablet: 768px;
  --desktop: 992px;
  --lg-desktop: 1200px;
  font-size: 68.75%;
}
@media screen and (min-width: 48em) {
  :root {
    font-size: 75%;
  }
}
@media screen and (min-width: 62em) {
  :root {
    font-size: 81.25%;
  }
}
@media screen and (min-width: 75em) {
  :root {
    font-size: 87.5%;
  }
}

Using the @ root directive, we calculated the size of the root font for each breakpoint. Also now we have the opportunity to link our css and javascript to native css variables. The value of each breakpoint is converted to em.

Input

:root {
  @root (fluid);
}

Output

:root {
  --tablet: 768px;
  --desktop: 992px;
  --lg-desktop: 1200px;
  font-size: 68.75%;
}
@media screen and (min-width: 48em) {
  :root {
    font-size: calc(68.75% + 2 * ((100vw - 48em) / 224));
  }
}
@media screen and (min-width: 62em) {
  :root {
    font-size: calc(81.25% + 1 * ((100vw - 62em) / 208));
  }
}
@media screen and (min-width: 75em) {
  :root {
    font-size: 87.5%;
  }
}

Now our font and layout have become elastic. It is possible to have precise control over responsive typography. Using calc() and viewport units you can create fluid type that scales perfectly between specific pixel values, within a specific viewport range. This was made possible by Mike Riethmuller and his formula.

Base font size

Input

body {
  @base;
}

Output

body {
  font-size: 1.4545454545454546rem;
  line-height: 2rem;
}
@media screen and (min-width: 48em) {
  body {
    font-size: 1.4166666666666667rem;
  }
}
@media screen and (min-width: 62em) {
  body {
    font-size: 1.3846153846153846rem;
  }
}
@media screen and (min-width: 75em) {
  body {
    font-size: 1.4285714285714286rem;
  }
}

The @ t-base directive sets the size of the base font to rem for each breakpoint, and also sets line-height: 2rem.

Breakpoints

@up

@up takes as parameters the names of breakpoints, values in pixels or ems.

Input

.your-class {
  @up (desktop) {
    /* your code */
  }
}

Output

@media screen and (min-width: 62em) {
  .your-class {
    /* your code */
  }
}

@down

@down takes as parameters the names of breakpoints, values in pixels or ems. Input

.your-class {
  @down (desktop) {
    /* your code */
  }
}

Output

@media screen and (max-width: 74.99875em) {
  .your-class {
    /* your code */
  }
}

@only

@only takes as parameters parameters only the names of breakpoints.

Input

.your-class {
  @only (desktop) {
    /* your code */
}

Output

@media screen and (min-width: 62em) and (max-width: 74.99875em) {
  .test {
    /* your code */
  }
}

@between

@between takes as parameters the names of breakpoints, values in pixels or ems.

Input

.your-class @between(tablet, desktop) {
  /* your code */
}

Output

@media screen and (min-width: 48em) and (max-width: 74.99875em) {
  .your-class {
    /* your code */
  }
}

Step unit

Set the font size from the position in the modular scale.

position in modular scale

To convert step to rem, use directives @up, @down, or @only.

input

h1 {
  font-size: 6step;

  @-above (tablet) {
    font-size: 6step;
  }

  @up (desktop) {
    font-size: 6step;
  }

  @up (lg-desktop) {
    font-size: 6step;
  }
}

Output

h1 {
  font-size: 2.1818181818181817rem;
}
@media screen and (min-width: 48em) {
  h1 {
    font-size: 2.8333333333333335rem;
  }
}
@media screen and (min-width: 62em) {
  h1 {
    font-size: 4.153846153846154rem;
  }
}
@media screen and (min-width: 75em) {
  h1 {
    font-size: 4.285714285714286rem;
  }
}

Step unit is converted to rem.

This approach is useful if you want to dramatically increase the font size on any of the breakpoints, but in most cases it is too cumbersome and we force you to duplicate the code every time. For this I have something better for you!

step function

With step function we do the same much faster and more gracefully.

Input

h1 {
  font-size: step(6);
}

Output

h1 {
  font-size: 2.1818181818181817rem;
}
@media screen and (min-width: 48em) {
  h1 {
    font-size: 2.8333333333333335rem;
  }
}
@media screen and (min-width: 62em) {
  h1 {
    font-size: 4.153846153846154rem;
  }
}
@media screen and (min-width: 75em) {
  h1 {
    font-size: 4.285714285714286rem;
  }
}

Nesting

Inheritance the name of the parent class. Do this as you are used to in sass, less and stylus.

Input

.your-class {
  border: 1px solid gray;

  &__inner {
    padding: 1rem;
  }

  &__inner_active {
    background-color: rebeccapurple;
  }

  &:hover {
    border: 1px solid black;
  }
}

Output

.your-class {
  border: 1px solid gray;
}
.your-class__inner {
  padding: 1rem;
}
.your-class__inner_active {
  background-color: rebeccapurple;
}
.your-class:hover {
  border: 1px solid black;
}

MIT License

Copyright (c) 2018 Maxim Alyoshin

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.