CSS Properties to Control Web Typography
Web typography has the advantage of drawing on the wealth of knowledge belonging to the centuries-old tradition of print typography. By the same token, that tradition carries with it standards of best practices and excellence that web typography is called on to live up to.
However, the web as a medium of communication comes with its own peculiarities. So much so that we’re led to think that a seamless move from print to web typography is a tough call. In his book On Web Typography, p.110, Jason Santa Maria explains:
Printed books are a static format. From the designer’s initial layout of the book to its trip to the press bed, the warehouse, the bookshelf, and your hands, the output of that book doesn’t change. It’s delivered exactly as the designer conceived it.
When it comes to the web, the very same site can be experienced very differently according to a number of factors, e.g., various kinds of devices, screen resolutions, personalized browser settings, etc. Some of these factors, as Jason further explains …
… may give us the impression that the type is too small, others may cause us to miss something important just off screen, and still others may make it nearly impossible to view the web page at all.
That said, it’s also true that “The web is the best place for text.”, as Tim Brown claims in his talk on Universal Typography. Text on the Internet can be “searched, copied, translated, linked to other documents, it can be printed, it’s convenient, it’s accessible”.
The flexibility of the web doesn’t mean relinquishing control. On the contrary, as web designers, we’re still expected to make informed choices about anything we put into our work, and text is no exception. The way text elements are laid out, their color, size, typeface, all this and more communicate a website’s core message and brand.
To manipulate the appearance of text on the web, our primary tool of choice is CSS.
The CSS properties I’m going to present in this post can be found in the CSS Text Module specification.
This module describes the typesetting controls of CSS; that is, the
features of CSS that control the translation of source text to
formatted, line-wrapped text.
In other words, The CSS Text Module deals with the display of characters and words in the browser, and how they’re spaced, aligned, hyphenated, etc., using CSS.
What constitutes a basic unit of text or word, as well as where exactly a word is allowed to break in a given piece of text, significantly depends on the rules of the language being used in a website. For this reason, it’s important to declare this information in the HTML document (usually in the lang
attribute of the <html>
element).
Here, I won’t be discussing the following two topics:
- fonts, that is, the visual representations of characters, i.e. glyphs, and their properties;
- features of CSS related to text decoration, such as underlines, text shadows, and emphasis marks.
If you’re curious, you’ll find the latest documentation on fonts and text decoration properties in the CSS Fonts Module Level 3 and the CSS Text Decoration Module Level 3 respectively.
Manipulating Letter Case
There can be times when text elements need to be displayed in capital letters, for instance first and last name. CSS gives us control on letter case with the text-transform
property.
The default value of the text-transform
property is none
, that is, no effect on letter case is applied.
The capitalize
Value
If you’d like the first letter of each word to be displayed in uppercase while leaving the appearance of all other letters unaffected (whatever their case in the HTML document), using the value capitalize
will achieve this:
The HTML:
<h2>alice's adventures in wonderland</h2>
The CSS:
h2 {
text-transform: capitalize;
}
Notice how capitalize
doesn’t follow title case conventions: in fact, all first letters in the above example appear capitalized, including the word “in”. Authors who intend to follow a literary convention concerning titles will need to manipulate the letters manually in the source text.
The uppercase
Value
If your goal is to have all letters displayed in uppercase, no matter their case in the HTML document, uppercase
is the appropriate value to use:
The HTML:
<h2>alice's adventures in wonderland</h2>
The CSS:
h2 {
text-transform: uppercase;
}
The lowercase
Value
Using the value lowercase
will cause all letters to be displayed in lowercase. Naturally, this won’t affect the appearance of letters that are already lowercase in the original source document.
The HTML:
<h2>Alice's Adventures in Wonderland</h2>
The CSS:
h2 {
text-transform: lowercase;
}
The full-width
Value
The specification has added a new value, full-width
. This value constrains the character to appear inside a square as if it were an ideographic character, e.g., Japanese, Chinese, etc. This facilitates aligning Latin characters with ideographic characters.
Not all characters have a corresponding full-width form, in which case characters will not be affected by the full-width
value.
The HTML:
<h2>Alice's Adventures in Wonderland</h2>
The CSS:
h2 {
text-transform: full-width;
}
Here’s what characters look like in Firefox when full-width
is applied:
Further Remarks
Browser support for the text-transform
property is excellent. In fact, all major browsers support it.
The only exception is the full-width
value, which at present works only in Firefox. Perhaps understandably so, given the probability that full-width
is at risk of being dropped at the Candidate Recommendation stage of the spec.
Further, I’ve noticed a small inconsistency between Firefox (v.39) and other major browsers in rendering the capitalize
value on a hyphenated word.
Here’s what it looks like in Firefox:
Notice how the first letter after a hyphen is not being capitalized. On the other hand, below is the same text displayed in Chrome:
In this instance, letters following a hyphen character are no exception; they are also being displayed with a capital letter. I’ve observed this same behavior in the latest release of all other major browsers except, as noted above, Firefox.
Finally, mind the cascade! If you set the text-transform
property on a container element, its value is inherited by all its child elements. To avoid undesired results, reset the child elements’ text-transform
property value to none
.
View a demo for the text-transform property values.
How to Handle White Space
When you press the Tab key, the space key, or force some text to break to the next line (using the ENTER key or the <br>
tag), you create white space in your source document.
By default, browsers collapse sequences of white space into a single space, line breaks are removed, and lines of text wrap to fit their container. This is convenient for us because it allows us to indent and separate chunks of text to keep our source document readable and maintainable without impacting how content is displayed in the browser.
However, what if this isn’t your goal? Let’s say, for instance, that you’d like to preserve the white space you create in the HTML document. A common scenario is when you write some text designed to be displayed as a properly indented code snippet. Or, you’d like some text to be displayed all on one line, without breaking.
On such occasions, when you intend to override the browser’s default behavior, the white-space
property offers some interesting options.
The normal
keyword resets the browser to its default behavior: all extra white space is collapsed into one character and lines wrap when they reach the edge of their container.
The pre
Value
The pre
keyword allows you to display text by preserving all the white spaces and forced new lines present in the source document. Text will not wrap into a new line when overflowing its container.
element {
white-space: pre;
}
If you use tabs to create white space, you can control their size with the tab-size
property by setting it to an integer value.
element {
white-space: pre;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
}
tab-size
is a property with inconsistent browser support, but if you really can’t stand the default tab’s character length, here’s a polyfill to cover all your bases.
The pre-wrap
Value
Let’s say you’d like white space in the source document to be preserved in the browser display. However, you’d also like to let lines wrap as they reach the edge of their container.
The pre-wrap
keyword will help you achieve the desired result.
element {
white-space: pre-wrap;
}
Notice how each line displayed in the browser reflects the forced breaks in the source code, although the container has plenty of room to fit more text:
However, shrink your browser screen and you’ll notice the lines wrapping to fit their container.
The pre-line
Value
A final interesting value for the white-space
property is pre-line
. To the extent it collapses sequences of space into one space and allows wrapping, it behaves like normal
. However, where a new line character or a <br>
tag is present in the HTML document, these are preserved in the browser display.
element {
white-space: pre-line;
}
Try out the CodePen demo for the pre
, pre-wrap
and pre-line
keywords.
The nowrap
Value
nowrap
is perhaps the best known white-space
value. Does your design require that a piece of inline content should never wrap? Using white-space: nowrap;
on your element does the trick.
Louis Lazaris points to the following use case for this value.
Above is a link followed by the »
symbol. Having this character drop to the next line, for example in fluid web layouts, wouldn’t be desirable.
In this and similar circumstances (think of icons, for instance), the nowrap
value is quite handy.
Another interesting use case is brought to us by Sara Soueidan in the Codrops CSS reference. Sara points out that the white-space
property can be applied to any inline content, including images.
It is used with the value
nowrap
sometimes to create a horizontal list of images in a scrollable element, by preventing the images from wrapping and forcing them to be displayed on one single line inside their container.
I’ve enlarged on this suggestion by creating a basic jQuery carousel using white-space: nowrap
. Here’s the demo:
See the Pen Using the word-wrap Property on an Image Carousel by SitePoint (@SitePoint) on CodePen.
Taking Control of Line Breaks Inside Words
Sometimes it happens that a design looks off because a long word fails to wrap to the next line, thereby overflowing its container. Long URLs or some user-generated long words in blog comments are common scenarios.
The following CSS properties are designed to give us some measure of control on handling long words on the web.
The word-wrap/overflow-wrap
Property
The overflow-wrap
property (previously called word-wrap
, fully supported and working in all major browsers for legacy reasons) takes effect if the white-space
property allows for text wrapping. It can have one of two values: normal
and break-word
.
By using the normal
value, words break at allowed break points, e.g., spaces, hyphens, etc.
The break-word
value permits arbitrary breaking points inside a word if the line can’t otherwise be broken at some other acceptable point.
The image below shows the display of a long word that overflows its container:
Let’s set the overflow-wrap
property, and also, for legacy purposes, the word-wrap
property, to the break-word
value:
element {
word-wrap: break-word;
overflow-wrap: break-word;
}
… and the long word’s display is now broken into multiple lines to fit the available space.
The hyphens
Property
Breaking up long words is all well and good. However, the resulting text could be confusing to readers. A better option is to hyphenate the word as it breaks to the next line. This way, it’s immediately clear to readers they’re looking at one word wrapping onto multiple lines. To achieve this, CSS offers the hyphens
property, which you can use in conjunction with word-wrap: break-word
.
More specifically, the auto
value of the hyphens
property enables you to display a hyphen at the point where words break to the next line, if the document’s language rules allow it or hyphenation is present in the HTML source. For this to work, make sure you set the lang
attribute to your desired language in the HTML document:
.break-word.hyphens-auto {
-moz-hyphens: auto;
-webkit-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto;
}
You can also prevent the display of hyphen characters. In this case, set the hyphens
property to none
:
.break-word.hyphens-none {
-moz-hyphens: none;
-webkit-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
Additionally, you can display hyphen characters on line breaks within words, if words are hyphenated in the markup and the text wraps to the next line. This is done with a value of manual
:
.break-word.hyphens-manual {
-moz-hyphens: manual;
-webkit-hyphens: manual;
-ms-hyphens: manual;
hyphens: manual;
}
Aided by vendor prefixes, browser support for the hyphens
property is good on all major browsers, although not without some slight inconsistencies. The latest versions of Chrome (v.44) and Opera (v.30) at the time of writing don’t support the property value auto
.
View the above examples on CodePen
Manipulating space between Words and Letters
What makes a piece of text more or less readable often depends on a number of factors. In some cases, increasing or decreasing the space between each word or each single letter, i.e. tracking, brings about huge improvements.
CSS offers the word-spacing
and letter-spacing
properties to control the appearance of spacing between words and letters respectively.
The word-spacing
Property
Below are the values for the word-spacing property:
normal
<length>
percentage
normal
displays the default space between letters. The amount of space depends on the font used or the browser.
.normal {
word-spacing: normal;
}
<length>
lets you add inter-word spacing in addition to the default spacing defined by the font or the browser.
.length {
word-spacing: 0.5em;
}
percentage
works the same way as <length>
but using percentage values. I haven’t found any browser implementation for it and percentages are at risk of being removed from future drafts of the specification.
.percentage {
word-spacing: 1%;
}
The letter-spacing
Property
You can set the letter-spacing
property to one of two values: normal
or <length>
.
Using normal
leaves the default font spacing between letters. It also resets any letter-spacing
length previously specified to its default value. For instance, if you specify a letter-spacing
value of 1em
on a parent element but wish to display the default value on child elements, normal
is your friend.
element {
letter-spacing: normal;
}
The <length>
value is a unit of measurement, e.g. px or ems, whereby you can increase the spacing between letters in addition to the default spacing already provided by the font.
element {
letter-spacing: 1em;
}
Further Details
word-spacing
is not only applicable to words. You can use it on any kind of inline or inline-block content.
Also, you can animate both word-spacing
and letter-spacing
. However, using CSS transitions on letter-spacing
shows that the normal
value is not recognized by the current version of Firefox (v.39). To overcome this, simply replace normal
with 0em
.
Here’s a demo with animated text using word-spacing
and letter-spacing
:
See the Pen Animating the CSS letter-spacing and word-spacing Properties by SitePoint (@SitePoint) on CodePen.
Latest CSS Options for Text Alignment
The text-align
property has been around for some time. It controls how inline content like text and images are aligned inside a block container. The kewords left
and right
align inline content to the left and right respectively. Setting text-align
to center
aligns the content to the center of its container. Finally, the justify
keyword justifies content so that each line is of the same length (except for the last line, if it’s not sufficiently long to reach the edge of its container).
The spec adds two new values that could be quite useful on internationalized websites using right-to-left (RTL) language systems: start
and end
.
For left-to-right (LTR) readers, they correspond to left
and right
respectively. When a website uses a RTL language, start
corresponds to right
and end
corresponds to left
.
element {
text-align: start;
}
element {
text-align: end;
}
Applying text-align: match-parent
to an inline child element ensures that the child inherits the same alignment as the parent. The inherited start
or end
value is calculated against the parent’s language direction resulting in an output of either left
or right
.
The text-align-last
Property
New to CSS is also the text-align-last
property. This property controls the alignment of the last line of justified text before the end of a paragraph or before a <br>
tag. It has the same keyword values as text-align
, except for auto
, which is the default value. The auto
value allows you to align the last line of text according to the value of the element’s text-align
property, if set. If no text-align
property is applied, the text defaults to a value of start
.
At the time of writing, browser support for text-align-last is rather poor. Therefore, it’s my view that it should be used sparingly, if at all.
View a CodePen demo showing these features in action
Indenting Text
Indenting a line of text, usually the first line in a paragraph, is not something you often come across on websites. Instead, an empty line is placed as a common visual mark of separation between paragraphs.
Nonetheless, indenting the first line of a paragraph is sometimes used to create a classic look suitable to specific designs.
If your design is enhanced by this technique, CSS offers the text-indent
property. Let’s consider the possible values.
A value of length
is commonly set using px or em units:
element {
text-indent: 2em;
}
A percentage is set using a percentage value:
element {
text-indent: 6%;
}
A value of each-line
indents the appearance of the first line inside a block container as well as each line after a forced line break, that is, a line break caused by hitting the enter key or inserting a <br>
tag in the HTML source. However, the display of the first line after a soft wrap break, that is, text that wraps to the next line to fit its container, is not affected.
A value of hanging
causes all lines except the first line to be displayed as indented.
The each-line
and hanging
values are experimental values, not yet implemented in any browser at the time of writing.
View this demo to see text-indent in action
Conclusion
CSS has been making huge progress towards web text manipulation, although more is expected to be done. Besides sketchy browser support for some of the newest properties, it would be nice, for example, if CSS offered kerning capabilities, i.e., the opportunity to manipulate the distance between two letters in a given word.
In this post I delved into a number of CSS properties that control formatting, line wrapping, and alignment of text on the web. Feel free to experiment with these using the demos.
I look forward to your feedback!