Last spring when I implemented a new design for my weblog, I wanted to use a fancy drop cap for the first letter of the first paragraph of the first post of each page. There are all sorts of ways to make a drop cap happen, but since I was reading Jeremy Keith's excellent book DOM Scripting at the time, I thought I'd do it that way. The DOM scripting method that I put together had some important benefits for me at the time:
- It used an image, so I didn't have to worry about installed fonts on users' machines
- The HTML source stayed intact, so search engines wouldn't trip over a first word with a missing first letter.
Now that I'm learning jQuery, I thought I'd revisit my code and see if I could tidy it up a bit, the jQuery way.
I first put together a set of images, one for each letter of the alphabet, using a font from the Dieter Steffman collection at typOasis. If you don't want to go through the laborious process of converting letters into images, you can download mine (20KB zip). See the letter "A" floating to the right of this paragraph for an example.
Setting up the Code
Instead of putting all of the code in a
$(document).ready() function, I created a separate function and just called it inside
Now we can get down to business.
Insert Image Here
The easiest part of the process was inserting the image, because jQuery makes it almost effortless.
I needed two variables here â€” one for the first paragraph ( first_paragraph ) of the post and one for the first letter ( first_letter ). I started by adding the image with its "src" attribute to the DOM. All of the image files had this basic naming:
/images/alphabet/n.gif, where "n" could be any letter of the alphabet, so you can see how I concatenated the "src" attribute using the file path, a lower-case "first_letter" variable and the image file extension:
Then I gave the image "alt" text in case images are turned off (thanks to Klaus Hartl for reminding me :) ) and a class for CSS styling:[js] .attr('alt',first_letter) .addClass('fancy-letter') [/js]
By the way, I could have put all four of those lines (minus the comments) on the same line and it would have worked the same, but I thought it would be more readable this way.
Now that the element was created, I wanted to add it to the page, right at the beginning of the first paragraph (hence the "first_paragraph" variable):[js] .prependTo( first_paragraph ); //Note the semicolon here [/js]
And that's it! The image is prepended to the first paragraph:[js] $('') .src('/images/alphabet/' + first_letter.toLowerCase() + '.gif') .attr('alt',first_letter) .addClass('fancy-letter') .prependTo( first_paragraph ); [/js]
So, let's back up a bit.
Set the First Paragraph
That bit of code so far isn't going to do anything until we know what
first_letter mean. For my purposes, finding the first paragraph was easy, since I knew it would always be the first paragraph of the DIV with an id of "main-content". We can write this a few different ways, but I wanted to get the DOM element itself, not the jQuery object, so I had to do it either like this:
or, per John Resig's suggestion, like this:[js] var first_paragraph = $('#main-content p'); [/js]
I then had to stop the script if a page for some reason didn't have a paragraph inside a "main-content" DIV. Easy enough:[js] var first_paragraph = $('#main-content p'); if ( !first_paragraph ) return false; [/js]
With that done, I moved on to the first letter.
Set the First Letter
This part was much harder. If I knew that the first letter would never be wrapped in a tag of its own, such as
<a href=""> or
<strong>, I'd be in good shape. But I didn't know that. I couldn't even be sure that the first letter wouldn't reside in nested tags. (Stay tuned for Part 2, in which I'll show how I tackled that problem.) To make a long tutorial a little less long, though, let's pretend that we can assume the first character of the paragraph will be a letter between a and z. We'll need to get the value of the "text node" of the first paragraph and then grab just the first character of it:
Line 1 gets the first child node of the paragraph and then the value of it. Line 2 gets a substring of that value from 0, which is the first character, to (but not including) 1, the second character.
Drop the First Letter of Text
It's a good thing we have that
text variable. We're going to slice that text at the second letter, so that the first letter is cut off:
Now we're done! For real this time! Prepending the image goes after slicing off the first letter. Just to be sure things wouldn't break, I also didn't let the slicing or prepending happen unless
text was really there. Here is the final code in its entirety:
Demonstration of the Fancy
Here is an example of the fancy drop cap. Lovely "H," no? The code to render this drop cap is the same as the code above, except it references a different ID.
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.