Reference typography for on screen reading

  1. Full code
  2. Font sizes by selector (alphabetical order)
  3. Font sizes by size (ascending)
  4. Discussion

This is the list of font-sizes that I currently use for the recurring elements like headers, lists, etc. of websites.

The sizes are presented as CSS rules ordered by size or by selector, in alphabetical order. Only the font-sizes of the body and html tags are expressed in pixels: the other rules use rem values.

According to the W3C specs 1 rem equals the “computed value of font-size on the root element” so if the html font-size is set to 16 pixels, 1 rem = 16 pixels, 0.8 rem = 12.8 pixels, etc.

For elements that do not have a specific HTML tag – like an emphasis blockquote – I use a class selector with a descriptive name (e.g.: .emphasis-blockquote).

At the end of the lists there is a small explanation of the rationale behind the chosen values.

Full code

Font sizes by selector (alphabetical order)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
blockquote {
font-size: 0.8rem
}

body {
font-size: 21px /*body and html selectors are usually grouped in a single rule*/
}

caption {
font-size: 0.8 rem
}

code {
font-size: 0.8rem
}

.emphasis-blockquote {
font-size: 1.2rem
}

figcaption {
font-size: 0.8rem
}

h1 {
font-size: 2rem
}

h2 {
font-size: 1.5rem
}

h3 {
font-size: 1.25rem
}

h4 {
font-size: 0.9rem
}

h5 {
font-size: 0.9rem
}

h6 {
font-size: 0.9rem
}

input {
font-size: 0.8rem
}

label {
font-size: 0.7rem
}

html {
font-size: 21px /*body and html selectors are usually grouped in a single rule*/
}

.meta {
font-size: 0.9rem
}

ol {
font-size: 0.8rem
}

p {
font-size: 1rem
}

pre {
font-size: 0.8rem
}

.read-more-text{
font-size: 0.9rem
}

.title {
font-size: 2rem
}

ul {
font-size: 0.8rem
}

Font sizes by size (ascending)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
h1, .title{
font-size: 2rem
}

h2 {
font-size: 1.5rem
}

h3 {
font-size: 1.25rem
}

.emphasis-blockquote {
font-size: 1.2rem
}

p {
font-size: 1rem
}

html, body {
font-size: 21px
}

h4, h5, h6, .meta, .read-more-text {
font-size: 0.9rem
}

blockquote, caption, code, figcaption, input, label, ol, pre, ul {
font-size: 0.8rem
}

Discussion

These are few principles that guided me to pick the values:

  • font sizes should not be responsive, i.e. the paragraph font size should remain consistent between a large monitor and a mobile phone;
  • a too big text is better than an unreadable text (i.e. it is better to err on the side of caution);
  • the number of different font sizes should be kept to the minimum .

I also tried to read some scientific papers on the subject of readability, and tried to follow their suggestion. I found particulary interesting the following two papers:

An issue where my choice differs considerably from the results of the mentioned papers is the size of the main body text, which I set to 21 pixels and not to 12-14 pixels as raccomended. I believe that 12 - 14 pixels if a far too small size for comfortable on-screen reading, and so followed the “big font size” trend that could be observed in websites like Medium, The New York Times, etc.

Font size by selector

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
blockquote {
font-size: 0.8rem
}

body {
font-size: 21px /*body and html selectors are usually grouped in a single rule*/
}

caption {
font-size: 0.8 rem
}

code {
font-size: 0.8rem
}

.emphasis-blockquote {
font-size: 1.2rem
}

figcaption {
font-size: 0.8rem
}

h1 {
font-size: 2rem
}

h2 {
font-size: 1.5rem
}

h3 {
font-size: 1.25rem
}

h4 {
font-size: 0.9rem
}

h5 {
font-size: 0.9rem
}

h6 {
font-size: 0.9rem
}

input {
font-size: 0.8rem
}

label {
font-size: 0.7rem
}

html {
font-size: 21px /*body and html selectors are usually grouped in a single rule*/
}

.meta {
font-size: 0.9rem
}

