Module: CSS
CSS·037·4 MIN READ

037: Floats, Multi-Column Layout, Lists, and Tables

TOPICS COVERED: Floats, Multi-Column Layout, Lists, and Tables

Learning outcomes

By the end, you can use floats for genuine text wrapping; clear/contain floats; create multi-column editorial layouts; style list markers without destroying semantics; style tables accessibly; and know when Flexbox/Grid are better choices.

Prerequisites and retrieval

Retrieve normal flow from 025 and table/list HTML semantics from the HTML module. This lesson covers specialized layout/styling areas represented separately on the CSS roadmap.

Floats: what they are still good for

html
<article class="story">
  <img class="story__image" src="speaker.jpg" alt="Conference speaker on stage">
  <p>
    The conference opened with a discussion of browser layout...
  </p>
</article>
css
.story {
  display: flow-root;
}

.story__image {
  float: inline-start;
  inline-size: min(40%, 14rem);
  margin-inline-end: 1rem;
  margin-block-end: 0.5rem;
}

Text wraps around the floated image. That is a natural float use case.

Do not build modern page columns with floats:

css
/* historical technique; avoid for ordinary page layout */
.sidebar {
  float: left;
  width: 30%;
}

Flexbox and Grid express layout relationships more directly.

Clear

css
.footer {
  clear: both;
}

clear controls whether a box may sit beside earlier floats. display: flow-root on the containing block is often a cleaner way to contain floats.

Multi-column layout

css
.article {
  column-width: 18rem;
  column-gap: 2rem;
}

or:

css
.article {
  column-count: 3;
}

Column rule:

css
.article {
  column-rule: 1px solid #cbd5e1;
}

Prevent a heading from being awkwardly separated:

css
.article h2 {
  break-after: avoid;
}

Span all columns:

css
.article__title {
  column-span: all;
}

Worked example: editorial article

css
.long-read {
  max-inline-size: 75rem;
  margin-inline: auto;
  column-width: 20rem;
  column-gap: clamp(1.5rem, 4vw, 3rem);
}

.long-read p {
  margin-block-start: 0;
}

.long-read h2 {
  break-after: avoid;
}

Multi-column layout flows content top-to-bottom within one column, then into the next. That can be useful for print/editorial reading but can be awkward on tall scrolling screens because the reader may need to move back upward. Test the reading experience rather than using columns solely for visual density.

Lists

Remove default styling only when you replace its visual purpose appropriately:

css
.nav-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

For content lists, keep markers or create clear alternatives.

Custom marker:

css
.features li::marker {
  color: #16a34a;
  content: "✓ ";
}

Marker position/style:

css
.steps {
  list-style-position: outside;
  list-style-type: decimal;
}

Worked example: numbered process

css
.steps {
  counter-reset: step;
  list-style: none;
  padding: 0;
}

.steps li {
  counter-increment: step;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.75rem;
}

.steps li::before {
  content: counter(step);
  display: grid;
  place-items: center;
  inline-size: 2rem;
  aspect-ratio: 1;
  border-radius: 50%;
  background: #2563eb;
  color: white;
  font-weight: 700;
}

The semantic <ol> should still be used if sequence/order matters; CSS counters are presentation.

Tables

Baseline:

css
table {
  width: 100%;
  border-collapse: collapse;
}

th,
td {
  padding: 0.75rem 1rem;
  border-block-end: 1px solid #e2e8f0;
  text-align: start;
}

th {
  font-weight: 700;
}

Zebra striping:

css
tbody tr:nth-child(even) {
  background: #f8fafc;
}

Hover can aid pointer scanning:

css
tbody tr:hover {
  background: #eff6ff;
}

but do not make hover the only way to see essential row information.

Table layout algorithm

css
table {
  table-layout: fixed;
}

fixed can make column sizing more predictable/performance-friendly in some data tables, but long content may overflow. Use deliberately.

css
td {
  overflow-wrap: anywhere;
}

Responsive table wrapper

html
<div class="table-wrap" role="region" aria-label="Quarterly sales" tabindex="0">
  <table>
    ...
  </table>
