Quick Facts
- Category: Web Development
- Published: 2026-05-04 07:36:02
- Urgent Security Patches Deployed Across Linux Ecosystem: Chromium, Kernel, and More
- Iran War Reveals Erosion of US Economic Sanctions Power
- Urgent: Critical ASP.NET Zero-Day Allows Full System Takeover on Linux, macOS
- Record Viewership Expected as 152nd Kentucky Derby Approaches; Three Horses Scratched
- Go Marks 16th Anniversary with Production-Ready AI Focus and Major Testing Upgrades
CSS has always been a mix of love and frustration for web developers. One of the most requested but never implemented features is the ::nth-letter pseudo-element. Imagine being able to style each letter in a word individually—skewing, coloring, or animating them without touching JavaScript or adding extra spans. While the CSS Working Group has consistently ignored this plea, developers have found creative workarounds. This article explores the history, the impossible demos, and the clever hacks that let us pretend ::nth-letter exists today.
What exactly is the ::nth-letter selector and why do we want it?
The ::nth-letter selector would allow developers to target individual letters within a text element, similar to how ::first-letter targets only the first character. The idea has been floated since at least 2003, with early mockups by Chris Coyier showing how you could easily create alternating skewed letter styles with just a few lines of CSS. It would open up typographic effects like drop caps on every letter, rainbow texts, or interactive hover effects on each character — all without littering the markup with extra <span> tags. The CSS community has repeatedly expressed desire for this feature, but the W3C has not added it to any specification, citing complexity in implementation (especially with regards to line breaks and text direction). The dream, however, remains alive in countless demo pens and articles.

Why hasn't CSS implemented ::nth-letter after all these years?
The official reason is that ::nth-letter is technically difficult to implement reliably. Unlike ::first-letter, which only deals with one character, ::nth-letter would need to wrap each character in a pseudo-element, breaking the inline text into potentially thousands of elements. This impacts performance, especially on long paragraphs, and creates challenges with text selection, line-breaking, and accessibility. Additionally, the CSS specification prefers features that can be polyfilled, but as Philip Walton from Google discovered, writing a robust polyfill for CSS pseudo-elements is nearly impossible because of the way browsers handle the cascade and specificity. The CSS Parser API, which could theoretically let developers create custom selectors like ::nth-letter, has been promised since 2017 but never materialized. So, while the desire exists, the implementation hurdles have kept it off the standards track.
How are the fake ::nth-letter demos actually working if the selector doesn't exist?
The demos that appear to use ::nth-letter are clever hacks using JavaScript and CSS custom properties. They typically work by splitting the text into individual characters using JavaScript, wrapping each character in a <span> or inline element, and then applying styles via generated CSS. For example, a script can read the text content of an element, break it into an array of letters, and output each letter in a <span> with a CSS class like letter-1, letter-2, etc. Alternatively, some demos use the sibling-index() function in CSS (experimental in Chrome/Safari) to style <span> elements based on their position relative to a parent. The video demo by the author's eight-year-old child shows that you can even make a simple interactive page with a few lines of JavaScript that mimics the syntax. So while the CSS itself is invalid, the visual result can be achieved through scripted markup manipulation.
Can we write a reliable polyfill for ::nth-letter? What did Philip Walton find?
Philip Walton, a developer at Google, attempted to create production-ready CSS polyfills and concluded that building a reliable polyfill for CSS pseudo-elements is essentially impossible. The main issue is that CSS polyfills must parse and modify stylesheets at runtime, but browsers do not expose a clean API for that. Walton created an abandoned framework that attempted to do this, but it only works for simple cases and breaks with anything complex. For ::nth-letter, a polyfill would need to intercept the selector and transform it to target actual elements in the DOM. Because CSS selectors can be combined and overridden, the polyfill would have to replicate the entire cascade logic, which is both fragile and slow. As a result, any polyfill is likely to be unreliable and cause side effects. This is why most demos using ::nth-letter are either static or rely on JavaScript to inject the necessary markup rather than pretending to extend CSS itself.
What's the easiest workaround to style individual letters today without ::nth-letter?
The most straightforward workaround is to wrap each letter in a <span> element manually in your HTML or via JavaScript. For static content, you can write the spans directly; for dynamic content, use JS to split the text and create spans. Then you can use CSS nth-child selectors or custom properties to style each span. For example, to recreate the alternating skew effect from Chris Coyier's mockup, you'd do: <h1 class="fancy"><span>H</span><span>e</span>...</h1> and then h1.fancy span:nth-child(even) { transform: skewY(15deg); }. This works in all browsers and gives full control. The downside is that it pollutes the markup and can break text selection if you're not careful (you need to preserve the original text order). For a more semantic approach, you can use CSS custom properties and JavaScript to assign inline styles, but the span-based method remains the simplest and most compatible solution.
Will we ever get ::nth-letter in CSS? Are there any proposals?
As of 2026, there is no active proposal for ::nth-letter in the CSS Working Group. The closest development is the CSS Parser API, which would theoretically allow custom selectors, but its specification hasn't moved forward. Some new CSS features like text-wrap: pretty or initial-letter address typographic needs, but not letter-level styling. However, the idea has been revived in discussions about Houdini, a set of low-level APIs that let developers extend CSS. The CSS Typed OM and Custom Properties could enable advanced letter animations, but not a simple pseudo-element. Given the complexity, it's unlikely that ::nth-letter will become a standard in the near future. Instead, we'll probably see more high-level typography features that reduce the need for per-letter styling. Until then, developers will continue to rely on JavaScript workarounds or the old-fashioned span method.
Does using ::nth-letter workarounds cause accessibility problems?
Yes, many workarounds for ::nth-letter can harm accessibility if not implemented carefully. When you split text into individual <span> elements, screen readers may read each letter separately instead of as a word, especially if you use ARIA roles incorrectly. For example, a heading broken into spans might be announced as “H” then “E” then “L” instead of “HELLO”. To fix this, you can wrap the entire content in a <span> with aria-label or use role="text" on a container to ensure the screen reader treats the spans as inline. Additionally, keyboard navigation and text selection can break if spans are not properly contained. When using JavaScript-based splitting, test with screen readers and ensure that the visual effect does not interfere with readability. Simpler is often better: use CSS effects that don't require per-letter markup, like background-clip: text for gradient letters or filter for overall text treatment.