---
title: 'Floating Elements'
source: 'https://academia.sh/en/courses/css-fundamentals/floating-elements'
course: 'Visual Presentation with CSS'
language: en
updated: '2026-08-17T18:09:15+00:00'
license: 'CC BY-SA 4.0'
---

# Floating Elements

Floating shortening line boxes so text flows around a box; the containing box's height problem, and the clearing and formatting-root solutions.

Normal flow laid boxes out in two patterns: blocks stacked, inline boxes side by side. In the
station page's location section there is a request that fits neither pattern — the location
image should sit to the left of the text, and the caption text should **flow around** the
image.

The mechanism defined for this behavior is called **float**. Floating pushes a box to one edge
of the inline axis and has the line boxes in flow pass around it. This lesson takes up what
floating does, what it does not do, and the height problem it brings with it.

## Floating Shortens Line Boxes

A floated box is taken out of normal flow but **keeps affecting** flow. Its effect is in one
place only: line boxes that share its vertical range get shortened.

```js
// float.mjs — computes how a floated box shortens line boxes
function lines({ containerWidth, floatWidth, floatHeight, lineHeight, lineCount }) {
  const result = [];
  for (let i = 0; i < lineCount; i++) {
    const top = i * lineHeight;
    const insideFloat = top < floatHeight;
    const available = insideFloat ? containerWidth - floatWidth : containerWidth;
    result.push({ line: i + 1, top, available, start: insideFloat ? floatWidth : 0 });
  }
  return result;
}

for (const s of lines({ containerWidth: 640, floatWidth: 200, floatHeight: 120, lineHeight: 24, lineCount: 7 })) {
  console.log(`line ${s.line}: top=${String(s.top).padStart(3)}  x=${String(s.start).padStart(3)}..640  available width=${s.available}`);
}

console.log("\n--- the container's height ---");
function containerHeight({ flowContentHeight, floatHeight, isFormattingContext }) {
  return isFormattingContext ? Math.max(flowContentHeight, floatHeight) : flowContentHeight;
}
for (const isFormattingContext of [false, true]) {
  const h = containerHeight({ flowContentHeight: 48, floatHeight: 120, isFormattingContext });
  console.log(`formatting context=${String(isFormattingContext).padEnd(5)} -> container height=${h}`);
}
```

```
line 1: top=  0  x=200..640  available width=440
line 2: top= 24  x=200..640  available width=440
line 3: top= 48  x=200..640  available width=440
line 4: top= 72  x=200..640  available width=440
line 5: top= 96  x=200..640  available width=440
line 6: top=120  x=  0..640  available width=640
line 7: top=144  x=  0..640  available width=640

--- the container's height ---
formatting context=false -> container height=48
formatting context=true  -> container height=120
```

The first five line boxes are 440 units wide instead of 640, and start from 200: that is where
the floated image sits over that range. The sixth line, since it passes the image's bottom
edge, returns to full width. This is what it means for text to flow around the image — not
some mysterious wrap behavior, but line boxes being shortened.

Two conclusions follow from this.

**Floating affects only line boxes, not block boxes.** A block box next to a floated box does
not narrow; it keeps filling its container and passes underneath the floated box. Only the
text lines inside that block box get shortened. This is why using float to build column
layout is fragile.

**Floating has a direction.** `float: inline-start` pushes the box to the start of the inline
axis, `float: inline-end` to the end. Their physical counterparts are `left` and `right`;
logical values adapt to writing direction.

## The Container's Height Collapses

The output's second block gives the actual problem with floating. Since a floated box is
taken out of flow, it **takes no part** in its container's height. If the container has 48
units of flow content and a 120-unit floated image, the container's height comes out 48; the
image spills outside the box.

The visible result is that a background or border given to the container does not cover the
image. This is not a bug, it is a direct consequence of the definition: a box out of flow
contributes nothing to flow's height.

There are two solutions.

## Solution 1: Clearing

The `clear` property tells a box to drop **below** any floated boxes that precede it.

```css
.clear { clear: both; }
```

`clear: inline-start` drops below only start-floated boxes, `inline-end` below only
end-floated ones, `both` below either.

Clearing is used to fix the container's height indirectly: if a clearing box is placed as the
container's last child, that box drops below the float and the container stretches to contain
it. This can be done without cluttering the document with a pseudo-element:

