Grow your CSS skills. Land your dream job.

A Call for ::nth-everything

Published by Chris Coyier

With CSS3, we have positional pseudo class selectors to help us select specific elements when there are no other distinguishing characteristics other than where it is in the DOM in relation to it's siblings.

:first-child
:last-child
:nth-child
:nth-last-child

:first-of-type
:last-of-type
:nth-of-type
:nth-last-of-type

:only-child
:only-of-type

We also get a couple of text-specific pseudo elements to help with our typography needs:

::first-letter
::first-line

That's a great start, but it really would be useful if we could extend the whole ":nth" concept to these typographic selectors. Let me convince you.

Please note that most of the code below is not valid. It's example code. Like "wouldn't it be cool if" code.

::nth-line() / ::last-line / ::nth-last-line()

We already have ::first-line, so to complete the set let's add ::nth-line(), ::last-line, and ::nth-last-line().

With these, we could select the first two lines of a poem to highlight.

article.poem p:first-child::nth-line(-n+2) {
  font-variant-caps: small-caps;
  color: red;
}

I don't know from poetry, Brendon.

Or perhaps we could fade out the end of a passage.

article.poem p:last-child::nth-last-line(3) {
   color: hsla(26, 5%, 25%, 1);
   font-size: 70%;
}
article.poem p:last-child::nth-last-line(2) {
   color: hsla(26, 5%, 50%, 1);
   font-size: 60%;
}
article.poem p:last-child::nth-last-line(1) {
   color: hsla(26, 5%, 75%, 1);
   font-size: 50%
}

If we were allowed to use generated content on these line pseudo elements, we could accomplish something like line numbering without having to resort to intrusive markup.

pre::nth-line(n)::before {
  content: counter(line) ". ";
  color: #999;
}

Look ma, easy practical multi-line code styling.

Relevant article by Adam Prescott.

::nth-word() / ::first-word / ::last-word / ::nth-last-word()

We currently don't have any word-based pseudo elements. We do have word-spacing though, which is notable.

One use case is similar to using ::first-letter for drop caps, only doing a whole word.

article p::first-word {
  float: left;
  font-size: 300%;
  margin: 0 10px 10px 0;
}

Also similar to the "fade out" of lines above, we could fade out a passage word-by-word using ::nth-last-word(n).

::nth-letter() / ::last-letter() / ::nth-last-letter()

We already have ::first-letter, which sees pretty decent usage, so why not complete the set?

Of all of these "new" selectors, ::nth-letter is likely the most useful. For instance, Lettering.js wraps letters in <span>s for us so that we can select individual letters. This would be entirely unnecessary with ::nth-letter.

Take this example:

h1.fancy::nth-letter(n) {
  display: inline-block;
  padding: 20px 10px;
}
h1.fancy::nth-letter(odd) {
  transform: skewY(15deg);
  background: url(light-red-pattern.png);
}
h1.fancy::nth-letter(even) {
  transform: skewY(-15deg);
  background: url(dark-red-pattern.png);
}
h1.fancy::nth-word(n) {
  margin-right: 20px;
}
h1.fancy::last-word {
  margin-right: 0;
}

Check out all the examples at Lettering.js -- all of those are good examples of the need for this.

Another word/letter combination example is a formal "letter", like:

<p>Dear Emily,</p>
<p>yadda yadda yadda.</p>
<p>Love, Chris.</p>

Perhaps this "letter" is generated by dynamic content from a database, but we want to ensure the proper capitalization and style of the opening and closing lines.

.letter p:first-child::nth-word(-n+2)::nth-letter(1),
.letter p:last-child:nth-word(-n+2):nth-letter(1) {
  text-transform: uppercase;
}

The Complete Set

So if we get all of this, the complete set would be:

:first-child        :first-of-type        :only-child
:last-child         :last-of-type         :only-of-type                  
:nth-child          :nth-of-type    
:nth-last-child     :nth-last-of-type

