Lettering.js was built to solve a problem. As web typography improves, web designers want the same level of control print designers have.

Just as we’ve moved beyond Helvetica and Times New Roman, we’ve begun to think about web type in finer detail than <h1> or <span> tags currently (semantically) allow. For example, when Dave Rupert and I prepared to markup the 3 sites for the Lost World’s Fairs project, we saw elements in each design that would require an excessive number of <span> tags to target words, even letters, at a time.

El Dorado
The Moon

Ideally, CSS selector pseudo classes or elements would work, but even with options like :nth-child and ::first-letter we wouldn’t be able to target all that we needed.  As eager as we were to dive into building these beautifully designed pages, we couldn’t help but realize two things:

  1. We needed more control over letters, words, and lines than CSS currently provided for.
  2. The markup was going to be extremely difficult to manage because wrapping individual letters in <span> tags would get messy quick.

An hour later Dave came back with the best solution we could think of: a simple jQuery plugin that injected <span> tags around letters, words, or lines within any declared element. Lettering.js let us build out & revise the pages, saving heaps of code as well as grunt work. It was such a lifesaver that we decided to share it with the web community, launching letteringjs.com late fall 2010.


Lettering.js was well-received, though there are a few valid criticisms that I’d like to briefly address:

If you buy good fonts, they don’t need to be kerned.
That may be, but some fonts do, and the thinking behind Lettering.js goes beyond kerning into overall control. What if web designers want to use italics, font-size, or even change font-family within an element?

Lettering.js isn’t the only way.
True, and it isn’t the ultimate solution either. Let’s consider our options from most problematic to least:

  1. Embed an image
  2. Use CSS image replacement
  3. Wrap letters or words in <span> tags
  4. Use JS to inject <span> tags after the markup as we have with Lettering.js

Even though the <span> tags aren’t in the markup, there’s still bloat.
This is true. While Lettering.js keeps the source HTML clean, it doesn’t do the DOM any favors and inserts quite a bit of code.

Load times are increased. Javascript libraries are loaded just to target a few words or letters.
Again, consider the alternatives.  An image could easily outweigh javascript code.  On the other hand, yes, it’d be ideal to do this independently from JS.

Can we replace Lettering.js with CSS?

I hope so. Lettering.js is a solution, but perhaps it’s not the ultimate solution. As I mentioned earlier, CSS Selectors come close. What if the CSS spec was adapted to fill in the gaps? After scouring the internet, here’s a brief timeline recounting what’s already been discussed.


The W3C proposed Cascading Style Sheets, level 1 (CSS1) featuring the ::first-letter and ::first-line pseudo selectors.


Anne Van Kesteren explored the idea of expanding selectors to cover ::nth-line(n) and ::nth-letter(n).


Safari 1.3 was released as the first browser to fully support both the ::first-letter and ::first-line pseudo selectors. It’s worth mentioning that prior to this, IE5.5+ (July 2000 ) and Firefox 1 (November 9, 2004 )  had partial/buggy support for these selectors.


An extensive (50+ message) CSSWG thread on Proposed ::last-line and ::last-letter selectors was started by Andrés Delfino. The feasibility was discussed at length, and rejected due to narrow user base and high cost / complexity.

At the time, this thread had trouble coming up with good use cases. With the expansion of pseudo selectors & available web fonts, good use cases are now everywhere. The discussion focused heavily on ::last-line and ::last-letter which may not be particularly useful.


As a necessity, Dave Rupert built Lettering.js as a workaround.  Version 0.6.1 has been downloaded 1500 times, with 550 watchers on Github, indicating that alongside the growth of web fonts, the ‘narrow user base’ is widening rapidly.

From CSS1, we’ve been able to use pseudo-elements to target ::first-letter.  What if you extended that idea to targeting letters, or even words, within an element similar to the CSS3 ::nth-child(n) selector, resulting in something like this:

  • h1:nth-letter(4); or h1:nth-char(4); targeting the 4th letter within an <h1> tag.
  • h1:nth-word(3);
    targeting the third word within an <h1> tag.

I think this would be the ideal solution from a web designer’s perspective. No javascript would be required, and 100% of the styling would be handled right where it should be- in the CSS. On the other hand, I have no idea what goes into implementing these additions for a browser, which is why the idea has been proposed as a blog post with comments. Please, feel free to share your own thoughts about how we can gain more typographic control on the web.

25 Responses