ol {
font-size: 0.8rem
}

p {
font-size: 1rem
}

pre {
font-size: 0.8rem
}

.read-more-text{
font-size: 0.9rem
}

.title {
font-size: 2rem
}

ul {
font-size: 0.8rem
}

Font sizes by size

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
h1, .title{
font-size: 2rem
}

h2 {
font-size: 1.5rem
}

h3 {
font-size: 1.25rem
}

.emphasis-blockquote {
font-size: 1.2rem
}

p {
font-size: 1rem
}

html, body {
font-size: 21px
}

h4, h5, h6, .meta, .read-more-text {
font-size: 0.9rem
}

blockquote, caption, code, figcaption, input, label, ol, pre, ul {
font-size: 0.8rem
}

Back to top button with pure Javascript

  1. Full Code
  2. Button design
  3. CSS code
  4. JavaScript Code

I want to have a back to top button that takes the user back to the top of the website when clicked. The button shoud have the following features:

  • appears only after the user scrolls down a certain amount of pixels;
  • change color when hovered;
  • take back the user to the top of the website with an animation;
  • use vanilla JavaScript, no libraries.

Full Code

Button design

I’m going to put an SVG image directly into the HTML code (also known as inline SVG) to be able to change its color on the fly with CSS. I’m going to borrow the chevron up icon from the fontawesome set. After some clean up, the code to be included in the HTML looks like this:

1
2
3
4
5
<div id="back-to-top">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<path d="M240.971 130.524l194.343 194.343c9.373 9.373 9.373 24.569 0 33.941l-22.667 22.667c-9.357 9.357-24.522 9.375-33.901.04L224 227.495 69.255 381.516c-9.379 9.335-24.544 9.317-33.901-.04l-22.667-22.667c-9.373-9.373-9.373-24.569 0-33.941L207.03 130.525c9.372-9.373 24.568-9.373 33.941-.001z"></path>
</svg>
</div>

There’s nothing to do here, this code goes as it is into its div container, which is identified with an id.

CSS code

For the CSS code I need three selectors: one for the general properties; one for the hover effect and the last one which will make it visible/invisible.

1
2
3
4
5
6
7
#back-to-top {
display: none;
position: fixed;
bottom: 10px;
right: 80px;
max-width: 30px;
}

The button is hidden by default (display: none) and has a fixed position. The specific values for the position depend on the layout of the website, in my case, the button should appear on the bottom left of the website. The max-width property sets the width to which the svg will be restricted to: if not set, the svg will fill all the available space.

1
2
3
#back-to-top:hover svg{
fill: #212121
}

The second selector changes the svg color when hovering over the button container. It should be noted that the CSS property that controls the color of an SVG path is called fill, not color.

1
2
3
#back-to-top.back-to-top--show{
display: block
}

The above rule shows/hides the button: when the back-to-top--show class is added (it will be added by the JS code), the button shows up. Notice that I can’t simply use the .back-to-top-show selector because a class selector is always less specific than an id selector (as #back-to-top) and so the rule will never be applied on top of the previous one with the id selector. On the other hand, enqueing the class selector after the id selector creates a new selector that is more specific than the id alone, and so it takes precedence.

Lastly, I’m trying to use the BEM naming convention as much as I can, that’s the reason for such a verbose name.

JavaScript Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var backToTopBtn = document.querySelector('#back-to-top');

window.addEventListener('scroll', function() {
if (window.pageYOffset > 200) {
backToTopBtn.classList.add('back-to-top--show');
} else {
backToTopBtn.classList.remove('back-to-top--show');
}
});

backToTopBtn.addEventListener('click', function(e){
e.preventDefault();
document.body.scrollIntoView({behavior: 'smooth', block: 'start'});
});

The code is pretty simple. For the sake of convenience, I’m creating a variable called backToTopBtn with the pointer for the button container (line 1).

The second statement (lines 3-9) tells the browser to listen for a scroll event and then, if the page is scrolled by more than 200 pixels, add the class back-to-top--show - the one I set up in CSS that makes the button visible - to the button container. When the page is scrolled up by less than 200 pixels the class is removed.

The third statement tells the browser to listen to a click event on the button and then call the scrollIntoView Javascript method, which is a built-in method that does exactly what I want: scroll back to the top of the page. The method has several options; the ones used here set the scroll behaviour to smooth and the scroll target to the start of the page).

