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.
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.
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.
To install the stable version:
yarn
yarn add postcss @typographist/postcss -D
npm
npm i postcss @typographist/postcss
- Connect Typographist
requireJs
const { typographist, ratios } = require('@typographist/postcss');
es6 modules
import { typographist, ratios } from ' @typographist/postcss';
- 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',
});
- 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,
});
- 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,
});
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 |
- 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
},
});
- 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.)
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',
},
}),
],
});
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()),
);
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.
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.
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.
@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 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 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 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 */
}
}
Set the font size from the position in the 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!
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;
}
}
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.