</div>
css
.table-wrap {
  overflow-x: auto;
  max-inline-size: 100%;
}

.table-wrap:focus-visible {
  outline: 3px solid #2563eb;
  outline-offset: 3px;
}

Only add tabindex="0" when the scroll region needs keyboard access/discoverability in the target environment; do not flood the tab order with unnecessary focusable wrappers.

Caption styling

css
caption {
  text-align: start;
  font-weight: 700;
  padding-block-end: 0.75rem;
}

Keep the actual <caption> in HTML rather than simulating it with a styled paragraph.

Deep dive: formatting contexts, fragmentation, and counters

Containing floats

Floats are removed from ordinary block flow enough that a parent may appear not to contain them. Creating a new block formatting context can contain float effects:

css
.article-lead {
  display: flow-root;
}

.article-lead img {
  float: inline-start;
  margin-inline-end: 1rem;
  margin-block-end: 0.5rem;
}

flow-root is usually clearer than old clearfix hacks.

Shape-aware wrapping

Where appropriate, shape-outside can make text wrap around a non-rectangular float:

css
.profile-photo {
  float: inline-start;
  inline-size: 12rem;
  aspect-ratio: 1;
  border-radius: 50%;
  shape-outside: circle(50%);
  margin-inline-end: 1.5rem;
}

This is editorial layout, not a replacement for Flexbox or Grid.

Multi-column fragmentation

Multi-column layout flows content through columns, so page-like fragmentation rules matter.

css
.article {
  columns: 18rem 3;
  column-gap: 2rem;
  column-rule: 1px solid var(--border);
}

.article h2 {
  column-span: all;
}

.article figure,
.article blockquote {
  break-inside: avoid;
}

Do not use columns for controls that need a predictable left-to-right interaction order. They are best for long-form reading.

CSS counters for semantic numbering

Keep list semantics in HTML, then customize marker presentation:

css
.steps {
  counter-reset: step;
  list-style: none;
  padding: 0;
}

.steps > li {
  counter-increment: step;
}

.steps > li::before {
  content: counter(step) ".";
  font-weight: 700;
  margin-inline-end: 0.5rem;
}

If an ordered sequence is actually ordered, prefer <ol> even if CSS customizes the marker.

Table layout decisions

table-layout: fixed uses declared/available widths more predictably:

css
.pricing-table {
  inline-size: 100%;
  table-layout: fixed;
  border-collapse: collapse;
}

This can prevent one long cell from dominating column sizing, but it also makes overflow management your responsibility.

For narrow screens, first consider horizontal scrolling while preserving the real table:

css
.table-scroll {
  overflow-x: auto;
  overscroll-behavior-inline: contain;
}

Avoid converting every cell into pseudo-label blocks unless the transformed reading order and header relationships have been tested with assistive technology.

Decision rule

  • Float: text wraps around an object.
  • Columns: editorial content flows into newspaper-like columns.
  • Flexbox: one-dimensional component/layout relationship.
  • Grid: row-and-column alignment.
  • Table: genuinely tabular data with header relationships.

Choose by information structure before visual preference.

Common mistakes

  • Using floats for entire application layouts.
  • Clearing floats with meaningless extra HTML.
  • Applying multi-column layout to interactive forms/cards where reading order becomes confusing.
  • Removing list markers from ordinary content without another visual cue.
  • Turning a real data table into display: block fragments and destroying relationships.
  • Setting display: grid on table internals without understanding the semantic/accessibility consequences.
  • Forcing narrow table columns that make content unreadable.

Practice set

  1. Float an editorial image and contain it with flow-root.
  2. Build a two/three-column article using column-width.
  3. Style an ordered process without removing <ol>.
  4. Build an accessible data table with caption and scoped headers.
  5. Add a horizontal overflow wrapper and keyboard focus style.
  6. Compare table-layout: auto and fixed.

Recap

Floats remain useful for content wrapping, multi-column layout is an editorial flow system, lists should preserve list semantics, and tables should preserve data relationships. Specialized CSS tools are valuable when used for the problem they were designed to solve.

Official references