CSS writing-mode Browser Support and Cross-Browser Fixes
Learn how writing-mode support varies across browsers, choose the right vertical text values, and build readable fallbacks for older browsers.
writing-mode is broadly supported in current browsers. For most projects, use horizontal-tb, vertical-rl, or vertical-lr directly, and test the exact browser versions and text you support. Check sideways-* values and legacy browsers separately: support for the property overall does not guarantee that every value or glyph combination renders the same way.
When a less common value is unsupported, keep a readable baseline and enable the enhanced layout with @supports. Use text-orientation to change glyph direction inside vertical lines. A transform can imitate a limited rotation effect, but it does not reproduce writing-mode flow and can position glyphs unexpectedly.
What writing-mode controls
writing-mode sets whether lines run horizontally or vertically and controls the direction of block flow. It affects how blocks are ordered, so it is a layout property as well as a text-orientation choice. For a document-wide mode, set it on the root html element. [MDN: writing-mode]
| Value | Line direction and block flow | Typical use |
|---|---|---|
horizontal-tb |
Horizontal lines; blocks flow top to bottom | Default horizontal page layout |
vertical-rl |
Vertical lines; blocks progress right to left | Vertical layout where columns advance from the right |
vertical-lr |
Vertical lines; blocks progress left to right | Vertical layout where columns advance from the left |
sideways-rl |
Sideways line orientation with right-to-left block flow | Specialized sideways text; check support in target browsers |
sideways-lr |
Sideways line orientation with left-to-right block flow | Specialized sideways text; check support in target browsers |
The writing mode works with direction and text-orientation. For scripts such as Chinese, Japanese, and Korean, vertical writing is a real layout mode. Choose the block progression first; do not treat the property as a generic text-rotation switch. [MDN: CSS writing modes]
Browser support: check the exact value
MDN describes writing-mode as widely available across browsers since March 2017, while noting that support varies for parts of the syntax. Can I Use reports 97.26% global usage for the general property in its August 2026 snapshot. Its separate vertical-rl table reports 96.84%, with support from Chrome 48, Firefox 43, and Safari 9; IE 6–11 are listed as unsupported for that value. These are global estimates, not a guarantee for your users. [MDN; Can I Use: writing-mode; Can I Use: vertical-rl]
text-orientation has separate compatibility data: Can I Use reports 96.2% in the August 2026 snapshot and lists support from Chrome 48, Firefox 41, and Safari 10.1; IE 11 is unsupported. Do not extrapolate vertical-rl support to sideways-rl, sideways-lr, text orientation combinations, embedded web views, or a particular operating system. Check the exact combination that matters. [Can I Use: text-orientation]
The usage shares above are snapshots credited to StatCounter GlobalStats by Can I Use. Use your own site’s audience and browser requirements to decide whether a legacy fallback is necessary.
Choose text-orientation separately
text-orientation controls character orientation within a line and only takes effect when the writing mode is vertical. Its standard values include mixed, upright, and sideways. If columns flow correctly but characters face the wrong direction, adjust this property rather than changing the broader writing mode. [MDN: text-orientation]
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Vertical writing example</title>
<style>
.vertical-label {
writing-mode: vertical-rl;
text-orientation: mixed;
border-inline-start: 2px solid currentColor;
padding-inline-start: 0.75rem;
min-block-size: 12rem;
}
</style>
</head>
<body>
<p class="vertical-label">Vertical layout with mixed character orientation</p>
</body>
</html>
Use logical properties such as border-inline-start, padding-inline-start, and min-block-size when the component should adapt to writing direction. Physical properties such as left, right, width, and height still have uses, but may encode assumptions that do not hold after the writing mode changes.
Build a cross-browser fallback with @supports
Start with content that remains readable in the baseline layout, then apply the less common value only when the browser recognizes it. Feature queries test whether a declaration is supported; they do not verify that the final layout looks right for every font, script, or browser version.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Sideways writing with a readable fallback</title>
<style>
.label {
/* Baseline remains readable when sideways-lr is unavailable. */
writing-mode: horizontal-tb;
display: inline-block;
max-inline-size: 18rem;
}
.unsupported-note { display: block; }
@supports (writing-mode: sideways-lr) {
.label {
writing-mode: sideways-lr;
max-inline-size: none;
}
.unsupported-note { display: none; }
}
</style>
</head>
<body>
<p class="label">A label that can use sideways text when supported.</p>
<p class="unsupported-note">This browser shows the label horizontally.</p>
</body>
</html>
This follows MDN’s feature-query approach for an unsupported sideways value. Keep the fallback useful: readable horizontal text is often safer than a visual imitation that overlaps or clips. [MDN: writing-mode examples]
When a transform workaround is appropriate
A transform rotates the rendered box; it does not change the browser’s block-flow model. MDN describes a 180-degree rotation as one possible workaround for a narrow sideways-lr case, and warns that glyphs may not be designed to rotate, causing unexpected positioning or rendering. [MDN: writing-mode]
.rotated-fallback {
display: inline-block;
transform: rotate(180deg);
transform-origin: center;
}
Use this only when the intended effect is a rotation of a compact element and you can validate its dimensions and surroundings. It is not a general replacement for vertical writing. Rotated elements can still occupy their unrotated layout box, so surrounding content may need explicit sizing or positioning. Test the actual font and characters, including mixed scripts, before relying on it.
Validation checklist
- Identify the exact failing value:
vertical-rl,vertical-lr, or a particularsideways-*value. - List target browser families and versions, including embedded web views if relevant. Compare the exact feature table rather than the property’s general support figure.
- Check whether the issue is block progression, glyph orientation, font coverage, sizing, or clipping. Change
writing-modefor flow andtext-orientationfor glyph direction. - Keep a readable baseline and use
@supportsfor optional syntax. - Test real text in the fonts and scripts the page uses, at narrow and wide viewports, and with surrounding content.
- If using a transform, inspect the element’s visual position and occupied layout space in each target browser.
When validating screenshots across browsers, capture the same URL, viewport, and state in each environment so differences are easier to compare. ScreenshotNeo is a website screenshot API and MCP server for developers; its API can capture pages, and the product’s options include device presets and custom viewport settings. See the ScreenshotNeo site and API documentation.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
writing-mode appears ignored |
The browser/version does not support the exact value, or a later rule overrides it. | Inspect computed styles, confirm the exact value in compatibility data, and provide a baseline plus an @supports enhancement. |
| Columns progress in the wrong direction | vertical-rl and vertical-lr differ in block progression. |
Choose the value that matches the intended column order; check direction where inline direction also matters. |
| Characters rotate or appear upright unexpectedly | text-orientation controls glyph orientation only in vertical writing. |
Set an explicit orientation such as mixed, upright, or sideways, then test the scripts and font in use. |
| A sideways value works in one browser but not another | Support is value-specific and not uniform for all sideways-* syntax. |
Use @supports (writing-mode: sideways-lr) (or the exact value) and retain a useful baseline. |
| Rotated fallback overlaps or looks misaligned | A transform changes visual rendering but does not reproduce writing-mode flow; glyph metrics may not suit rotation. | Prefer readable unrotated text, or tune the compact element’s size and origin and verify it across target browsers. |
| Layout breaks after switching writing mode | Styles may assume physical dimensions or edges. | Review physical sizing and positioning; use logical properties where the component should follow inline and block axes. |
Performance, reliability, and maintenance
Writing mode is a CSS layout choice; the practical work is validating the resulting layout, fonts, and fallbacks across the browsers you support. Keep the fallback simple, scope enhanced rules to the component, and avoid using transforms to simulate a full alternate flow. Recheck compatibility data when changing target-browser policy because browser support and usage estimates can change.
For reproducible visual checks, hold the URL, viewport, content, and page state constant. If a page uses delayed content, consent prompts, or other overlays, account for that state when comparing captures; otherwise an apparent CSS difference may come from different page content.
Or skip the browser setup
To capture a page for visual comparison without configuring a browser automation stack, make one request to ScreenshotNeo. The API returns an image or PDF for a URL; see the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Every feature is on every plan.
Sign up for ScreenshotNeo and get 1,000 free screenshots a month with no card.
FAQ
Should I set writing-mode on html?
For a document-wide writing mode, MDN recommends setting it on the root html element. For a single label or component, scope it to that element instead.
Does @supports prove that the layout renders correctly?
No. It checks whether the browser recognizes the declaration. You still need visual checks for the target fonts, scripts, browser versions, and surrounding layout.
Can I use writing-mode just to rotate a heading?
You can, but choose it when vertical flow is desired. For a simple visual rotation, a transform may fit; it has different layout behavior and should be checked for positioning and clipping.
Are global support percentages enough to drop a fallback?
No. They summarize global usage for a stated snapshot. Decide from your own audience, required browser versions, and the consequences of an unreadable or missing enhancement.


