CSSwriting-mode & text-orientation

writing-mode & text-orientation

writing-mode controls the direction in which text lines are laid out — horizontally (the default in Latin scripts) or vertically (used in CJK scripts like Japanese and Traditional Chinese). text-orientation controls how individual characters are rotated within a vertical line. These properties are also used creatively in web design to create sideways text labels for vertical tabs and rotated headings.

writing-mode

CSS
/* Horizontal (default) — text flows left-to-right, lines stack top-to-bottom */
writing-mode: horizontal-tb;   /* horizontal, top-to-bottom block direction */

/* Vertical — text flows top-to-bottom, lines stack right-to-left */
writing-mode: vertical-rl;     /* vertical, right-to-left line progression */

/* Vertical — text flows top-to-bottom, lines stack left-to-right */
writing-mode: vertical-lr;     /* vertical, left-to-right line progression */

/* Sideways — same as vertical-rl but all glyphs are rotated upright */
writing-mode: sideways-rl;
writing-mode: sideways-lr;
text-orientation

CSS
/* text-orientation only applies in vertical writing modes */

text-orientation: mixed;      /* default — upright CJK, rotated Latin */
text-orientation: upright;    /* all characters upright, even Latin letters */
text-orientation: sideways;   /* all characters rotated 90deg */

/* mixed is the correct default for Japanese text —
   kanji sit upright, Latin letters rotate 90deg to read normally */
Sideways tab labels — a practical use case

writing-mode is frequently used in CSS for rotated tab labels, sidebar headings, and vertical text annotations. The key insight is that width and height swap their block/inline role:

CSS
/* Vertical tab label — text reads bottom-to-top */
.tab-label {
  writing-mode: vertical-rl;
  transform: rotate(180deg);  /* flip so text reads bottom-to-top instead of top-to-bottom */
  white-space: nowrap;         /* prevent the vertical text from wrapping */
}

/* Left-aligned sidebar section title */
.sidebar-title {
  writing-mode: vertical-lr;
  text-orientation: mixed;
}

/* Decorative vertical headline */
.vertical-hero-text {
  writing-mode: vertical-rl;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  font-size: 0.75rem;
}

/* Note: in vertical writing mode, width and height swap
   A 100px height becomes the inline (text-flow) dimension
   A 200px width becomes the block dimension */
In vertical writing mode, width becomes the block axis and height becomes the inline axis — logical properties (block-size, inline-size) are safer to use
When you apply `writing-mode: vertical-rl` to an element, what was previously the horizontal direction is now the block direction, and vertical is the inline direction. Physical properties like `width` and `height` work fine but can be confusing. Logical properties — `block-size` (equivalent to height in horizontal, width in vertical) and `inline-size` (width in horizontal, height in vertical) — stay meaningful regardless of writing mode.
CJK vertical text

CSS
/* Traditional Japanese/Chinese vertical text */
.japanese-article {
  writing-mode: vertical-rl;
  /* Japanese flows right-to-left, top-to-bottom */
}

.japanese-article p {
  text-orientation: mixed;  /* kanji upright, Latin rotated */
}

/* Punctuation that should be upright */
/* Japanese fullwidth punctuation is automatically handled by the browser */

/* For primarily Latin text read vertically */
.rotated-english {
  writing-mode: vertical-lr;
  text-orientation: sideways; /* rotate all characters consistently */
}

/* Or use transform rotate as an alternative for purely decorative text */
.rotated-label {
  transform: rotate(-90deg);   /* visually rotated but still horizontal mode */
  white-space: nowrap;
}
Logical properties and writing mode

CSS logical properties automatically adapt to the writing mode, making them essential for truly internationalised layouts:

CSS
/* Physical properties — don't adapt to writing mode */
p { margin-top: 1em; padding-left: 1rem; }

/* Logical properties — adapt to writing mode */
p {
  margin-block-start: 1em;    /* 'before' the text flow direction */
  padding-inline-start: 1rem; /* 'start' of the inline direction */
}

/* In horizontal-tb: block-start = top, inline-start = left
   In vertical-rl:  block-start = right, inline-start = top
   In RTL Arabic:   block-start = top, inline-start = right */
Next
Single font files that contain entire type families — how variable fonts work and how to use them: [Variable Fonts](/css/variable-fonts).