How to Use Vertical Text Orientation in CSS Across Browsers
Use writing-mode to create vertical text and text-orientation to control glyphs. Learn the browser, script, and bidi details that make the result consistent.
To make text flow vertically, set writing-mode; to control how characters sit within that vertical line, set text-orientation. A common starting point is writing-mode: vertical-rl with text-orientation: mixed. The first property controls line flow and column progression; the second controls glyph orientation. text-orientation by itself does not create vertical flow.
For example, Japanese text can remain upright while Latin characters in the same line turn sideways:
<style>
.vertical-copy {
writing-mode: vertical-rl;
text-orientation: mixed;
}
</style>
<p class="vertical-copy">縦書き ABC 123</p>
Use vertical-lr instead when columns should progress left to right. Check the actual scripts and punctuation in your target browsers; consistent CSS does not guarantee identical font glyphs or composition everywhere.
1. Understand flow and character orientation
writing-mode determines whether lines are horizontal or vertical and the direction in which they flow. text-orientation determines the orientation of characters within a line and has an effect only in vertical typographic modes. The W3C specification describes it as the property that “specifies the orientation of text within a line.” (CSS Writing Modes Level 4.)
| Property | What it controls | Typical choice |
|---|---|---|
writing-mode |
Line orientation, flow direction, and column progression | vertical-rl or vertical-lr |
text-orientation |
Whether characters remain upright or rotate within a vertical line | mixed, upright, or sideways |
These properties also affect layout. Vertical writing changes block flow and ordering, so revisit dimensions, spacing, alignment, and any assumptions based on physical horizontal and vertical axes. Logical sizing and positioning properties are usually easier to adapt than physical ones.
2. Choose a writing mode and text orientation
Choose the column direction
/* Columns progress from right to left. */
.vertical-rl {
writing-mode: vertical-rl;
}
/* Columns progress from left to right. */
.vertical-lr {
writing-mode: vertical-lr;
}
These are the usual modes for vertical flow. Pick based on the reading and column progression you need, then check the resulting layout with real content. Writing modes describe the flow; they are not a visual rotation shortcut.
Choose how characters sit in each line
.vertical-mixed {
writing-mode: vertical-rl;
text-orientation: mixed;
}
.vertical-upright {
writing-mode: vertical-rl;
text-orientation: upright;
}
.vertical-sideways {
writing-mode: vertical-rl;
text-orientation: sideways;
}
| Value | Behavior in vertical text | Use when |
|---|---|---|
mixed |
Initial value. Characters with intrinsic vertical orientation stay upright; horizontal-script characters turn 90 degrees clockwise. | The content is primarily in a vertical script and horizontal-script runs should be rotated character by character. |
upright |
Horizontal-script characters remain upright. The specification also makes the used direction value ltr and treats characters as strong LTR for bidi reordering. |
You need every character upright and have accounted for its effect on RTL or mixed-direction content. |
sideways |
Text is laid out as horizontal text and rotated 90 degrees clockwise. | You want a horizontal text run turned sideways in vertical flow. |
For a Latin label running vertically, compare mixed, which can rotate individual characters, with sideways, which rotates a horizontally laid-out run. For CJK text, most characters have intrinsic vertical orientation and remain upright in mixed. Unicode vertical-orientation properties guide that behavior. Punctuation placement and alternate glyph forms can differ between horizontal and vertical composition, so inspect the actual font and text.
3. Handle RTL and mixed-direction content
Be especially careful with text-orientation: upright on Arabic, Hebrew, or mixed-direction content. Its specified LTR behavior affects bidi reordering. Verify the complete string, including punctuation, numbers, and embedded Latin text, in the context where it will appear.
Do not assume that changing direction alone will cancel this behavior. If correct RTL ordering is essential, test the target writing mode and orientation with representative content in each supported browser. Where the result is not suitable, consider isolating runs or choosing a different typographic treatment rather than applying a transform without checking reading order.
4. Build a reusable, layout-aware example
This example provides a vertical label and a vertical content area. It uses logical sizing for the label and demonstrates how to keep layout decisions separate from character orientation.
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Vertical text example</title>
<style>
.specimen {
display: flex;
gap: 1rem;
align-items: start;
font: 1rem/1.6 system-ui, sans-serif;
}
.specimen__label {
writing-mode: vertical-rl;
text-orientation: upright;
block-size: 12rem;
padding: 0.5rem;
border: 1px solid #888;
}
.specimen__copy {
writing-mode: vertical-rl;
text-orientation: mixed;
block-size: 12rem;
padding: 0.5rem;
border: 1px solid #888;
}
</style>
<div class="specimen">
<div class="specimen__label">SECTION 01</div>
<p class="specimen__copy">縦書きの例 ABC 123</p>
</div>
</html>
In vertical writing, logical dimensions such as block-size map to the flow-relative axis. A fixed block size can create wrapping or overflow depending on the content and container. Try the example with long text, narrow screens, zoom, and your production font; adjust dimensions and overflow behavior for the intended design.
5. Check browser support and fallbacks
MDN describes text-orientation as broadly available since September 2020 and writing-mode since March 2017, with some parts of writing-mode varying in support. Those dates do not guarantee support for every value in every browser version. Check the exact browsers and values your audience requires using the MDN text-orientation reference, MDN writing-mode reference, and a current Can I Use compatibility table. Compatibility data changes over time.
If a browser does not support the vertical treatment you need, decide whether a horizontal fallback is acceptable. Apply the vertical rules only where supported if your support policy calls for that, and ensure the fallback remains readable. Test the exact value rather than inferring support for sideways or another value from support for a basic vertical mode.
For unsupported sideways-lr, MDN describes a transform-based workaround and warns that rotation can cause unexpected positioning or rendering. For left-to-right scripts, vertical-rl can have the same effect as sideways-lr; in some situations a 180-degree rotation may suffice. These are limited workarounds, not drop-in equivalents: verify glyph shape, dimensions, wrapping, and alignment. See the MDN writing-mode documentation.
6. Verify the result across browsers
- Test every browser and version you must support, including any embedded webviews relevant to your audience.
- Use representative content: CJK characters, Latin words, digits, punctuation, and any RTL or mixed-direction strings the page displays.
- Check both
vertical-rlandvertical-lrif column progression is part of the design. - Inspect wrapping, line spacing, glyph orientation, punctuation, alignment, and clipping at different viewport sizes and zoom levels.
- Repeat with the production fonts loaded. Font fallback can change metrics and glyph appearance.
- Confirm that layout uses the intended logical or physical dimensions and that controls and reading order remain usable.
A screenshot comparison can help catch visual differences between browser renders. If you need a remote screenshot without setting up browser automation, ScreenshotNeo is a website screenshot API and MCP server for developers.
7. Troubleshooting
| Symptom | Likely cause | What to check or change |
|---|---|---|
| Text stays horizontal | text-orientation was set without a vertical writing mode, or the rule is overridden. |
Set writing-mode: vertical-rl or vertical-lr on the text element and inspect computed styles. |
| Latin characters rotate when they should be upright | text-orientation: mixed rotates horizontal-script characters. |
Try upright for upright characters or sideways for a rotated horizontal run; check the resulting spacing and bidi behavior. |
| RTL or mixed text appears in an unexpected order | upright applies specified LTR behavior for bidi reordering. |
Test the actual string and writing mode, then choose an approach that preserves the required reading order. |
| Columns progress in the wrong direction | The selected vertical writing mode has the opposite progression. | Switch between vertical-rl and vertical-lr. |
| Punctuation or CJK glyphs look different | Vertical composition can use different punctuation placement or glyph forms; fonts and browser rendering also vary. | Check the production font and target browsers with real strings, and allow enough space for the observed glyphs. |
| Rotated text overlaps or is misaligned | A transform changes visual orientation without automatically adapting layout dimensions and positioning. | Recheck the containing block, dimensions, alignment, and wrapping. Prefer native writing modes when their flow matches the design. |
| Text clips or wraps unexpectedly | Vertical flow changes which dimension constrains content; a fixed size may be on the wrong axis. | Review logical sizing, available space, and overflow with long content and narrow viewports. |
| One browser renders a value differently or ignores it | Support varies by browser, version, and specific value. | Check current compatibility data and test the exact required browser/value combination; provide a readable fallback. |
8. Or skip the browser setup
To capture a page for visual review without configuring browser automation, call the ScreenshotNeo API. See the ScreenshotNeo API documentation for request options.
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await (await import('node:fs/promises')).writeFile('shot.webp', image);
ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month.
9. Performance, reliability, and cost notes
For CSS rendering, the main practical costs are layout complexity and the work needed to verify the visual result across content and browsers. Keep the styles scoped to the intended component, avoid compensating transforms until you have checked native flow, and test with production fonts and representative text.
For screenshot capture, request only the output and page area needed for review. ScreenshotNeo bills only clean shots; its response headers identify the page verdict and billing status. Use those headers when accounting for captures, and consult the API documentation for configuration and response details. Available plans are Free (1,000 shots/month), Starter ($5 for 3,000), Growth ($15 for 15,000), Pro ($39 for 60,000), Scale ($99 for 250,000), and Business ($249 for 1,000,000); yearly billing gives two months free, and every feature is on every plan.
10. FAQ
Does text-orientation make text vertical by itself?
No. Set a vertical writing-mode to establish vertical flow; then choose a text-orientation value for the characters.
Which combination should I try first for vertical Japanese text with Latin runs?
Start with writing-mode: vertical-rl; text-orientation: mixed. Then inspect Latin runs and punctuation in your target browsers and font.
Will a CSS transform behave exactly like a vertical writing mode?
No. A transform rotates rendering and can leave sizing, positioning, and wrapping unsuitable. Use it only as a tested workaround for a specific need.
Can I assume a browser that supports writing-mode supports every orientation value?
No. Check the exact value and browser versions your audience needs; support can differ by feature and value.


