Jeff Croft

I’m a product designer in Seattle, WA. I recently worked at Simply Measured, and previously co-founded Lendle.

Some of my past clients include Facebook, Microsoft, Yahoo, and the University of Washington.

I’ve authored two books on web and interactive design and spoken at dozens of conferences around the world.

I’m currently accepting contract work and considering full-time opportunities.

Blog entry // 05.29.2007 // 10:45 AM // 27 Comments

Typogrify: easily produce web typography that doesn’t suck

Ever since I’ve worked at the Journal-World, I’ve lamented the fact that the typography on our sites left something to be desired. Straight quotes, widows all over the place, and so forth. And even though our programmers do care about typography (one of them is even quite the type nerd!), I had trouble getting the matter at the top of anyone’s (very long) priority list. I said I’d buy several beers for the first programmer to make John Gruber’s Smartypants a default piece of Ellington, the publishing system we develop and sell. Even that wasn’t enough of an incentive.

That is, until we hired Christian Metts, a designer who also happens to be quite a good programmer. Christian must have really wanted those beers, because he went way above and beyond my request and created a library of Django template filters that is almost certainly the best thing to happen to web typography since Matthew Carter crafted Georgia. It’s called Typogrify, and it’s available at Google Code.

Included filters

Typogrify includes several filters which can be used individually, or you can go whole-hog and do ‘em all. I’ve been using it here on my sites for a month now, and we’re using it on the recently redesigned Lawrence Journal-World site, as well. It works great. To see it in action, check out Christian’s example page. Here’s a quick overview of the various filters available in the package:


The amp filter wraps apersands in html with <span class="amp"> so they can be styled with CSS. Ampersands are also normalized to &amp;.


The caps filter wraps multiple adjacent capital letters in <span class="caps"> so they can be styled with CSS. It even understands multiple caps separated by periods (like D.O.T.) and multiple caps mixed with digits (like 31THREE).


The initial_quotes filter adds class="dquo" (for double quotes) or class="quo" for (single quotes) to specific block-level HTML elements (h1-h6, p, li) which begin with quote marks (and understands that inline elements like a, em, strong, span, b, and i may be the first thing inside those block level elements). This makes for easy creation of hanging quotation marks with CSS.


The smartypants filter runs the text through John Gruber’s wonderful Smartypants engine, which converts straight quotes to curly ones, double hyphens to em dashes, and sundry other typographical niceties.


Copping its name from Shaun Inman’s Wordpress plug-in, the widont filter replaces the space between the last two words in an HTML element with &nbsp; to ensure you never have just one word on it’s own line (a widow, in typography). It works on these elements: h1-h6, p, li a, em, strong, span, b, i


Finally, there is the typogrify filter, which applies all of the previous filters. My favorite!

Usage of these filters

These filters work just like all Django filters. You simply use Unix-style pipe syntax to pass some variable through a filter. As usual, you can daisy chain multiple filters. For example:

Also, there’s the oft-forgotten {% filter %} tag, which lets you run a filter on a block of text in a template, which may or may not include variables. It even works on variables with other filters attached. For example:


Recently added to Django’s “contrib” apps (these are applications which are distributed with Django, but aren’t part of the core framework) is django.contrib.webdesign. There’s not much there yet; my understanding is that it’s effectively a placeholder for contributed apps that are useful to web designer. I, for one, think Typogrify fits the bill, and I’m hereby calling for its inclusion in django.contrib.webdesign.

