Fancy Drop Cap – Part 2

In Fancy Drop Cap - Part 1, I showed how I used jQuery to insert a drop cap on my personal weblog. But there is still some unfinished business to take care of:

  1. Accounting for cases in which the first paragraph (where I want my drop cap to go) starts with another tag of some sort (<a href="...">, <em>, etc.)
  2. Adding a little CSS to the drop cap

So let's begin with item 1. As you may recall, we defined three variables, first_paragraph, first_letter, and text. The variables allowed us to get the value of the textNode of the first letter of the first paragraph, so we could replace it with the image. Here is what that part looked like:

[js] var first_paragraph = $('#main-content p')[0]; if (!first_paragraph) return false; var text = first_paragraph.firstChild.nodeValue; var first_letter = text.substr(0,1); if ( text ) { first_paragraph.firstChild.nodeValue = text.slice(1); } [/js]

The only problem with that code is that line 3 assumes that the first child node of the first paragraph is actually a text node. But what if it's a span tag (<span>) or a link (<a href="...">)? Well, in that case we'll need to keep drilling down through the nodes until we can't go any farther.

Loop the Loop

To do that, we'll set an intermediate variable, called node, initially making it the same as first_paragraph:

[js] var node = first_paragraph; [/js]

Next, we change our node variable to be defined as the first child of that node (node = node.firstChild), and we keep doing that until there are no more child nodes left, by using a "while" loop:

[js] while (node.childNodes.length) { node = node.firstChild; } [/js]

So, in other words, as long as there is a child node, our variable will be reset as that child node.

The First Letter — and Only a Letter

When that's all done, we set our text variable, this time as the value of our node variable:

[js]var text = node.nodeValue;[/js]

Now all we have to do is get the first letter of the text so that we can replace it with the drop-cap image: var first_letter = text.substr(0,1).

There is just one more thing that we should account for — the possibility that the first character is either the beginning of a self-closing tag such as <img /> or some other character for which we have no image. In my case, I only want a letter "a" through "z" to be replaced. Here is a simple regular expression for that, followed by a "if" condition that wraps the image-replacement code:

[js] var first_letter = text.substr(0,1); var match = /[a-zA-Z]/.test(first_letter); if ( match ) { // image-replacement code goes here }[/js]

Line 2 tests if first_letter is a lower-case or upper-case letter. If it is, "match" will return true; if it isn't, "match" will return false. Thanks to Fil for posting a comment about that on Part 1.

The full code

Here is what all of the code looks like.

[js]$(document).ready(function(){ swap_letter(); }); function swap_letter() { var first_paragraph = $('#main-content p')[0]; if (!first_paragraph) return false; var node = first_paragraph; while (node.childNodes.length) { node = node.firstChild; } var text = node.nodeValue; var first_letter = text.substr(0,1); var match = /[a-zA-Z]/.test(first_letter); if ( match ) { node.nodeValue = text.slice(1); $('') .attr('src','/images/alphabet/' + first_letter.toLowerCase() + '.gif') .attr('alt',first_letter) .addClass('fancy-letter') .prependTo( first_paragraph ); } }[/js]

For an explanation of the parts of this code not discussed in this entry, see my previous entry, Fancy Drop Cap - Part 1.

Adding Some Style

If we leave the fancy letter the way that it is, it will stick up above the rest of the first line in the paragraph. But we want it to drop. Fortunately, we've given our image a class called "fancy-letter," so we can just attach the style to that class. Let's float the image left and give it some padding on the top, right, and bottom:

[css]img.fancy-letter { float: left; margin: 2px 2px 2px 0; }[/css]

That's all there is to it! If you'd like to try this on your own site, you can download the script here. You'll also need the jQuery source code, of course. And here is a zip file of the fancy letters that I use. (20KB zip)

Update: To see how you can add fancy drop caps to every paragraph within a certain DIV, see my other entry: Multiple Fancy Drop Caps.


I've written a Fancy Letter Plugin that does all the hard work for you. You write a line of jQuery like $('div.content p').fancyletter(). The plugin wraps the first letter of the selected elements in a <span> with class names that you can then style to your needs.

Responsive Menu
Add more content here...