bweaver.net

web design, technology, photography, and other mayhem

bweaver.net header image 2

Wrangling Drop Caps

March 17th, 2008

»Initial drop caps and first line small caps are a nice CSS effect, but getting getting them to work smoothly across all browsers is a challenge. The :first-letter and :first-line CSS selectors are great, but sometimes they need a little extra help to get the job done. Let's combine them with other selectors and use jQuery to improve cross-browser compatibility.

 

Setting the initial letter of a page—or chapter, or section—in larger type and dropping it down a bit into the text is similar to decorated initials common in illuminated manuscripts, such as the breathtaking Saint John’s Bible, and of course, in the world of print. Initial drop caps are fairly simple to accomplish on the web with CSS and the :first-letter pseudo-selector. But, as you might guess, the differences amongst various browsers can make this a frustrating exercise.

Often combined with initial drop caps, another common typesetting flourish is to set the remainder of the first word, first several words, or the entire first line in small caps. Here you use the CSS :first-line pseudo-selector, though it too suffers from a few browser peculiarities.

Pseudo-selector Basics

Pseudo-selectors, or pseudo-elements, give a designer the flexibility to style portions of the document that are not distinct elements within the DOM. The W3 definition is as follows.

Pseudo-elements create abstractions about the document tree beyond those specified by the document language. For instance, document languages do not offer mechanisms to access the first letter or first line of an element’s content. CSS pseudo-elements allow style sheet designers to refer to this otherwise inaccessible information.

:first-letter controls everything up to the first letter or number of an element, including punctuation, while :first-line, controls everything in the first line of an element. We will be building CSS rules with these selectors to create initial drop caps in a first line of small caps.

The Challenge

The eventual goal for the examples below is to style only the first paragraph of a content page from a CMS (such as WordPress), and assumes that the paragraph follows an h2 element.

The Solution(s)

There are a few approaches to using first-letter and first-line pseudo-selectors. One is to assign an explicit class to the element you wish to style. Another is to use preceding selector notation to target the CSS rule. A third method uses Javascript (jQuery in this article) to make things happen. All three approaches are covered in this article.

Explicit Class Solution

The first option is to assign an explicit class to the target element, and apply the pseudo-selector to that class, as shown in the next several examples. Setting the element class will look something like the following example, where the paragraph is given the class someclass.

<p class="someclass">Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Donec ullamcorper mauris sit amet
ante. Donec convallis nisl malesuada eros. Nullam volutpat
quam non elit.</p>

(For the examples in this article, all sample output elements also use a class of _examples—shown below—that sets the font size to 16 pixels and the line height to twice that. So the code above would use class="someclass _examples" to combine the two.)

._examples{
font-size:16px;
line-height:32px;
}

Initial Capital

The following CSS rule sets the font size for the first letter of the example1 class to 32px (two em).

.example1:first-letter{
font-size:32px;
}

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ullamcorper mauris sit amet ante. Donec convallis nisl malesuada eros. Nullam volutpat quam non elit.

Small Caps

To set the first line in small caps, we will use the font-variant property, as shown below.

.example2:first-line{
font-variant:small-caps;
}

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ullamcorper mauris sit amet ante. Donec convallis nisl malesuada eros. Nullam volutpat quam non elit.

Put example1 and example2 together and we get the two combined styles, shown below.

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ullamcorper mauris sit amet ante. Donec convallis nisl malesuada eros. Nullam volutpat quam non elit.

Dropping The First Letter

That looks nice, but tweaking things will make things look even better. The key is to float the letter to the left and move it down, then adjust to taste.

.example4:first-line{
font-variant:small-caps;
}
.example4:first-letter{
font-variant:none;
font-size:64px;
float:left;
margin:-.06em .1em -.3em -.1em;
line-height:1;
}

For this example, there are several adjustments to the first letter rule to produce something like the text below.

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ullamcorper mauris sit amet ante. Donec convallis nisl malesuada eros. Nullam volutpat quam non elit.

The first letter adjustments include applying a left float, bumping the font size up to 64px, then tweaking the margins and line height.

Setting the first letter size to 64 pixels is a matter of taste, but essentially makes the first letter approximately the size of two lines. The margin adjustments accomplish a few things. The top margin moves the baseline of the letter up to the bottom of the second line; the right margin adds a bit of space after the large initial letter; the bottom margin chops the invisible space below the letter so the following line will flow under it; and the left margin cheats the big serifs a bit into the left margin to the meat of the letter aligns with the smaller text below it.

And this is where browser discrepancies bite us. In Internet Explorer, the top margin used above do not work to lower the “L” into the text as they do in Firefox. In IE we need to adjust the line height to make it work.

h2 + p Solution

In this approach, we set up h2 + p:first-letter and h2 + p:first-line rules (or h3, etc.). The advantage here is that additional tagging is unnecessary, and nicely separates content from display.

h2 + p:first-letter {
font-size:3em;
display:block;
float:left;
}
h2 + p:first-line {
font-variant:small-caps;
}

Unfortunately, IE 6 fails to handle the element-preceding notation (+) when combined with a pseudo-element such as :first-line or :first-letter. It does not hurt anything; your styling will simply not be applied in IE 6.

Another potential ill-effect is the need to avoid multiple h2 tags per page, unless we want multiple first-letter / first-line styling.

Also, this can work if we do not care about IE 6 (or can accept the graceful downgrade) and can control the content tagging such that a single element such as h2 is followed by the paragraph in need of special styling.

The jQuery Solution

Here we use jQuery to tear apart then rebuild the target paragraph to explicitly invoke the correct CSS rules.

This solution works in IE 6 (but not IE 5.5 and below).

Include jQuery and the following script:

<script>
$(document).ready(function(){
	$("h2 + p:eq(0)").each(function(){
		var t = $(this).text();
		var f = t.substring(0,1);
		var l = t.length;
		if($.browser.opera)
			t = "<div class='operap'>" + t + "</div>";
		else t = "<div class='firstp'>" + t + "</div>";
		$(this).hide().replaceWith( t ).show();
	});
});
</script>

The code uses jQuery’s selector logic to target h2 + p:eq(0), and simply replaces the paragraph with a div of class firstp. An advantage of this approach is that you do not have to explicitly tag the first paragraph by hand. Also h2 + p:eq(0) is specific enough to target the first paragraph after the first h2 element and it because jQuery is doing the heavy lifting, it works in IE 6. Which brings us to Opera.

More Browser Disagreements

All this works fine in Opera, except the top margin and a little rendering issue.

	if($.browser.opera)
		t = "<div class='operap'>" + t + "</div>";
	else t = "<div class='firstp'>" + t + "</div>";
	$(this).hide().replaceWith( t ).show();

The code above uses a special class with a top margin for :first-letter of 0 if it’s running in Opera, otherwise it uses the normal class that works for IE and Firefox. Then, it hides the target element, sets the HTML, then makes the element visible again. This is because Opera does not correctly re-render the element after the HTML has been changed. This forces the re-render to happen in Opera. (The curious syntax in this last line is an example of chaining jQuery calls.)

Demo

Check out the demo of first-letter and first-line pseudo-selectors used in conjunction with jQuery.

Tags: web design

Have something to say?

Comments are disabled at bweaver.net for a variety of reasons. However, if you have something relevant or otherwise interesting to say, I do want to hear from you. Fill out the contact form below. When you click Send, your message will be emailed to me. Unless you spam me, I'll probably read it soon.