Command Palette

Search for a command to run...

Hectal
PHASE 6Intermediate ~29 min· topic 1 of 5

Topic 6.1

Normal Flow and Writing Modes

In one line

With no layout CSS, the browser places boxes in normal flow: block boxes stack one under another and fill the width, while inline content runs along lines and wraps; writing modes and logical properties decide which way "down" and "along" really point.

Think of it like this

Writing in a notebook. You write words along a line from left to right, and when the line is full you move down to the next one. A new paragraph always starts on a fresh line and uses the whole width of the page. Nobody tells you to do this; it is the default. A Japanese notebook can be written the other way: lines run top to bottom, and new lines are added from right to left. The rules are the same, only the directions change.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Normal flow
The browser's default layout: blocks stack, inline content runs along lines. Nothing floated or positioned.
Block-level box
A box that starts on a new line and, by default, fills the width of its parent, like <p> or <div>.
Inline-level box
A box that sits inside a line of text next to other content, like <span> or <a>.
Line box
One invisible row holding one line of inline content. Text wraps by starting a new line box.
Anonymous box
A box the browser creates by itself to wrap loose text, so it can be laid out. You can't select it.
Out of flow
A box that no longer takes up space among its siblings, like a float or an absolutely positioned box.
Writing mode
Which way lines of text run and which way new lines are added: horizontal or vertical.
Inline axis and block axis
The inline axis is the direction text runs along a line. The block axis is the direction blocks and lines stack.
Logical property
A property named by flow (start, end, inline, block) instead of by screen side (left, right, top, bottom).
`dir` attribute
An HTML attribute that sets the text direction of content: ltr (left to right) or rtl (right to left).

Step by step

01Blocks stack in the block direction

Write three <div>s with no CSS. Each starts on its own line and stretches across the whole width of its parent, even if its text is short. Give one a background colour and you'll see the colour run all the way to the right edge.

index.htmlwhole filehtml
<div>Short</div>
<div>A little longer</div>
<div>The longest of the three blocks</div>

02Inline boxes run along lines

Inside a paragraph, <span>, <a> and <strong> sit next to each other like words. Make the paragraph narrow and they wrap onto the next line. Setting width: 200px on a <span> does nothing, because an inline box's size comes from its content.

index.htmlwhole filehtml
<p>Buy <strong>fresh</strong> mangoes at <a href="#">the market</a> today.</p>

03See the boxes the browser makes

Here a <div> holds a line of loose text and then a <p>. The text can't sit next to a block, so the browser wraps it in an anonymous block box. Now the div's children are two blocks, stacked in normal flow.

See the boxes the browser makesdiagram
Rendering diagram…

04Turn the page sideways

Add writing-mode: vertical-rl to a box. Its text now runs downwards, and each new line appears to the left of the previous one. The box's width and height swap meaning: what grows with more lines is now the width.

style.csswhole filecss
.vertical {
  writing-mode: vertical-rl;
  block-size: 120px; /* in vertical text, this is the width */
}

05Write sides by flow, not by screen edge

A note with a coloured bar at the start of its lines uses border-inline-start. In an English page the bar is on the left; give the paragraph dir="rtl" and the bar moves to the right, with no extra CSS.

style.csswhole filecss
.note {
  border-inline-start: 4px solid teal;
  padding-inline-start: 8px;
  margin-block: 12px;    /* top and bottom in horizontal text */
}

06Map physical to logical

In horizontal, left-to-right text, the mapping is: width = inline-size, height = block-size, left = inline-start, right = inline-end, top = block-start, bottom = block-end. In other writing modes the same logical names map to different physical sides.

Map physical to logicaldiagram
Rendering diagram…

