
What is hanging punctuation and how do you use it in CSS?
- Sajjad
- Typography
- 11 Oct, 2026
Hanging punctuation is the practice of placing certain punctuation marks, most often opening quotation marks, just outside the edge of a text block, so the letters themselves line up and the left edge looks straight. Without it, a paragraph that starts with a quotation mark appears indented by the width of that mark, because your eye aligns letters rather than punctuation. CSS has a property for this, hanging-punctuation, with values such as first, last and allow-end. At the time of writing only Safari supports it, so for other browsers you use fallbacks such as a negative text-indent on quoted paragraphs and outside-positioned list markers. Used together, these give you the optical alignment that print designers have relied on for centuries.
It's a small detail, but it's one of the clearest differences between text that has been set with care and text that hasn't. Pull quotes, blockquotes and testimonials are the most visible places, because they so often begin with a large quotation mark. In this article you'll learn why hanging punctuation improves alignment, what each value of the CSS property does, how to use it safely given its limited support, how to build reliable fallbacks for quotes and lists, and where hanging punctuation shouldn't be used.
Why Punctuation Should Hang
Text alignment is judged by eye, not by measurement. A left-aligned column looks straight when the vertical strokes of its letters form a clean line. Punctuation marks like “, ', ( and - are light and mostly empty space, so when one sits at the very start of a line it creates a visual notch. The first letter is pushed in, and the column looks slightly broken at that point.
Compare these two ways of setting the same quote:
Without hanging punctuation:
|“Good typography is invisible,” she said.
|It should never draw attention to itself.
With hanging punctuation:
“Good typography is invisible,” she said.
It should never draw attention to itself.
In the second version the quotation mark sits outside the margin, and the G lines up with the I below it. Typesetting software such as InDesign does this with optical margin alignment, which can also nudge hyphens, commas and even the rounded edges of letters slightly past the margin. CSS offers a simpler version focused on punctuation.
Which Marks Usually Hang
- Opening quotation marks: Single and double,
‘and“, at the start of a line. - Closing quotation marks and full stops: At the end of a line in justified or right-aligned text.
- Bullets and list markers: So the text of list items lines up with surrounding paragraphs.
- Hyphens and dashes: At line ends in justified text, in high-end print work.
On the web, the first and third are by far the most important.
The hanging-punctuation Property
The hanging-punctuation property is defined in the CSS Text Module Level 3. It accepts none (the default) or a combination of these keywords:
first: An opening bracket or quotation mark at the start of the first line of the element hangs outside the start edge.last: A closing bracket or quotation mark at the end of the last line hangs outside the end edge.allow-end: A full stop or comma at the end of a line may hang if it doesn't otherwise fit.force-end: A full stop or comma at the end of a line always hangs.
You can combine first, last and one of the two end values:
blockquote {
hanging-punctuation: first last;
}
.prose p {
hanging-punctuation: first allow-end last;
}
Hanging glyphs are not counted when the browser measures the line, so they sit in the padding or margin of the element. That means the element needs space outside its content box for the marks to hang into, or they can be clipped by overflow: hidden on a parent.
Browser Support
At the time of writing, Safari on macOS and iOS is the only major browser that supports hanging-punctuation. Chrome, Edge and Firefox ignore it. That makes it a safe progressive enhancement: it improves the result in Safari and does nothing anywhere else. It also means you need a fallback if hanging quotes matter to your design.
You can detect support with @supports:
@supports (hanging-punctuation: first) {
blockquote {
hanging-punctuation: first last;
}
}
@supports not (hanging-punctuation: first) {
/* fallback styles go here */
}
Fallback for Quotes: Negative Text Indent
The most common use for hanging punctuation is a blockquote or pull quote that begins with an opening quotation mark. A negative text-indent pulls the first line out by the width of the mark:
<blockquote class="hang-quote">
<p>“Typography exists to honour content.”</p>
</blockquote>
.hang-quote p:first-child {
text-indent: -0.45em;
}
@supports (hanging-punctuation: first) {
.hang-quote p:first-child {
text-indent: 0;
hanging-punctuation: first;
}
}
The exact width depends on the font and on whether you use a single or double mark, so -0.45em is a starting point rather than a rule. Most double opening quotes in common text fonts are somewhere between about 0.3em and 0.5em wide. Inspect the result at a large size and adjust until the first letter lines up with the line below.
Because text-indent affects only the first line, the rest of the paragraph stays aligned. The @supports block switches Safari to the native property so the indent isn't applied twice.
Only Apply It When the Text Starts With a Mark
CSS can't detect whether a paragraph starts with a quotation mark, so the class approach above needs the author or the template to add it. If your quotes are generated from structured content, it's more reliable to add the marks with CSS, so you know they're always there:
<blockquote class="pull-quote">
<p>Typography exists to honour content.</p>
</blockquote>
.pull-quote {
quotes: "“" "”" "‘" "’";
position: relative;
}
.pull-quote p::before {
content: open-quote;
position: absolute;
inset-inline-end: 100%;
}
.pull-quote p::after {
content: close-quote;
}
The quotes property defines which characters open-quote and close-quote produce, and positioning the opening mark at inset-inline-end: 100% places it entirely outside the start edge of the paragraph. This works in every browser and hangs the mark exactly, whatever font you use. Make sure the blockquote has enough padding or margin on the start side for the mark to sit in.
If the page language changes, you can set locale-specific quotes:
:lang(fr) .pull-quote {
quotes: "« " " »";
}
:lang(de) .pull-quote {
quotes: "„" "“";
}
A Decorative Oversized Mark
Many pull quotes use a large decorative quotation mark. Hang it in the same way, sized relative to the text:
.feature-quote {
position: relative;
font-size: 1.5rem;
line-height: 1.35;
margin-inline: 2rem 0;
}
.feature-quote::before {
content: "“";
position: absolute;
inset-inline-end: calc(100% + 0.1em);
inset-block-start: -0.15em;
font-size: 3em;
line-height: 1;
color: var(--accent, currentColor);
}
Because the mark is decorative and generated by CSS, some screen readers may announce it. If you want it purely visual, the content property accepts alternative text after a slash, which current browsers support: content: "“" / ""; gives the mark an empty accessible name.
Hanging List Markers
Bullets and numbers are a form of punctuation too. By default, browsers place list markers outside the list item's text and indent the whole list with padding, so the text of each item sits further in than surrounding paragraphs. If you want list text to line up with the paragraphs above, remove the padding and let the markers hang into the margin:
.prose ul,
.prose ol {
padding-inline-start: 0;
list-style-position: outside;
}
.prose li {
margin-inline-start: 0;
}
Now the markers sit outside the text column and every line of text, in paragraphs and lists, starts at the same edge. This only works if there's space for the markers to hang into, so check it on small screens where the content may sit close to the edge of the viewport. A safe pattern is to give the main content column some padding that markers and hanging quotes can use:
.prose {
max-width: 65ch;
padding-inline: max(1rem, 4vw);
margin-inline: auto;
}
For a deeper look at list markers, spacing and custom bullets, see how to style lists for better readability.
Where Not to Hang Punctuation
Hanging punctuation is about optical alignment, so it only helps where alignment is visible.
- Centred text: There's no straight edge to align to. Leave punctuation inside the line.
- Small interface text: Buttons, labels and menu items rarely start with a quotation mark, and hanging a mark in a tight component can clip it.
- Containers with overflow hidden: Cards and carousels often clip anything outside their box. Either add padding inside the container or don't hang.
- Code: Monospaced code relies on every character occupying exactly one column. Never apply hanging punctuation or negative indents to
preorcode. - Right-to-left text: The marks and edges are reversed. Logical properties such as
inset-inline-endandtext-indentfollow the writing direction, but test with real content.
Checking the Result
Hanging punctuation is easiest to judge at large sizes. Temporarily increase the font size of a quote and add a guide line at the content edge:
.debug-edge {
box-shadow: inset 1px 0 0 red;
}
document.querySelectorAll("blockquote").forEach((el) => {
el.classList.add("debug-edge");
el.style.fontSize = "3rem";
});
The red line marks the start of the content box. The quotation mark should sit to the left of it and the first letter should touch it, just like the first letter of the next line. Remove the debug styles when you're done.
FAQ: Hanging Punctuation
At the time of writing, only Safari on macOS and iOS supports it. Chrome, Edge and Firefox ignore the property, so use it as a progressive enhancement with a fallback for other browsers.
It makes an opening bracket or quotation mark at the start of the element's first line sit outside the start edge, so the first letter lines up with the lines below it.
Use a negative text-indent on the first line of quoted paragraphs, or generate the opening mark with a pseudo-element and position it absolutely just outside the start edge. Both approaches work in every current browser.
Hanging marks sit outside the element's content box. If a parent has overflow hidden or no padding on that side, the marks are clipped. Add padding or margin on the start side to give them space.
In long-form content, hanging bullets keep list text aligned with surrounding paragraphs, which looks tidier. In interfaces and narrow containers, indented lists are often clearer and safer.
For blockquotes, pull quotes and testimonials, yes, because the misalignment is obvious at large sizes. For ordinary paragraphs it's a refinement you can add cheaply with the native property for Safari users.
Conclusion
Hanging punctuation places quotation marks, brackets and list markers just outside the edge of a text block so that the letters line up and the edge looks straight. CSS supports it natively through hanging-punctuation, with first, last, allow-end and force-end controlling which marks hang, but only Safari implements the property today.
Use the native property as a progressive enhancement, and give other browsers a reliable fallback: a negative text-indent for quoted paragraphs, pseudo-element quotes positioned outside the box for pull quotes, and outside list markers with the list padding removed. Leave room for hanging marks to sit in, keep them away from centred text, small components and code, and check the alignment at a large size before you ship.