```css
.clearfix::after {
  content: "";
  display: block;
  clear: both;
}
```

The solution works but is indirect: a content element is generated to solve the height
problem.

## Solution 2: Independent Formatting Root

The direct solution is to make the container a **block formatting context**. Such a box
includes the floated boxes inside it in its own height; the output's last line, where the
height is 120 in the `formatting context=true` case, shows this.

The explicit way to make a box a formatting root:

```css
.location-section { display: flow-root; }
```

There are also indirect ways that give the same result: an `overflow` value other than
`visible`, the box sitting inside a flexible box or grid layout, being absolutely positioned.
These come with side effects — writing `overflow: hidden` also clips overflowing content.
`flow-root`, on the other hand, does only the job wanted.

A formatting root has three effects, and all three have already come up in earlier lessons:

- Floated boxes inside it are included in its height.
- Floated boxes outside it do not spill into it.
- Margin collapsing stops at its boundary.

All three come from the same definition: the box completes block placement within itself.

## The Floated Box's Own Size

A floated box produces a block box but does not fill its container. When its width is not
declared, it **shrinks to fit its content**: the box pulls in to the narrowest size it can fit
into. This is the opposite of a block box's behavior in flow.

The result is that declaring a width for a floated box is often necessary. A box carrying text
that shrinks grows the line count and stretches unpredictably; a box carrying an image settles
at the image's natural size.

A second behavior is that floated boxes **push against each other**. When more than one box is
floated to the same edge, they line up side by side; whatever does not fit on the line drops to
a row below. Where it drops is determined by the bottom edges of the preceding floated boxes,
and if the boxes are different heights, the arrangement becomes irregular. This is another
source of the fragility of building grid-like layout with float.

## The Shape of the Float Boundary

The boundary that shortens line boxes is, by default, the floated box's margin rectangle — a
rectangle no matter its shape. This boundary can be changed with the `shape-outside` property:

```css
.location-image {
  float: inline-start;
  shape-outside: circle(50%);
  shape-margin: 12px;
}
```

`shape-outside` only changes the boundary of flowing text; it does not clip the box itself. If
the image is also wanted to look circular, `clip-path` is written separately. The two
properties do different jobs: one decides where neighbors pass, the other decides what part of
the box is painted.

## What Floating Is For

Float has long been used as a tool for building column-based page layouts. This use does not
fit float's definition, and the output's first block shows why: floating does not place a box
into a column, it only shortens line boxes. Equalizing column heights, aligning boxes, and
spacing them remain problems that must be solved separately.

The one use that matches float's own definition is **flowing text around a box**. The layout
systems taken up in the next course take over the job of building columns, and do it with
fewer declarations and more predictably than float. Float still has a place in those courses
too, because no layout model flows text around a box.

```css
/* station.css — step 12: location image and text flowing around it */
.location-section { display: flow-root; }

.location-image {
  float: inline-start;
  inline-size: 200px;
  margin-inline-end: 16px;
  margin-block-end: 8px;
}

.location-section .source-note { clear: both; }
```

The `display: flow-root` declaration makes the section contain the image. The margin given
toward the end of the image keeps text from pressing against it — a floated box's margin edge
is the boundary that shortens line boxes, not its border edge.

The last rule drops the source note below the image; the note should be read not to the right
of the text but at the end of the section.

## Summary

- A floated box leaves normal flow but shortens line boxes that share its vertical range; this
  is what it means for text to flow around it.
- Floating affects line boxes, not block boxes; this is why it is fragile as a tool for
  building column layout.
- A floated box takes no part in its container's height; the container collapses and its
  background or border does not cover the floated content.
- `clear` drops a box below floated ones; used as the container's last child, it fixes the
  height indirectly.
- `display: flow-root` makes a box an independent formatting root: it includes floats in its
  height, keeps outside floats from spilling in, and stops margin collapsing at its boundary.

## Next Step

Floating took a box out of flow but did not let its destination be chosen; the box was only
pushed to one edge. Placing an element at a wanted point in the document — a badge in a card's
corner, a heading held fixed while scrolling — needs a different mechanism. The next lesson
defines positioning's five values and what box each is measured against.
