Styling a poem with advanced CSS selectors

CSS3 selectors offer endless possibilities of targeting specific HTML elements without the need of extra markup (which was already possible with previous versions of CSS). This time, I’m going to style the popular nursery rhyme “Twinkle Twinkle Little Star” using advanced CSS selectors, all in less than 5 minutes!

Coding a poem

There isn’t a consensus on how a poem should be marked up using HTML: most people believe that each stanza should be a paragraph (p) and each line separated by a line break (br). There have been some mentions to a future poem tag on HTML5, but it’s very unlikely to happen! :)

The markup

There are 3 main elements in our markup: 1) the title; 2) the sub-title, with the author information; and 3) the poem itself. This is the very simple markup we are going to use for this example:

<h1>Twinkle Twinkle Little Star</h1>
<h2>by Jane Taylor, 1806</h2>

<p>Twinkle, twinkle, little star,<br />
How I wonder what you are!<br />
Up above the world so high,<br />
Like a diamond in the sky!</p>
<p>When the blazing sun is gone,<br />
When he nothing shines upon,<br />
Then you show your little light,<br />
Twinkle, twinkle, all the night.</p>
<p>Then the traveller in the dark,<br />
Thanks you for your tiny spark,<br />
He could not see which way to go,<br />
If you did not twinkle so.</p>
<p>In the dark blue sky you keep,<br />
And often through my curtains peep,<br />
For you never shut your eye,<br />
Till the sun is in the sky.</p>
<p>As your bright and tiny spark,<br />
Lights the traveller in the dark,&mdash;<br />
Though I know not what you are,<br />
Twinkle, twinkle, little star.</p>

Styling the headings

Before starting to style the elements on the page, lets just add some basic resets and defaults:

body {
	background: #FFF;
	color: #111;
	font: 14px Baskerville, "Palatino Linotype", "Times New Roman", Times, serif;
	text-align: center;
	div, h1, h2, p {
		margin: 0;
		padding: 0;

We will also wrap our poem inside a div, to center the content nicely on the page:

#poem { 
	margin: auto;
	padding: 20px 0;
	text-align: left;
	width: 390px;

Next, we will center our headings and override the default bolds that headings have:

h1, h2 {
	font-weight: normal;
	text-align: center;

Now, we will set the font size of the main heading, the h1 tag; add a nice margin to the bottom; and a small line-height (because the font is so large, this way if our heading is very long, the lines won’t be too far apart from each other):

h1 {
	font-size: 34px;
	line-height: 1.2;
	margin-bottom: 10px;

For the h2 heading, with the author and date details, we will use a different, lighter colour; set a smaller font-size; make it italic, for that extra special touch; and also add a bottom margin:

h2 {
	color: #666;
	font-size: 18px;
	font-style: italic;
	margin-bottom: 30px;

The poem

For the body of the poem itself, we will add a larger line-height, so that each line has some white space around it and is easier to read. We will also add a bottom margin to each paragraph, to visually separate each stanza:

p {
	line-height: 1.5;
	margin-bottom: 15px;

The magical selectors

And now we can start having fun! First, lets add a decorative element before and after the author details. This will be done using the :before and :after pseudo-elements in conjunction with the content CSS property:

h2:before {
	content: '— ';
h2:after {
	content: ' —';

Now, let’s make the first letter of the poem really big — a drop cap. For that, we will be using the adjacent sibling selector (+) and the :first-letter pseudo-element. The adjacent sibling selector lets us target selectors that directly follow each other and are within the same parent element (for example, inside the same div). We will target the first letter of all paragraphs that follow an h2 tag, which, in our example, is only the first paragraph of the poem:

#poem h2 + p:first-letter {
	float: left;
	font-size: 38px;
	line-height: 1;
	margin: 2px 5px 0 0;

So we floated the first letter to the left, so that the rest of the text wraps around it; used a bigger font size; reduced the line-height, so that the following lines aren’t pushed down; and slightly repositioned the letter within the paragraph with some margin settings.

Next, we’ll make the first line of each paragraph display the letters in small-caps, and, to make it easier to read, add some extra space between each letter:

#poem p:first-line {
	font-variant: small-caps;
	letter-spacing: 1px;

To wrap things up, we’ll just add an extra bottom margin to our last paragraph, so that the poem is well separated from whatever comes next. For that, we will use the :last-child pseudo-element, which lets us target an element that is the last element of its parent:

#poem p:last-child {
	margin-bottom: 30px;
	padding-bottom: 30px;

And we’re done!

Some notes on browser support

Don’t expect this to work equally on every major browser. The latest versions of Safari, Firefox and Opera do support all the selectors. But… Internet Explorer 8 doesn’t support the :last-child pseudo-class; Internet Explorer 7 doesn’t support :last-child or the :before and :after pseudo-elements; and IE6 doesn’t support the :first-letter pseudo-element, on top of that.


This is a very basic tutorial on how CSS advanced selectors can be used in our stylesheets to address specific HTML elements without having to use extra classes, IDs or bloated markup. It will not work on older browsers, like Internet Explorer 6, which will render only the most basic CSS properties (with few exceptions), but that won’t make the text unreadable — it will simply add a new layer of detail to modern browsers, as if it was a little present for people who are up-to-date.

View example [download id=”7″]

Further reading