Sekrab Garage

CSS Tricks

The perfect blockquote, Part III: Conclusion

CSS June 23, 22
Series:

The perfect blockquote

Creating the perfect blockquote has always been my unmet aspiration. In this three-part article, I am digging, to find out once and for all, is it at all doable?
  1. two months ago
    The perfect blockquote, Part I: Setup
  2. two months ago
    The perfect blockquote, Part II: Challenges
  3. two months ago
    The perfect blockquote, Part III: Conclusion

Winding down

The biggest pain in CSS debugging is that properties affect each other, testing one factor in isolation is almost impossible.

The tool now has all variables we ran into, and four different groups are setup:

1. Text indentation - Font size scaling

2. Absolute positioning - Font size scaling

3. Text indentation - Transformation scaling

4. Absolute positioning - Transformation scaling

Playing around with the different tools and scaling up on purpose, here are some conclusions:

✅ Drop No.3

The leading quotation does not align to the left of the content, leaving much room for guessing. Additionally; whatever doable in No. 3 is more doable in No.4, due to control in position.

✅ Transformation origin and positions are equal

Once setting line heights to zero, changing the origin of top and left values, have exactly the same effect as changing top and left positions. Thus, No. 4 as well can be dropped.

✅ The balance between first and second methods lies in HTML

No.1 method in terms of CSS, has the least friction and most accuracy, but the defect in it, is in HTML, the white space added around quotes is a challenge. If we manage to control the HTML itself, then No.1 is the best. No.2 as well suffers from the defect, but only on one side.

✅ Font-size and text-indentation formula

In No.1, the larger the font-size, the more indentation is needed, the formula is not quite clear and may change for different fonts, so it is a per project setting.

✅ Font-size and top position formula

And for No.2, the larger the font-size the more adjustment to the top position of the leading quote is needed. This too is affected by the choice of font, and the formula is not clear. It is tempting, but artistically speaking, the trailing quote as well needs adjustment.

✅ Vertical align keywords

Vertical alignment keywords like middle, and text-top, sustain their relative position even when text font is larger. Exact measures do not. Here is an exaggerated quotation screenshot, have a look:

Vertical align

Nevertheless, having a different scoped variable in css is easy. Thus using exact measures for different projects is still my preferred method.

I was tempted to create variables as multipliers for different vanity properties, but years of experience have taught me, when it comes to CSS, be explicit for as long as you can.

That settles it, control your HTML, use negative inline text-indent, set line-height to zero, and fine tune vertical-align of both quotes. For larger fonts, further fine tune the text-indent and vertical-align.

The myth of the perfect blockquote

The tool I have just created (along with CoPilot, which is no longer free 😭) reveals to me that to get the perfect blockquote, there is less science and more exact fine tuning. And that is the sad part of the CSS story. With the right settings per project however, we just need to set it once, and bury it.

Generating the CSS

In order to generate the final CSS, and decide once and for all which method to use, we'll use a couple of use cases.

The first use case is for a project I'm working on, where I use Bitter as the main font, and 1.3 as the line-height. Fixing these values and playing with different options I get the following perfectly working setting. And when I say perfectly working, I specifically mean, it does not skip a line unintentionally, and it looks right when the quote text sits on one line, or spans multiple lines.

Here are both sets, and the variables for each set, once with the indentation method, and another with absolute positioning.

Text indentation:

 /*using text indentation*/
.quoted {
	--line-height: 1.3;
	--font-size: 150%;
	--leading-line-height: 0;
	--trailing-line-height: 0;
	--leading-vertical-align: -0.1rem;
	--trailing-vertical-align: -0.1rem;
	--leading-indent: 0.9rem;
	--font-family: 'Newsreader';
 
	line-height: var(--line-height, 1.5);

	blockquote {
		margin: 0;
		position: relative;
		margin-left: var(--leading-indent, 1rem);

		&:before {
			content: '\201C';
			font-family: var(--font-family);
			line-height: var(--leading-line-height, unset);
			vertical-align: var(--leading-vertical-align, unset);
			text-indent: calc(var(--leading-indent, 1rem) * -1);
			display: inline-block;
			font-size: var(--font-size, 100%);
		}

		&:after {
			content: '\201D';
			font-family: var(--font-family);
			line-height: var(--trailing-line-height, unset);
			vertical-align: var(--trailing-vertical-align, unset);
			font-size: var(--font-size, 100%);
		}
	}

	cite {
		display: block;
		margin-top: 1rem;
		font-style: italic;
		margin-left: var(--leading-indent, 1rem);
		&:before {
			content: '\2014';
			font-family: var(--font-family);
		}
	}
}

Positioning:

For the absolutely positioned option: more fine tuning, and less consistency, have a look:

/*using absolutely positioned method*/
.quoted  {
	--line-height: 1.5;
	--font-size: 150%;
	--leading-line-height: 0;
	--trailing-line-height: 0;
	--leading-vertical-align: unset; 
	--trailing-vertical-align: -0.2rem;
	--leading-indent: 0.9rem;
	--leading-left: 0;
	--leading-top: 1.1rem;
	--font-family: 'Newsreader';

	line-height: var(--line-height, 1.5);

	blockquote {
		margin: 0;
		position: relative;
		padding-left: var(--leading-indent, 1rem);

		&:before {
			content: '\201C';
			font-family: var(--font-family);
			line-height: var(--leading-line-height);
			vertical-align: var(--leading-vertical-align, unset);
			font-size: var(--font-size, 100%);
			position: absolute;
			left: var(--leading-left, 0);
			top: var(--leading-top, 0);
		}

		&:after {
			content: '\201D';
			font-family: var(--font-family);
			line-height: var(--trailing-line-height);
			vertical-align: var(--trailing-vertical-align, unset);
			font-size: var(--font-size, 100%);
		}
	}

	cite {
		display: block;
		margin-top: 1rem;
		font-style: italic;
		margin-left: var(--leading-indent, 1rem);
		&:before {
			content: '\2014';
			font-family: var(--font-family);
		}
	}
}

