A few months ago I threw together a quick redesign of the Learning jQuery site. It's nothing fancy, mind you, but I was itching to retire the thin veil covering the tired old WordPress Kubrick theme, so something had to be done.
Almost immediately upon changing the font-family and font-size of the blog post titles, I noticed a few unsightly widows (just to clarify, we're talking about typographical widows. My mother already suspects me of avoiding her; I don't want to add to her anxiety. ;) ).
Here is an example of one such widow:
See how the last word, "plugin," appears on its own line? According to a couple designerly friends of mine, that's a no-no. So, I considered for half a minute how to get that title to look more like this:
Selecting the Titles
On this site, entry titles are wrapped in
<h2><a href="foo"></a></h2>, which can be selected in jQuery with
$('h2 a'). Easy. Now, because I want to manipulate the text of each title independently, I'll need to use the
.each() method, which is basically a chainable
for loop. Inside the
.each() is where I substitute the last breaking space with the non-breaking variety. Here are three ways I came up with to achieve this.
The first approach was to convert the title string into an array of words and then stitch the array items back together, dealing with the last one specially.
.pop() array method "pops" the last item off the array and returns it; so it's no longer part of
h2Array, but its value is stored in the
h2Last variable. This is especially handy for us, because we don't want the last word to appear twice.
Line 6 joins the remaining array items with a space between them and then appends the non-breaking space and the popped last item. Line 7 dumps that concatenated string back into the title, inside
The next approach involved working solely with strings, using the
lastIndexOf methods to split the the string into two pieces — one leading up to the last space, and one immediately following the last space.
As line 7 demonstrates, the two sliced strings are stitched back together to keep the last two words on the same line.
The final technique is the one I ended up sticking with, partly because it's the tersest and partly because I have a fondness for regular expressions:
The distinguishing feature here is line 4, which uses the
replace regular-expression method. This method takes two arguments, a pattern to match against and a replacement value. For the pattern, which appears between the two slashes, we first match a space and then match one or more "word characters" (letters, numerals, or underscores). The parentheses capture all but that initials space, and the "$" at the end ensures that the match appears at the end of the string. The replacement argument starts with the non-breaking space and follows with
$1, which refers to the first (and in our case, only) parenthetical "capture group." (Please forgive me if I've provided too much detail about the regular expression. I'm never quite sure how much of this stuff is worth mentioning, but since this entry is targeting beginners, I suppose it's better to err on the side of too much.)
By the way, all three of these code examples can be reduced in length quite a bit. For example, the regular expression example can be pared down from 7 to 5 lines if we don't bother with the
h2Text variable and instead do something like this:
$(this).html($(this).text().replace(/ (\w+)$/,' $1'));
However, the code is usually easier to read and maintain (for me, at least) if the value is first stored in a variable.
Any suggestions for improvement here? Any other approaches that you would recommend instead? Leave a comment.