Leave a comment or contact me via Twitter @TrentWalton

  • Chandler Van De Water

    The people who take the time to push innovation on the web are what make the web great. You could sit back and use css image replacement and a big old negative text-indent but you don’t. Thanks for taking the time to research and explore these types of issues, Trent.

    It’s inspiring to not just take the easy route.

  • WKJ

    Great article. I am experimenting with lettering.js right now on some logo ideas.

    For some insight, not an answer exactly, as to why CSS and pseudo elements may not be as granular suggested above, check out Section “5.12.1 The :first-line pseudo-element” here: http://is.gd/nMqS7i

    For pseudo elements the browser is responsible for inserting “fictional tags” into the HTML. If these fictional tags happes to split other tags, the splitting doubles the tags involved.

    In the case of character level pseudo classing, the number of fictional tags and tag splitting could be enormous, slowing rendering.

    Just a guess though.

  • Joseph Schmitt

    Like Chandler said, you could have sit back and used inside-the-box techniques that don’t solve the problem you faced very well, or you could have pushed through the limitations and come through with a great solution. The web itself is a better place because you chose the latter. And if at some point the W3C does decide this feature is useful enough to include in the CSS spec, it will be because Lettering.js has shown there was a need for it.

  • Trent

    @Chandler Van De Water & @Joseph Schmitt: Thanks fellas. I’m glad you see it that way.

    @WKJ: Be sure to let us know if you put Lettering.js to good use.

    In the case of character level pseudo classing, the number of fictional tags and tag splitting could be enormous, slowing rendering.

    Good thinking. I’d love to get an expert’s input there- not sure it’d slow rendering a significant amount.

  • mark

    awesome! thanks for sharing the wisdom.

  • Montana Flynn

    Excellent writeup on the current and past conditions of typography on the web. I would certainly like to see the :nth-char psuedo class implemented, however it is unreasonable to believe we will be able to use it anytime soon.

  • Trent

    @Montana Flynn:

    however it is unreasonable to believe we will be able to use it anytime soon.

    Exactly! I’m not even sure it’s possible. That’s what makes this stuff so much fun. Here’s to looking ahead :)

  • Zach

    This is an excellent post! This is one of those things that you read and just say “duh, can’t believe I didn’t think of that!” The idea you’re proposing for the :nth-char pseudo class is just pure common sense. I’m really surprised something like that hasn’t already been included in css3, given all the other advancements made with animations and other javascript like behaviors.

  • Kevin Ripka

    I think the css spec should provide something like: p:char(i) + p:char(t) OR @char p(i + t) { measurement here }so that you can globally kern a font in your copy. So my example would take all the i’s followed by t’s with a p tag and add a kerning measurement. Then we’d have print like control and people who love type could create full stylesheets to optimally kern fonts.

  • Trent

    @Zach: I’m happy to know you see it that way. It’s great that :nth-char adds lots more control, but like you I’d like to see more.

    @Kevin Ripka: That’s a good thought. My main thought was to focus more on heading fonts, but if a web font is lacking this could come in really handy. On the bright side, more and more quality fonts are coming to the web, so we’ll get to worry less about all that.

  • Aaron Blakeley

    This might be the one of the best proposals that I have heard for handling typography for the web. Getting down to the letter is great and gives you lots of control. I think I would like to see pseudo classes for the :nth-word(n) as well.

  • Julian

    Well, without people like Trent and Dave there surely won’t be much change anytime soon.
    They’re what I’d call web-activists! An example we should all follow!

  • Trent

    @Aaron Blakeley & @Julian: Thanks, fellas :)

  • Chris Brauckmuller

    Awesome work guys. I think anyone who’s criticizing the “weight” of this little plugin is obsessing over performance way too much to have any fun designing a web page. It’s not like you’re going to be using this on every paragraph, likely just a few headers here and there and maybe some pullquotes or other calls to action. I say go for it, it’s way cleaner than image replacement or wrapping the markup by hand.

    The haters can go back to AOL.

  • Michael Maxwell

    I love these type of posts! I have been attempting to teach myself web design and resources like this are invaluable. Right now I am graduating from “place image here” to use css to do the job. Having this kind of control over typography will really make a design stand out. Adobe would have me believe that CS5 can seamlessly take any content and design from any of the bundled applications and import or export to the others and now my print document is a web page, now it is a book, a magazine... I have learned it is not quite that simple. As was stated above it is fun figuring these solutions out, except when my brain starts to hurt :^}
    Thank you and I am now going to distract myself with learning LetteringJS!

  • Trent

    @Chris Brauckmuller:

    It’s not like you’re going to be using this on every paragraph, likely just a few headers here and there and maybe some pullquotes or other calls to action.


    @Michael Maxwell: Hope you enjoy Lettering.js

    Right now I am graduating from “place image here” to use css to do the job.

    I still use images from time to time. If you’ve gotta use a font that isn’t yet something you can license for web-use, I’d say image replacement via CSS is a viable option.

  • Artem Pereverzev

    Control is what it’s all about, isn’t it? That and ease of styling. I mean, take CSS out of the picture and we are left with tables for our HTML. But CSS is meant to give you control over the appearance. Hope your proposal is at all implementable. Taking into consideration how long we have come in the last decade, I wouldn’t be surprised to see the issue on the carpet soon. As much as I love Lettering.js and think it is one of the recent wonders of the web, I welcome being able to skip those couple lines of code and style all the lines/words/chars from a stylesheet. Keep being awesome, Trent & Co.!

  • Florent Verschelde

    One thing to watch out for is that changing the dom of “word” to a bunch of SPAN elements (one per letter) will basically kill accessibility in a screen reader. Screen reader treat different element nodes as word separators, with some good reasons for doing so (like people writing word1word2 and relying on CSS to show the content as different words or lines). So it’s one more reason to maybe reconsider the :nth-line() and :nth-letter() ideas.

  • vinay

    @florent that’s where the css media query comes to play.

  • Gustavo

    This single handedly is the greatest article I have read thus far this year on typography for the web. If its okay I’d like to link to your post from my site.


  • Trent

    @Gustavo: Well, of course!

  • Gustavo

    You know after thinking about it: what is different than using an image for each block of text and having the text at least available for other devices in a format that could be used differently?

    I like the idea of being able to touch every single letter, I just wonder if it would be overkill. Has it got to that stage for you yet?

  • mikekidder

    Awesome! Very innovative approach, thanks for sharing Trent. Please continue to push that envelope for the rest of us.

    Found this site via Kern.js -> Lettering.js -> Cowpoke’s example

  • Marc Brooks

    Please tell me that h1:nth-char(-1) is the same thing as h1:last-char (and so on...) Then we’re REALLY talking :)

  • Flawlesscomplem96.blog.com

    Est-il possible de vous reprendre 2 ou 3 paragraphes sur mon site web ?

Leave a Reply