::first-letter      ::first-line          ::first-word
::last-letter       ::last-line           ::last-word
::nth-letter        ::nth-line            ::nth-word
::nth-last-letter   ::nth-last-line       ::nth-last-word 

Again, just wishful thinking. If there is anyone I can put this in front of that can do something about it, I will. And I'll also keep this updated with the feedback on it, positive or negative.

For the record, this isn't a new request. Anne van Kesteren called for it in 2003.

Comments

  1. Permalink to comment#

    Great idea, Chris!

  2. cnwtx
    Permalink to comment#

    How about “first-sentence, last-sentence, nth-sentence, and nth-last-sentence”?

    • Cool thought! How would you determine exactly what a sentence is though? All the text up until a period?

      What about:

      Mr. Penguin forgot his shoes in St. Augustine.

      I haven’t thought about it for very long, but at a glance it seems like it would be pretty hard to make smart enough to be useful.

    • cnwtx
      Permalink to comment#

      Yeah. . . I thought about that. You might, in certain time, get away with a: Period followed by a space, followed by a capital letter. But, that would make your example three sentences. Maybe it’d interpret “.” as the end of a sentence, and . as anything else?

    • cnwtx
      Permalink to comment#

      Whoops. . . It took that literally. It’s supposed to be: o

    • cnwtx
      Permalink to comment#

      Hmm. . . Still didn’t work. I’ll put spaces in between the characters this time: & # x 2 E ;

    • Permalink to comment#

      dots is the KING! :D

    • bill
      Permalink to comment#

      Don’t sentences also end with question and exclamation marks?

    • cnwtx
      Permalink to comment#

      Well, they’re a little easier to deal with, because you’re probably not going to encounter them in the middle of a sentence like you might periods.

    • How about if the period, exclamation point, and question mark are assumed to represent the ends of sentences and, if there are special cases involving periods within sentences, they require encoding?

      Mr. Penguin forgot his shoes in St&amp#46; Augustine.

    • Well that didn’t come out well — looked good in the preview though.

      A period can be encoded with & # 46;

    • cnwtx
      Permalink to comment#

      That was what I was trying to say earlier with & #x2E;.

    • Or regular expression selectors that let you select any text you like (define your own “sentence”).

  3. Permalink to comment#

    Looooove you.

  4. This makes good sense. I’d love to see more powerful tools like this built into CSS.

  5. Great ideas Chris :)
    Are you going to do something with this if you get enough responses? Can you submit it to the CSS working group for spec consideration/inclusion?

  6. Well Microsoft Word seems to do a good job with it. Word recognition, fragments, etc. I’m sure an algorithm could be created to pretty accurately determine that.

    Great article btw. Really good ideas in there.

  7. Wow, great idea.

  8. Alex Mellor
    Permalink to comment#

    All I want for Christmas is a parent selector; x < y.

    But yes, these would give us a lot more control over styling so I’m all for it!

  9. I hope at least some of this gets implemented soon. ::nth-line alone would be excellent for line numbering. Even an unintrusive solution without presentational markup today still requires a touch of JavaScript to hook into lines.

  10. I’m almost certain that these selectors (or ones similar to their functionality) will be added to CSS4.

  11. I took the liberty to post this to the CSS WG mailing ist.

    Let’s see if anyone picks it up, especially Fantasai (Elika Etemad) who is the editor of CSS 4 selectors.

  12. Permalink to comment#

    Rather than have an epic ton of selectors, why not use more programmatic approaches:

    ::nth-child()
    ::nth-line()
    ::nth-word()
    ::nth-letter()

    Then allow numerical specification for first, last and patternistic:

    ::nth-line(0) — first line
    ::nth-word(-1) — last word
    ::nth-letter(5n) — every 5 letters

  13. Permalink to comment#

    Can I add these to this year’s Christmas list?!? Better yet, let’s vote Chris the next WC3 President! Seriously though, this truly addresses the gap between print and web in everything my organization publishes. Anything that carries traditional (and time-honored) print layout techniques to new media is better for everyone anyway.

  14. I would love a :mod-nth-child where you can specify a modulus so you can do interesting things with every 3rd child or something.

  15. That ‘fit to scale’ example looks great!

  16. Permalink to comment#

    Very useful for blogazine maniacs! :D

  17. Charlie
    Permalink to comment#

    First letter would be great!

  18. Permalink to comment#

    great tips. will start using soon.
    Thanks Chris.

    • Josh
      Permalink to comment#

      These were not tips, they were simply wishful thinking. If you attempt to use these they will not work.

  19. Pat
    Permalink to comment#

    One complication is that in some languages / writing systems (Thai, to pick one) words aren’t distinguished by spaces, so defining “nth word” is non-trivial.

  20. Great read as always Chris!

    I’m thinking of SitePoint’s “Make Your Own Custom jQuery Selector” (http://ow.ly/7fdQK) and take that for a spin. Yes, yes, it isn’t CSS as we would like it of course, but it could be a start?

    Again, if you think about LESS.js, they’ve added their own “&:”, which I think is exclusive to .less files. So that must mean that it could be possible to extend the LESS.js code with the same structure that made the “&:” possible, just with this problem in mind instead? Could be one way. :)

    Keep up the amazing work! Your Lynda guide on WordPress really helped me out some time back, thanks for that.

  21. I can only say one word Chris:

    COOOOOOOOOOOOOOOOOOOOOOOOOL

    man, I knew almost everything about CSS3 new selectors, but I could never think of these usages you mentioned here. Also your new suggestions are exceptionally useful and practical.

  22. wow, so cool. I just know css3 is so powerful. many thanks for share.

  23. There’s some really nice ideas in there Chris. My favourite example is with line numbering for code, something which is generally a pain to markup!

  24. Wouter J
    Permalink to comment#

    Nice list!

    I am going to support some of these nth-everything things in my own JavaScript Engine (wjSelect).

  25. Permalink to comment#

    Really like the idea of a :nth-lat-word style selector, I was recently creating a “fade out text at bottom into a read more anchor” style effect (instead of … ). Ended up using positioning and gradients which worked Ok in that scenario but wouldn’t all.

  26. Gabe
    Permalink to comment#

    My ratio of caffeine to sleep is insufficient to fully parse these concepts. But I can tell it’s interesting.

  27. I’ve been thinking similarly just recently – very well put sir!

  28. Dang! I doubt I would have thought of this, but man these things look like they could be handy. Now I’m going to be spending the next little while looking into polyfills.

  29. Topan Lutfi
    Permalink to comment#

    Good list.
    Awesome,, this is useful for me.

  30. nice examples you have mentioned chris………..surely helpful for us.

  31. Matt Waldron
    Permalink to comment#

    Good thinking Chris…I was just thinking this would be a neat idea for headline replacement on blog article summaries. In fact you wouldn’t have to write any headlines at all, or add any heading or span tags in your markup…just have the first sentence of the paragraph automatically highlighted in the style of your choice w/link to full article.

  32. cpg
    Permalink to comment#

    Excellent. Where do you find the time to think up these awesome improvements to where we are now? I can’t keep up with what is already out there, let alone extend it into new territory.

  33. What’s the difference between :after and ::after/ Your post (this one) suggests that some selectors use a single colon, and some others use a double colon. If so, that how to know which one to use and for what?

    • Wouter J
      Permalink to comment#

      @aaron:

      There are in CSS psuedo classes and psuedo elements. There is no difference between this types in CSS2, but in CSS3 there is a difference.

      To make it more logic the developers of CSS added a rule that psuedo elements have a double colon and psuedo classes a single colon.

      For instance, an element is ::first-letter. And an class is ::first-child.
      You should see it in this way:
      With ::first-letter you grab the first letter and push a span around it:

      <p><span>H</span>ello world</p>

      NOTE: This don’t happend in a browser
      A span is an element, so psuedo elements.
      With :first-child you have more than one child:

      <li>Hello</li>
      <li>World</li>
      <li>...</li>

      With first-child you give a class to the first child. So this is an psuedo class.

    • So isn’t ::after and ::before also pseudo-elements? Don’t we usually use :after and :before? And I thought pseudo-elements meant false elements, elements you create through CSS. Essentially, I can look at it this way: I create a new element that contains only the first letter of the paragraph, and I style that new element. But when I’m using :first-child, I’m actually selecting some element already there in the HTML.

      And what’s the difference between DOM and HTML? What is the full-form of DOM?

  34. Permalink to comment#

    Hey guys, what do you think of the AXR Project? Here’s a small alideshare presentation: http://goo.gl/8O6gK

    • Permalink to comment#

      My instinct is that of a vampire who faces garlic (halloween).. It looks kinda exciting tho with being able to move away from images etc in an even more extensive way than what we have.. Altho at a quick glance some things seemed more complicated than html/css when presented as “easier”.

    • Permalink to comment#

      We’d be glad to hear anymore oppinions on this, Jonathan.

  35. Adrian
    Permalink to comment#

    I love :nths. But that’s because I care. Most end users will not have the mindset where using these subtleties (which require a modicum of abstraction and imagination to usefully implement) will deliver real benefits, so I don’t don’t how high up on the list of priorities they will be.

    Take http://www.nthdegree.com/ for example – please tell me this is a very subtle spoof… my eyes were more glazed than a hand-fired raku pot. I’m squeaking excitedly with anticipation over what they do with ::nth-last-letter :)

  36. Adrian
    Permalink to comment#

    ‘don’t don’t?’ That was meant to say ‘don’t know’ – see, a grammar-checker is way higher on the list :)

  37. Wonderful ideas — and I’m with Alex Mellor on the value of a parent selector.

  38. Daniel
    Permalink to comment#

    I like the potential of ::first-word.

  39. Permalink to comment#

    for me this is like a language from hell, i dont understand anything haha

  40. Chris, thanks for your work on this.

    I just recognized that there is `p:last-child::nth-last-child(3)` aso. in the second example. Shouldn’t this be `p:last-child::nth-last-line(3)`? Or am I missing the point?

  41. Very cool suggestions to add to the spec. Also, if nth-line would be an inline pseudo-element this would enable easier “Multi-Line Padded Text”. Double win!

    Ps. Those fake comments are very annoying. Couldn’t a recaptcha help solve this?

  42. Anba
    Permalink to comment#

    ::nth-child()
    ::nth-line()
    ::nth-word()
    ::nth-letter()
    last-line
    last-child
    last-word
    all of them above not working for me any one help me to know how to use this

    • This whole article is about the stuff not working yet. If you really need the functionality, check into jQuery plugins.

  43. Glenn
    Permalink to comment#

    Clearly with all of these comments, there are a lot of people thinking the same thing.

    Here’s hoping that at least some of these ideas make it in to CSS4.

  44. Lucas
    Permalink to comment#

    Dammit – I actually thought these were real, and tried to use them, until I properly read that they were just drafts of possible ideas for implementations.

  45. Mr Shizank Shizanka
    Permalink to comment#

    This is awesome. God awful awesomeness. Thanks for publishing this as I was wondering in there was a global CSS command for differentiating text color.

  46. While we are wistfully wishing for selectors how about:

    ::character
    ::nth-character
    ::word
    ::nth-word
    

    Sometimes you might want to color an ::character(‘@’) differently, or not use italics on a | or use a different font for number characters, or make all instances of your company name red ::word(‘Apple’) , all swear words display: none or whatever!

    I’d love the ability to match subsections of text node content.

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".