I still haven’t bought Christian those beers. But I will.


  1. 001 // Kevin Hamm // 05.29.2007 // 11:42 AM

    Jeff, let me know the final bill on those beers, I’ll buy half of them! Great work, Matthew!!

  2. 002 // Tom // 05.29.2007 // 11:51 AM

    Very nice work indeed. It’s great to see web typography being hauled up to scratch with print! I think perhaps even more than some beers is in order!

  3. 003 // Rémi Prévost // 05.29.2007 // 11:54 AM

    Typo alert! You wrote “a window, in typography” instead of “widow

  4. 004 // Henrik Lied // 05.29.2007 // 12:35 PM

    Let’s set up - with Typogrify included, of course!

    But yes - Typogrify is simply a wonderful library. I’m currently building a rather extensive site, and Typogrify is of course included.

  5. 005 // Jeff Croft // 05.29.2007 // 2:16 PM

    Thanks, Rémi. I fixed it. :)

  6. 006 // Bryan Veloso // 05.29.2007 // 2:39 PM

    Wee! This keeps getting better and better! :D Thanks Jeff!

  7. 007 // Tom Watson // 05.29.2007 // 5:22 PM

    I like it! I’ve been using SmartyPants for a long time but just recently noticed that the primes weren’t getting converted right in my recent post about height.

    It was converting them when the appropriate thing in this (edge) case would have been to just have left them as primes. I wonder if it does it with your implementation… 6‘9”.

  8. 008 // Jeff Croft // 05.29.2007 // 5:37 PM

    Looks like it’s wrong here, to, Tom. Not surprising — the Smartypants that Typogrify uses is just a straight port of Gruber’s original to Python. It should, in theory, do exactly the same thing. Would be nice to get that corrected, though! :)

  9. 009 // Scott Johnson // 05.29.2007 // 7:31 PM

    I think it would be great to include typogrify in contrib. To me, it’s an essential library that no site should be without. (And I just discovered it yesterday!)

  10. 010 // Ryan Miglavs // 05.29.2007 // 10:36 PM

    Wow! Thank you, Christian, and thank you, Jeff! This is great work, and as it spreads the web will grow to be a better place. I love me some type.

  11. 011 // Hamish M // 05.30.2007 // 8:31 AM

    Wow, this is great stuff, Kudos to Christian — do you think he would mind if I ported some of the code for a Wordpress plugin?

  12. 012 // Christian Metts // 05.30.2007 // 10:32 AM

    Thanks everyone. I’m glad you’re enjoying it/finding it useful.

    Hamish: Go for it. It’s licensed under the New BSD. Do whatever you want with it. It’s pretty much just a pile of regexes. :)

  13. 013 // Hamish M // 05.30.2007 // 12:13 PM

    Thanks Christian. Sure, it’s a just a pile of regexes, but they’re worth their weight in gold. ;)

    Haha, I’m such a typography geek.

  14. 014 // Florian // 05.30.2007 // 6:08 PM

    I wonder how typografy works for non-english typography-needs. Maybe that would need to be solved before integrating that with Django.

    And on a completely different topic: Jeff, I noticed that your RSS Feed doesn’t contain this posts code-examples …

  15. 015 // Jeff Croft // 05.30.2007 // 6:20 PM

    That’s a good point, Florian. The Django community values internationalization a lot, so that might indeed be an issue. As for the RSS feeds — whoops! I’ll fix that. :)

  16. 016 // Dave Lowe // 05.30.2007 // 11:10 PM

    I can’t wait to use typogrify on a project. It’s exciting too that this has come to Django, further establishing it as the framework for designers. :) Great job, Christian!

  17. 017 // Matt Boersma // 05.31.2007 // 10:01 AM

    I’ve been using smartypants and widont separately, but what I cobbled together didn’t work as well as this. Thanks so much, Christian!

    +1 on adding this to django.contrib.webdesign—lorem ipsum is lonely!

  18. 018 // Joe Clark // 05.31.2007 // 4 PM

    And how does it handle the problem cases of words (not always beginning with numerals) that take an initial apostrophe? I think we’ve all seen the ‘90s a few too many times. (This gets trickier with some British and Irish English house styles that use single quotes.)

    Do the macros avoid the WordPress overregularization of any numeral+close quote ? numeral+prime?

  19. 019 // Jeff Croft // 05.31.2007 // 5:30 PM

    And how does it handle the problem cases of words (not always beginning with numerals) that take an initial apostrophe?

    Since Typogrify uses Smartpants, the answer is “just the same as Smartypants does it.” I’m not actually sure if Smartypants does it correctly or not.

    Do the macros avoid the WordPress overregularization of any numeral+close quote ? numeral+prime?

    Typogrify is for Django, not WordPress, so there are no hooks in it for WordPress’ shortcomings. There is now a Typogrify port for WordPress by a third party — not sure if it accounts for this or not (I’ve never used WordPress, so I wasn’t even aware it had these issues).

  20. 020 // Mike Birch // 06.01.2007 // 8:53 PM

    to ensure you never have just one word on it’s own line

    Looks like a random straight apostrophe sneaked through the Typogrify filter, and also the grammarify filter ;)

  21. 021 // Richard Rutter // 06.05.2007 // 3:28 AM

    That’s great stuff Jeff. I asked John Gruber at SxSW if he had any plans to expand Smartypants, and he asked me what I’d like to see. I came up with a list very similar the additions you describe in Typogrify (and John said he’d already developed a few himself, such as widont functionality). This all makes me very happy.

    Joe’s point about initial apostrophes is a tricky one though, and would probably require a whitelist of exceptions to deal with words such as ‘flu and ‘90s. As Joe pointed out, we Brits have a tendency to ‘use single quotes’ rather than “double quotes” for inline speech and quotations, which could make automation harder.

  22. 022 // Michelle // 06.06.2007 // 1:22 PM

    Maybe this is a stupid question, but can this tool also be used out of the boy with German or French..? I mean because of the special character the languages do have.

  23. 023 // johno // 10.08.2007 // 2:22 AM

    This is a wonderful plugin. I’m using Hamstu’s php port.

    Beautiful site, btw.

  24. 024 // Tony Arnold // 03.23.2008 // 12:29 AM

    Not that I’ve hooked it up to my site yet, but if anyone is using 21 degrees’ awesome CMS ‘Symphony’, I’ve put together a text formatter based on Typogrify for their upcoming 2.0 release.

    You can download a copy at the Symphony forums: <a href=”“ rel=”nofollow”>…

  25. 025 // Tony Arnold // 03.23.2008 // 12:31 AM

    Oh, for full disclosure, my Symphony extension uses Hamstu’s PHP port of Typogrify to work the magic.

  26. 026 // Helmet // 12.11.2009 // 4:38 AM

    Thanks a lot for Typogrify.

    One caveat, though: How do I deactivate the CAPS function?

    All the best

  27. 027 // Andy Walpole // 12.17.2009 // 2:44 AM

    Interesting, but should we really be using dynamic code for presentation? It’s best just to stick to CSS although I’ll give it a go to see it plays out on a live site.

Tags for this entry
Links in this entry