Dreaming of CSS ::nth-letter: Why It Doesn't Exist and How to Fake It
For decades, designers have wished for a CSS selector that targets individual letters within a word—a ::nth-letter pseudo-element. While browsers support ::first-letter for drop caps, they've never extended it to arbitrary letter positions. This article explores the phantom selector, the creative demos that make it work (spoiler: via JavaScript), and why a true CSS polyfill remains elusive.
What exactly is the ::nth-letter selector?
The hypothetical ::nth-letter pseudo-element would let developers target specific letters inside a text node, much like ::nth-child works on elements. For example, h1.fancy::nth-letter(odd) would select every odd-positioned letter and apply styles like skew transforms or distinct backgrounds. The concept is natural—we already have ::first-letter—but CSS hasn't implemented it. The syntax would resolve a major pain point: applying per‑letter effects without wrapping each character in a <span>.

Why hasn't CSS implemented ::nth-letter natively?
CSS has to balance power with performance. A native ::nth-letter would require the layout engine to recalculate styles whenever text changes, which could be costly for long passages or dynamic content. Standardization takes years, and while the CSS Working Group has discussed similar proposals (like ::nth-letter and ::nth-word), they've never moved beyond discussions. Meanwhile, the upcoming CSS Parser API might eventually let authors define custom pseudo‑elements, but it's still nowhere near ready.
How do the demo videos and CodePen examples work if ::nth-letter doesn't exist?
The demos in the original article—like the skewed, colored letters and the direction‑aware hover effect—are all driven by JavaScript. A script splits the text into individual <span> elements, then applies inline styles or CSS classes to each span. The trick uses the sibling-index() function (Chrome/Safari only) to map letters to even/odd or arbitrary nth patterns. The result looks like a native CSS selector, but it's actually a clever workaround that cannot be done purely in CSS.
Is it really impossible to create a polyfill for CSS selectors like ::nth-letter?
Google engineer Philip Walton (affectionately nicknamed “Polyphil”) once attempted to build production‑ready CSS polyfills but concluded that reliable polyfilling is impossible. His abandoned framework worked for simple cases but failed when selectors interacted with complex layouts, dynamic content, or browser‑specific edge cases. CSS polyfills require parsing stylesheets, modifying selectors, and injecting JavaScript—all of which break down under real‑world constraints. The demos shown here work because they're tightly controlled, not because they're universal polyfills.
What would real CSS with ::nth-letter look like?
Chris Coyier imagined this back in 2011:
h1.fancy::nth-letter(n) {
display: inline-block;
padding: 20px 10px;
color: white;
}
h1.fancy::nth-letter(even) {
transform: skewY(15deg);
background: #C97A7A;
}
h1.fancy::nth-letter(odd) {
transform: skewY(-15deg);
background: #8B3F3F;
}
That syntax would be declarative, maintainable, and performant. Today, you need to add a JavaScript shim that breaks text into spans and then write equivalent CSS rules for those spans. The effect is the same, but the markup is cluttered and the code is harder to maintain.
Can we achieve advanced typography effects without JavaScript today?
Some effects are possible with existing CSS: ::first-letter for drop caps, text-decoration and text-shadow for underlines and glows, and background-clip: text for gradient text. But per‑letter transforms, alternating colors, or direction‑aware hovers remain impossible without JavaScript. The closest we have is splitting text manually into <span>s in HTML, which is tedious and not dynamic. Until a native ::nth-letter arrives, developers must choose between heavy JavaScript and limited styling.
What future CSS features could help fill the gap?
The CSS Parser API (still a draft) would let authors define custom at‑rules and pseudo‑selectors, potentially enabling user‑land ::nth-letter implementations. Another promising area is the CSS Houdini suite, particularly the Custom Paint API and Typed OM, which give developers low‑level control over rendering. However, these are complex and not yet widely supported. For now, JavaScript remains the only practical way to style individual letters—and the demos we've seen prove that while you can fake it, a true CSS solution would be much cleaner.