Vanity

The final test is creating a pull quote, and see which one holds. Here are the additional vanity styles, with the update in variables to fit in the 150% increase in text font size.

/* using indentation method*/
.vanity {

	/*because of increase in blockquote size, i need more indentation*/
	--leading-indent: 1.3rem;
	
	/*increase vertical align as well*/
	--leading-vertical-align: -0.3rem;
	--trailing-vertical-align: -0.3rem;
	blockquote {
		font-size: 150%;
		font-style: italic;
		margin-left: 0;
	}
	blockquote:before,
	blockquote:after {
		font-style: normal;
	}
	cite {
		margin-left: 0;
		font-size: 120%;
		font-style: normal;
	}
}

If we use the positioned method, two extra variables need to be updated.

/*using positioned*/
.vanity {

	/*we need margin-left indentation to hang the quotation mark*/
	--leading-indent: 1.3rem;
	/*increase vertical align as well*/
	--trailing-vertical-align: -0.4rem;

	/*and more top position*/
	--leading-top: 1.5rem;
	blockquote {
		font-size: 150%;
		font-style: italic;
		margin-left: 0;
		padding-left: 0;
	}

	blockquote:before,
	blockquote:after {
		font-style: normal;
	}
	/*and this should be set explicitly*/
	blockquote:before {
		margin-left: calc(var(--leading-indent, 1rem) * -1);
	}

	cite {
		margin-left: 0;
		font-size: 120%;
		font-style: normal;
	}
}

Verdict

What do you think? Which is more effective? All in all, they both work well, the second method however uses more variables that are less consistent. I am going with option 1: Text Indentation. How about you?

Updating our test tool to have this particular setup, and adding the final enhancements, discussed below, the final tool can be found here:

Final enhancements

The following is just icing on the cake:

  • Remove line heights and fix them at 0 for the quotation marks. The blockquote line-height is inherited from the body or container's line-height. The pull quote however, may need extra line-height, so we calculate, but that should be a rare case.
  • Vertical alignment for both quotes is the same, we shall unify the variables to --vertical-align
  • I don't remember what I was thinking when I named them leading and trailing, when I could have just named them opening and closing. Rename the --leading-indent variable to --opening-indent. The other variables are not part of the solution any more.
  • I also threw in a few other fields to the final testing tool: the body font size, body font family, vanity text-indent and vanity vertical-align.

Using this new tool to find out the best choice for the example above:

Blockquote fine tuning

Find this in StackBlitz as well.

/* shared */
:root {
  --quote-font: 'Newsreader';
  --line-height: 1.3;
}

body {
  font-family: 'Bitter', serif;
  font-size: 1.4rem;
  line-height: var(--line-height);

}

/*The best option*/
.quoted {
	--font-size: 150%;
	--vertical-align: -0.2rem;
	--opening-indent: 0.9rem;

	blockquote {
		margin: 0;
		position: relative;
		margin-left: var(--opening-indent, 1rem);
    &:before, 
    &:after {
      font-family: var(--quote-font);
    	line-height:0;
    	vertical-align: var(--vertical-align, unset);
    	font-size: var(--font-size, 100%);
    }
		&:before {
			content: '\201C';
			text-indent: calc(var(--opening-indent, 1rem) * -1);
			display: inline-block;
		}
		&:after {
			content: '\201D';
		}
	}

	cite {
		display: block;
		margin-top: 1rem;
		font-style: italic;
		margin-left: var(--opening-indent, 1rem);
		&:before {
			content: '\2014';
			font-family: var(--quote-font);
		}
	}
}

.vanity {
  /* because of increase in blockquote size, i need more indentation*/
  --opening-indent: 1.3rem;
  --vertical-align: -0.3rem;
	
  blockquote {
		font-size: 150%;
		font-style: italic;
		margin-left: 0;
    &:before, 
    &:after {
      font-style: normal;
    }
	}
	
	cite {
		margin-left: 0;
		font-size: 120%;
		font-style: normal;
	}	
}

q:before {
  content: '\2018';
  font-family: var(--quote-font);
}
q:after {
  content: '\2019';
  font-family: var(--quote-font);
}

Applied to my project:

Output blockquote

Another use case

For a technical blog, like this one, it has simpler requirements. The font family used is the same, but the line-height is too large to carry out to pull quotes, my fields were set as follows:

  • Font: Sans-serif (Signika in this case)
  • Font size: 1.6rem
  • Line height: 1.7
  • Font size of quotation: 150%
  • Leading indentation: 1rem
  • Vanity leading indentation: 1.5rem
  • Vertical align: -0.5rem (for both)

In the final CSS produced

  • Removed quote-font (it's the same font)
  • Removed italic faces
  • Adjusted the vanity line height by 0.7
    line-height: calc(var(--line-height) * 0.7);

The CSS looks smaller, and it makes sense, since a technical blog does not need too much art! Have a look at the result on Sekrab Garage.

Conclusion

Creating the perfect blockquote is not impossible, but it is not a given. We solved a ton of issues, and created a tool to play with all parameters to see which one works best. We finally settled for one way, and we also found an inherent HTML problem that needs attention.

Thank you for bearing with me this far, what do you think? Is the perfect blockquote a myth?

  1. two months ago
    The perfect blockquote, Part I: Setup
  2. two months ago
    The perfect blockquote, Part II: Challenges
  3. two months ago
    The perfect blockquote, Part III: Conclusion