HTML

1
2
3
4
5
<div id="back-to-top">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<path d="M240.971 130.524l194.343 194.343c9.373 9.373 9.373 24.569 0 33.941l-22.667 22.667c-9.357 9.357-24.522 9.375-33.901.04L224 227.495 69.255 381.516c-9.379 9.335-24.544 9.317-33.901-.04l-22.667-22.667c-9.373-9.373-9.373-24.569 0-33.941L207.03 130.525c9.372-9.373 24.568-9.373 33.941-.001z"></path>
</svg>
</div>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#back-to-top {
display: none;
position: fixed;
bottom: 10px;
right: 80px;
max-width: 30px;
}

#back-to-top:hover svg{
fill: #212121
}

#back-to-top.back-to-top--show{
display: block
}

Javascript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var backToTopBtn = document.querySelector('#back-to-top');

window.addEventListener('scroll', function() {
if (window.pageYOffset > 200) {
backToTopBtn.classList.add('back-to-top--show');
} else {
backToTopBtn.classList.remove('back-to-top--show');
}
});

backToTopBtn.addEventListener('click', function(e){
e.preventDefault();
document.body.scrollIntoView({behavior: 'smooth', block: 'start'});
});

Horizontal line decoration with CSS

  1. Full code
  2. Single line decoration
    1. HTML code
    2. CSS code
  3. Single line dashed decoration
    1. CSS code
  4. Double line decoration
    1. CSS code

My goal is to have headers text (h1, h2, etc.) decorated with horizontal lines in various fashion (single line, dashed, double, etc.).

Full code

Single line decoration

Intended result:

Horizontal line decoration example

HTML code

1
2
3
4
5
<div>
<h2>
<span>H2 text</span>
</h2>
</div>

For the CSS code to work I need a tag inside the header tag, it can be a <span> (as above) or anything else. In the example above the div tag simulates the text container.

CSS code

1
2
3
4
5
div{
max-width: 300px;
margin: auto;
overflow: hidden;
}

The critical bit of code above is overflow: hidden: it hides the part of the horizontal lines that exceed the div max width.

1
2
3
4
5
6
7
8
9
10
11
12
h2 span{
display: inline-block;
position: relative;
}

h2 span::before, h2 span::after {
content: "";
position: absolute;
border-bottom: 1px solid black;
top: 50%;
width: 600px;
}

These rules are shared by both pseudo elements. top: 50% will ensure that the horizontal line stays vertically centered. The width value could be anything greater than the text-container width.

1
2
3
4
5
6
7
8
9
h2 span::before{
right: 100%;
margin-right: 15px;
}

h2 span::after{
left: 100%;
margin-left: 15px;
}

At last I need some rules for the left and right pseudo-elements. I’m going to use ::before for the left one and ::after for the right.

Single line dashed decoration

Intended result:

Horizontal line decoration example

The dashed version differs from the single line for a single line of code in the combined CSS rule for the pseudo-elements:

CSS code

1
2
3
4
5
6
7
h2 span::before, h2 span::after {
content: "";
position: absolute;
/*changed*/ border-bottom: 1px dashed black; /* was: 1px solid black */
top: 50%;
width: 600px;
}

Double line decoration

Intended result:

Horizontal line decoration example

The double line version requires a coulpe of edits in the CSS code:

CSS code

1
2
3
4
5
6
7
8
9
.article-header h2 a:before,.article-header h2 a:after {
content: "";
position: absolute;
/*NEW code*/height: 5px;
border-bottom: 1px solid black;
/*NEW code*/ border-top: 1px solid black;
top: 50%;
width: 600px;
}

I’m going to use the border-top property to draw the second line. The rule will be the same as the border-bottom one.

