
CSS initial-letter: Creating Drop Caps the Modern Way
- Maria
- Typography
- 23 Oct, 2026
If you've ever built a drop cap in CSS, you know the routine. Float the first letter, set its font-size to something like 4.2em, nudge the line-height down, add a negative margin, and then adjust everything again when you change the body font. The result looks right in one browser and sits a few pixels too low in another. Change the line height of the paragraph and the whole thing falls apart.
The initial-letter property replaces that guesswork. You tell the browser how many lines the letter should span, and it calculates the size and position so the top of the letter lines up with the cap height of the first line and its baseline sits on a line of body text.
This guide covers the syntax, the difference between dropped and raised caps, styling tips, a fallback for browsers without support, and the accessibility details that are easy to get wrong.
What a Drop Cap Is
A drop cap is an enlarged first letter that sinks into the paragraph, spanning several lines of text. It's one of the oldest devices in typography, going back to illuminated manuscripts, and it still appears at the start of chapters, magazine features, and long-form articles.
There are a few variations:
- Dropped initial: the letter sinks down into the paragraph, and its top aligns with the top of the first line.
- Raised initial: the letter sits on the first line's baseline and rises above the paragraph.
- Sunken-raised initial: a mix, where the letter sinks a few lines but also rises above the top of the text.
What makes a drop cap look professional is alignment. The top of the letter should line up with the cap height of the first line, and its baseline should land exactly on the baseline of a later line. That's the bit floats never got quite right, because they don't know anything about font metrics.
The initial-letter Syntax
initial-letter applies to the ::first-letter pseudo-element (or to an inline element at the start of a block). It takes one or two values:
p.intro::first-letter {
initial-letter: 3;
}
The first value is the size: how many lines tall the letter should be. The second, optional value is the sink: how many lines the letter should drop into the paragraph. If you leave out the sink, it equals the size, which gives you a classic dropped initial.
| Declaration | Size | Sink | Result |
|---|---|---|---|
initial-letter: 3 | 3 lines | 3 lines | Classic drop cap spanning three lines |
initial-letter: 3 2 | 3 lines | 2 lines | Sinks two lines and rises above the first line |
initial-letter: 3 1 | 3 lines | 1 line | Raised cap sitting on the first baseline |
initial-letter: 2.5 2 | 2.5 lines | 2 lines | Fractional size, sinks two lines |
initial-letter: normal | none | none | No special treatment (the default) |
The size can be a decimal, but the sink must be a whole number of lines, since it determines which baseline the letter lands on.
The specification also allows the keywords drop and raise in place of the sink number. drop matches the sink to the size, and raise uses a sink of 1. Browser support for the keywords is thinner than for numbers, so numbers are the safer choice.
How the Browser Sizes the Letter
You don't set font-size yourself. The browser works out the font size needed for the letter's cap height to span the requested number of lines, using the paragraph's line height and the font's metrics. If you change the paragraph's line-height or font-size, the drop cap scales to match automatically.
That's the main reason to prefer initial-letter over a float. It's tied to the text around it, so it stays aligned when the type changes.
A Complete Example
<article class="feature">
<p class="feature__lede">
Long before the printing press, scribes marked the beginning of a text with
an oversized letter. The habit stuck. Today's editors still use drop caps to
signal that a story starts here, and to give the reader's eye a clear point
of entry into a dense page.
</p>
<p>The rest of the article continues in normal paragraphs.</p>
</article>
.feature__lede {
font-family: "Source Serif 4", Georgia, serif;
font-size: 1.125rem;
line-height: 1.6;
}
.feature__lede::first-letter {
initial-letter: 3;
font-weight: 700;
color: #b4532a;
margin-inline-end: 0.5rem;
}
The margin-inline-end adds space between the letter and the text that wraps around it. Without it, the body text can crowd right up against the initial. A value around a third to half an em of body text usually looks right.
Raised and Sunken-Raised Initials
A sink smaller than the size raises the letter above the paragraph. This is common in magazine design, where a big initial creates a strong visual anchor without eating too many lines of text.
/* Raised: three lines tall, sitting on the first baseline */
.raised::first-letter {
initial-letter: 3 1;
}
/* Sunken-raised: four lines tall, dropped two lines */
.sunken-raised::first-letter {
initial-letter: 4 2;
}
Raised initials need room above the paragraph, so check that the space above the first line (a heading's margin, for example) doesn't collide with the top of the letter.
Styling the Initial
Only some properties apply to ::first-letter. The useful ones are font properties, color, background, margin, padding, border, and text decoration. That's enough for most drop cap designs.
Using a Different Typeface
Drop caps are a good place to use a decorative or display face, since you're only showing one character:
.feature__lede::first-letter {
initial-letter: 3;
font-family: "Playfair Display", Georgia, serif;
font-weight: 900;
color: #1d3557;
margin-inline-end: 0.4rem;
}
Keep in mind that the browser aligns the letter using the cap height of the font you choose. A display face with an unusual cap height will still align correctly, which is another win over hand-tuned floats. For guidance on choosing such faces, see Display Typefaces: Making Headlines Without Sacrificing Clarity.
Boxed Initials
You can put the letter inside a colored box using background and padding:
.boxed::first-letter {
initial-letter: 3;
background: #1d3557;
color: #f1faee;
padding: 0.25rem 0.6rem;
margin-inline-end: 0.6rem;
font-weight: 700;
}
Padding is added around the letter, so you may need to tweak the values until the box sits nicely within the three lines.
Matching the First Line
A common editorial touch is to set the rest of the first line in small caps after the initial:
.feature__lede::first-line {
font-variant-caps: small-caps;
letter-spacing: 0.05em;
}
This works with any approach to the drop cap. If you go this route, read Small Caps: When to Use Them and How to Set Them Properly to make sure your font has real small caps.
Punctuation and ::first-letter
If a paragraph starts with an opening quotation mark, ::first-letter includes that punctuation together with the first letter. The quote mark gets enlarged as well. Sometimes that's what you want, but often it looks heavy.
There's no clean CSS-only fix. Options include:
- Rewrite the opening sentence so it doesn't start with a quote.
- Let the quote mark be enlarged, and choose a typeface whose quotes look good at large size.
- Wrap the first letter in an element and apply
initial-letterto that element instead of using::first-letter.
The third option looks like this:
<p class="quote-lede">
“<span class="initial">T</span>he archive was never meant to be
public,” the curator explained.
</p>
.quote-lede .initial {
initial-letter: 3;
}
initial-letter applies to an inline element if it's the first thing in the block, possibly after punctuation. Be aware this has accessibility consequences, described below.
Accessibility Considerations
Drop caps are decorative, so they should never change what assistive technology reads.
Using ::first-letter is the safest approach. The text in the HTML remains a normal word, and screen readers announce it normally.
Wrapping the letter in a <span> is usually fine too, since inline elements don't normally split a word when read aloud. Avoid these older techniques, though:
- Removing the letter from the text and rendering it with an image or a pseudo-element's
content. The word becomes "ong before" for screen readers and search engines. - Using a separate block element for the letter, which some screen readers can announce as a separate item.
Also check color contrast. A drop cap in a light accent color is still text, and it should meet the same contrast requirements as other large text.
A Fallback for Unsupported Browsers
Support for initial-letter is uneven. Safari has supported it for years with the -webkit- prefix, and Chromium-based browsers support the unprefixed property. Firefox support has lagged, so check caniuse for the current state before you rely on it.
A practical approach is to write a float-based fallback first and then replace it inside @supports:
/* Fallback: float the letter */
.feature__lede::first-letter {
float: left;
font-size: 4.1em;
line-height: 0.85;
margin: 0.05em 0.1em 0 0;
font-weight: 700;
color: #b4532a;
}
/* Modern browsers: let initial-letter handle size and alignment */
@supports (initial-letter: 3) or (-webkit-initial-letter: 3) {
.feature__lede::first-letter {
float: none;
font-size: inherit;
line-height: inherit;
margin: 0 0.5rem 0 0;
-webkit-initial-letter: 3;
initial-letter: 3;
}
}
The fallback numbers are tuned for a specific font and line height, so you'll need to adjust them for yours. The goal is simply a decent drop cap in browsers that need it, not pixel-perfect alignment.
If maintaining two versions feels like too much work, it's also reasonable to show no drop cap at all in unsupported browsers. A drop cap is decoration, and plain text is a perfectly good fallback:
@supports (initial-letter: 3) {
.feature__lede::first-letter {
initial-letter: 3;
margin-inline-end: 0.5rem;
}
}
Design Guidelines
Some rules of thumb for drop caps that look intentional:
- Use one per article, or one per major section. Drop caps mark beginnings. If every paragraph has one, they stop meaning anything.
- Make the first paragraph long enough. A drop cap spanning three lines needs at least four lines of text to wrap around it, or the shape looks broken.
- Be careful on narrow screens. On mobile, a three-line drop cap takes up a large share of the width. Consider
initial-letter: 2on small screens, or turn the effect off. - Pick letters that work. Letters like "A", "L", "T", and "W" leave awkward gaps next to the text because of their shape. You can't always choose the first letter, but if you're writing the copy, it's worth noticing.
- Keep it on the text grid. One reason to use
initial-letteris that it lands on a baseline. If your layout uses a baseline grid, the sibling guide on vertical rhythm explains how that fits together.
A responsive version might look like this:
.feature__lede::first-letter {
initial-letter: 2;
margin-inline-end: 0.4rem;
}
@media (min-width: 48rem) {
.feature__lede::first-letter {
initial-letter: 3;
margin-inline-end: 0.5rem;
}
}
Common Mistakes
- Setting
font-sizealongsideinitial-letter, then wondering why it has no effect. The browser calculates the size for you. - Forgetting the
-webkit-prefix, which leaves Safari users without a drop cap. - Leaving no space after the letter, so body text butts up against the initial.
- Using drop caps on short paragraphs, where there aren't enough lines to wrap around the letter.
- Removing the first letter from the text and drawing it with an image or generated content, which breaks the word for screen readers.
- Ignoring opening punctuation, which gets enlarged along with the letter by
::first-letter.
Conclusion
initial-letter turns drop caps from a pile of hand-tuned numbers into one declaration. Give it a size in lines, optionally a sink, and the browser handles the font size and alignment based on your paragraph's real metrics. Combine it with ::first-letter, a little margin-inline-end, and an accent color or display face, and you have a drop cap that stays aligned when the type changes.
Because support isn't universal yet, wrap it in @supports and decide whether unsupported browsers get a float fallback or plain text. Either way, keep drop caps for real beginnings, and they'll do what they've done for centuries: tell readers exactly where the story starts.