Try it yourself

  1. 1

    Make the inline box obey a width

    In the first example, add display: inline-block; to .tag. Predict what the console prints for span display and really 200px wide?, and how the spans look. (Now they are 200px wide and 80px tall, and each one sits on its own line because two don't fit in 260px.)

  2. 2

    Switch the vertical direction

    In the second example, change vertical-rl to vertical-lr. With one short line nothing seems to change. Now add more text to the vertical box until it wraps: with vertical-rl the second line appears on the left, with vertical-lr on the right.

  3. 3

    Swap a physical property for a logical one

    Add a third paragraph with dir="rtl" and style="margin-left: 24px". Predict which side gets the gap. (The left: physical properties don't follow the text direction. That's the bug logical properties prevent.)

Code & diagrams

Blocks stack and fill the width; inline boxes ignore width New tab

A starts 10px down (2px border + 8px padding); B starts 36px + 8px margin later. Block A is 260px wide although its text is short. The spans' `width` is ignored: `getComputedStyle` still reports the 200px you wrote, but the real rendered box (`offsetWidth`) is only as wide as its word.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

A top: 10 B top: 54
A width: 260
span display: inline
span computed width: 200px
really 200px wide? false
Writing modes and logical properties New tab

The same `inline-size: 160px` makes the first box 160 + 12 + 6 = 178px wide, but the vertical box 178px tall: in `vertical-rl`, the inline axis points down and `inline-start` is the top edge. In the `dir="rtl"` paragraph, every `inline-start` property lands on the right.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

horizontal: 178 x 48
vertical: 48 x 178
vertical border-top: 6px
rtl margin-left: 0px margin-right: 24px
rtl border-right: 4px
What decides a box's place in normal flowdiagram
Rendering diagram…

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Expect a span to take a width

Give a <span class="badge"> the rule .badge { width: 80px; height: 24px; background: gold; } to make a fixed-size pill.

terminal
$ the page shows
── what you'll see ──
The gold background hugs the text exactly. The span is no wider than its word. DevTools lists width: 80px in the Styles pane, but the box model diagram shows the much smaller real size.

Break #2

Hard-code left and right in a translated site

Style a quote with border-left: 4px solid teal; padding-left: 12px;, then the site is translated to Arabic and <html dir="rtl"> is set.

terminal
$ the page shows
── what you'll see ──
The text now starts on the right, but the teal bar and the padding stay on the left, at the end of the lines.

Myth vs fact

Myth

A <div> is as wide as its content.

Fact

A block box with width: auto fills the whole inline size of its parent, however short its content. To shrink it to its content, use width: fit-content or display: inline-block.

Myth

Logical properties are a niche feature for multilingual sites.

Fact

They work in every modern browser and cost nothing in English. Shorthands like margin-block and padding-inline are often shorter than writing two physical properties, and the site is ready if it is ever translated.

Myth

direction: rtl in CSS is the right way to make an Arabic page.

Fact

Direction is part of the content's meaning, so set it in HTML with dir="rtl" (on <html> or the element). That also helps search engines, screen readers and the browser's handling of mixed text.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Normal flow is built from formatting contexts. A block formatting context (BFC) lays out blocks vertically and is where vertical margins collapse; an inline formatting context lays out line boxes. New BFCs are created by floats, absolutely positioned boxes, display: flow-root, overflow other than visible/clip, and flex and grid items. A BFC contains its floats and stops margin collapsing through it. You'll use this in Topic 6.4.

  • ▸

    Images are inline by default and sit on the text baseline, which leaves a gap of a few pixels under them (room for letters like g and y). display: block on the image, or vertical-align: middle, removes the gap. Most CSS resets do this for img, svg and video.

  • ▸

    Physical and logical properties are aliases for the same value in the cascade: margin-left and margin-inline-start both set one physical margin, and whichever wins the cascade applies. Mixing them for the same side causes confusing overrides, so pick one style per project.

  • ▸

    The writing-mode of the root element sets the writing mode of the viewport, and it changes which way the page scrolls. In vertical-rl the page scrolls horizontally and starts at the right edge.

Remember this

  1. 1

    Normal flow is the browser's default way of placing boxes when you haven't asked for anything else: no floats, no positioning, no Flexbox or Grid. Every element's display value says how it takes part. Block-level boxes (div, p, h1, section, ul) each start on a new line, stack one after another in the block direction (downwards in English) and, with width: auto, stretch to fill the full width of their parent. Inline-level boxes (span, a, strong, em, text itself) sit side by side in the inline direction (left to right in English) and wrap onto the next line when there's no room.

  2. 2

    Inside a block, inline content is cut into line boxes: one invisible row per line of text. The browser fills a line box from the start, and when the next word doesn't fit it starts a new line box below. That's why an inline element ignores width and height: its size comes from its text and the line it sits on. Vertical padding and borders on an inline box do paint, but they don't push the lines apart. If you need a box that sits in a line but has a real width and height, use display: inline-block (Phase 5, Topic 5.4).

  3. 3

    When a block contains both text and other blocks, the browser wraps the loose text in an invisible anonymous block box, so every child of a block container is either all blocks or all inline content. You can't select anonymous boxes with CSS; they inherit from their parent. They explain odd cases, such as a bare line of text between two <div>s that still behaves like a block.

  4. 4

    Some things are taken out of normal flow: floated boxes (Topic 6.4) and boxes with position: absolute or position: fixed (Topic 6.2). Out-of-flow boxes no longer take up space for their siblings, so the rest of the page closes up as if they weren't there. Boxes with position: relative or sticky stay in flow: their original space is kept.

  5. 5

    The writing mode decides which way lines run. writing-mode: horizontal-tb (the default) means horizontal lines stacked top to bottom. vertical-rl makes lines run top to bottom, with each new line placed to the left of the last (traditional Chinese, Japanese and Korean). vertical-lr does the same with new lines going to the right (traditional Mongolian). The direction inside a line also changes for languages like Arabic and Hebrew, which run right to left. Set that with the HTML dir="rtl" attribute rather than the CSS direction property, because the direction belongs to the content, not the styling.

  6. 6

    Logical properties describe sides by flow instead of by screen edge. The inline axis is the way text runs; the block axis is the way blocks stack. So margin-inline-start means "the margin where a line begins": the left side in English, the right side in Arabic, the top in vertical text. inline-size and block-size replace width and height, padding-block sets top and bottom padding in horizontal text, and inset-inline-start replaces left. With logical properties, one stylesheet lays out correctly in every language. This topic is a preview; you'll use them throughout Phases 7–9.

Explain it without notes

01

What is normal flow, and how do block and inline boxes behave in it?

02

Why do width and height have no effect on a <span>?

03

Which boxes are taken out of normal flow, and what happens to their siblings?

04

What are the inline and block axes, and why do logical properties exist?

Practice

01

Make a <span class="pill"> 100px wide and 28px tall while it still sits inside the line of text.

02

Write a .callout rule with a 4px solid orange bar at the start of its lines, 12px of padding at the start, and 16px of margin above and below, all with logical properties.

03

Make a <div class="spine">Volume 1</div> that shows its text running top to bottom, like a book spine, 40px wide and 160px tall.

Trade-offs

  • ↔

    Logical properties make a stylesheet work in any language and writing mode, but they read less familiarly to teams used to left/right, and very old browsers (before 2020) lacked some of them.

  • ↔

    Normal flow needs no layout CSS and is naturally responsive and accessible, because the visual order matches the HTML order. Taking boxes out of flow gives you control but makes you responsible for overlap, spacing and source order.

Done when you can

  • I can describe how block and inline boxes are placed in normal flow.

  • I know why width doesn't apply to a <span> and how to fix it.

  • I can name what takes a box out of flow and what keeps it in flow.

  • I can switch a box to writing-mode: vertical-rl and predict its width and height.

  • I can rewrite margin-left, width and padding-top as logical properties.