I also need to specify an height for the pseudo elements, so that the two lines will not be printed one over the other. If no height is specified the browser assumes it’s zero, so the bottom and top border (which we are using to draw the lines) coincide.

The greater the height, the greater the distance between the two lines will be.

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="single-line">
<h2>
<span>Single line</span>
</h2>
</div>

<div class="dashed-line">
<h2>
<span>Dashed line</span>
</h2>
</div>

<div class="double-line">
<h2>
<span>Double line</span>
</h2>
</div>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
div{
max-width: 300px;
margin: auto;
overflow: hidden;
}

/**SINGLE LINE**/

div.single-line h2{
text-align: center;
}

div.single-line h2 span{
display: inline-block;
position: relative;
}

div.single-line h2 span::before, div.single-line h2 span::after {
content: "";
position: absolute;
border-bottom: 1px solid black;
top: 50%;
width: 600px;
}

div.single-line h2 span::before{
right: 100%;
margin-right: 15px;
}

div.single-line h2 span::after{
left: 100%;
margin-left: 15px;
}
/** DASHED LINE **/

div.dashed-line h2{
text-align: center;
}

div.dashed-line h2 span{
display: inline-block;
position: relative;
}

div.dashed-line h2 span::before, div.dashed-line h2 span::after {
content: "";
position: absolute;
height: 100%;
border-bottom: 1px dashed black;
top: -50%;
width: 600px;
}

div.dashed-line h2 span::before{
right: 100%;
margin-right: 15px;
}

div.dashed-line h2 span::after{
left: 100%;
margin-left: 15px;
}

/** DOUBLE LINE **/

div.double-line h2{
text-align: center;
}

div.double-line h2 span{
display: inline-block;
position: relative;
}

div.double-line h2 span::before, div.double-line h2 span::after {
content: "";
position: absolute;
height: 5px;
border-bottom: 1px solid black;
border-top: 1px solid black;
top: calc(50% - 2.5px);
width: 600px;
}

div.double-line h2 span::before{
right: 100%;
margin-right: 15px;
}

div.double-line h2 span::after{
left: 100%;
margin-left: 15px;
}

Nginx redirects

  1. HTTP to HTTPS
    1. Where does it go?
    2. Where in the file should I put this?
  2. WWW to non-WWW
    1. Where does it go?
    2. Where in the file should I put this?

This is a list of the redirects code snippets that works for me.

  1. HTTP to HTTPS
    1. Where does it go?
    2. Where in the file should I put this?
  2. WWW to non-WWW
    1. Where does it go?
    2. Where in the file should I put this?

HTTP to HTTPS

Code for redirecting all HTTP requests to HTTPS:

1
2
3
if ($scheme = http) {
rewrite ^/(?!.well-known)(.*) https://MYWEBSITE.COM/$1 break;
}

Where does it go?

It goes into the domain specific config file, e.g.:

1
/etc/nginx/sites-available/MYWEBSITE.COM.conf

Where in the file should I put this?

Inside the main server{} code group, e.g.:

1
2
3
4
5
6
7
8
9
server {
server_name MYWEBSITE.COM www.MYWEBSITE.COM;
# Rest of file content goes here
# ...
# ...
if ($scheme = http) {
rewrite ^/(?!.well-known)(.*) https://MYWEBSITE.COM/$1 break;
}
}

WWW to non-WWW

Code to redirect all WWW requests to the non-WWW URL version:

1
2
3
4
server {
server_name www.MYWEBSITE.COM;
return 301 $scheme://MYWEBSITE.COM$request_uri;
}

Where does it go?

It goes into the domain specific config file, e.g.:

1
/etc/nginx/sites-available/MYWEBSITE.COM.conf

Where in the file should I put this?

You need to create another server{} group before the main one:

1
2
3
4
5
6
7
8
9
10
11
server {
server_name www.MYWEBSITE.COM;
return 301 $scheme://MYWEBSITE.COM$request_uri;
}

server {
server_name MYWEBSITE.COM;
# Original config content
# ...
# ...
}

notice that the main server{} group only needs the non-WWW version of the URL as server_name

dark