CSS Layout Strategies
Introduction

This page reviews the basic CSS layout strategies that a web developer can employ to layout content on a page.

Along the way I present a basic workflow for how one can go about translating a desired design into a workable page layout. First, we start by creating a sensible DOM layout using standard HTML tags and/or <div> and <span> tags. Next, we work on the general sizing and spacing of the layout using the CSS Box Model facilities. Before going any further, we pause to think about how the layout will work with different screen sizes, and think about how we will use CSS Media Queries to affect a responsive design. We then consider when or where we may need to use floats or positioning. Finally, we consider which type of layout will be most effective for our design by considering table, list, Flexbox, and Grid layout mechanisms.

That's not to suggest that the workflow is a strictly linear progress. For example, if one knows for sure that they want or need a Flexbox or Grid layout, you may want to start there and then work your way back into the CSS Box Model margins and padding. It's an iterative process. The final design will usually involve a hybrid of all of the approaches outlined here.

HTML Tags

Before we begin to stylize and layout the page structure with CSS rules, we want to first consider a sensible DOM structure using available HTML tags.

Tag Section(s) Purpose Tag List Notes
Phrasing Content Presentation-Oriented Inline Content Styling <b>, <br>, <i> Avoid using presentation-oriented tags. Use alternate tags with better semantic meaning where possible. <strong> is preferred over <b>. <em> is preferred over <i>. Use paragraphs and/or margins and padding in place of <br> where possible.
Phrasing & Flow Content Semantically-Oriented Inline Content Styling <abbr>, <em>, <strong>, etc. Most other tags not listed here, with the exception of metadata tags, are part of a large category of flow content tags. They are generally used to style the actual content of the page, not the structural layout.
Sectioning Content Semantically Meaningful Structure <article>, <aside>, <nav>, <section> Sectioning content tags are the first opportunity to begin considering the actual structural layout of the page.
Flow Content Section Headers & Footers <header>, <footer> Technically speaking, these tags are flow content, and are not considered part of sectioning content or heading content. They are generally placed inside of a <section>, but this is not required. When not inside a section group, the tags should be considered to supply header and footer content for the page body. As such, these tags should be considered for use as part of an overall page layout strategy.
Flow Content The Main Tag <main> Another flow content tag, <main> designates the main body of content of page. It should not contain any content that is repeated across pages, such as logos, top navigation bars, side navigation bars, headers, footers, etc. This tag should be considered as part of a well-designed page layout.
Heading Content Header Titles <h1> to <h6> Use heading content tags to supply title information to pages and sections.
Flow Content Lists & More <ol>, <ul>, <li> Traditionally used to format hierarchically-arranged bulleted lists, these tags have been used creatively for other purposes. A common example is to use a formatted list to style a set of tab header items for tab-separated content. In addition to the tags, the CSS property display: list‑item can be used to style any element as a list item.
Flow Content Tables <table>, <tr>, <thead>, <tfoot>, <th>, <td> Tables should not be used for general page layout purposes. They should only be used to format genuinely tabular data for which multiply aligned rows and columns are the most logical form of presentation. The corresponding CSS rules display: table and its brethren can now be used to style any element as a table-type structure, and can sometimes be a good choice for cetain layouts that are difficult to achieve with ordinary methods, although now with Flexbox and Grid layouts they are less needed.
Flow Content Generic Structure <div>, <span> Because HTML provides us with so few sectioning content tags that we can use for semantically-meaningful layout, most of the time we need to resort the the generic box tags <div> and <span>, which provide block and inline boxes (see below for more details). For increased semantic meaning, we can apply one or more CSS classes.
Box Display Types

The commonly-used block, inline, and inline‑block display values are typically used in conjunction with the <div> and <span> tags, but they can be applied to any element. These properties are frequently the first line of attack when approaching page layout.

Display Value Description Box Characteristics
display: none; The box is not rendered and no space is taken up in the document flow. To reserve space in the document flow, but make the box invisible, use visibility: hidden; instead.
  • N/A
display: block; Displays the element as a block element (like <p>)
  • Settable width and height
  • Normally, line breaks are inserted into the document flow after the element, unless other flow-disrupting properties are in effect, such as floats, non-static positioning, etc.
display: inline; Displays the element as an inline element (like <span>)
  • Width and height are ignored
  • The size of the box expands or contracts as needed to accommodate the size of its children.
  • No line break inserted into the document flow after the element
display: inline‑block; Displays the element as an inline-level block container. The inside of this block is formatted as a block-level box, and the element itself is formatted as an inline-level box.
  • Settable width and height
  • No line break inserted into the document flow after the element
Other Display Values See other layout alternatives below for more possible display values, such as flex and grid.
  • See below

More Information

Block vs. Inline

Basic Box Model Layout

After laying out the page with well-chosen HTML tags, and choosing block, inline, and inline‑block box types as-needed, the next step in a typical layout workflow would be to turn our attention to the CSS Box Model styling attributes to size the boxes as we'd like.

The CSS Box Model is a very power and flexible mechanism for controlling the margin, border, and padding of the boxes.

More Information

CSS Box Model

Advanced Box Model Layout

Beyond the basic box model usage, there are some advanced, trickier, and less known techniques we can consider.

Technique Notes
Box Sizing

The box‑sizing property is set to content‑box by default. That means the height and width settings are applied to the size of the box's content only. The total size of the box is the content size + border + margin + padding.

It's often the case, especially when focusing on the outer, overall layout of the page, that this doesn't give us what we want. If we change the sizing property to border‑box, then the height and width will apply to the content size + padding + border (but still not the margin).

Negative Margins

Although not immediately obvious, negative margins are valid on boxes. While its best not to misuse this feature, there are legitimate use cases for negative margins. More Details

Auto Margins

The keyword auto can be applied as a setting to the left and right margins. When they are both set to auto, then content will center itself horizontally with the parent box.

Unfortunately, auto margins do not work for the top and bottom margins, and so the same technique does not work for vertically aligning content within a parent box. Vertical alignment is a classic problem with HTML and CSS.

CSS calc() Function

The introduction of CSS3 gave us the calc() function, which is now supported on all modern browsers, including IE10 and IE11, and even IE9 supports it with a few minor bugs.

The most common use case is to calculate the actual width based on a percentage value and a fixed unit value. For example, suppose my box has left and right margins of 10px each, and I want my width to be 100% of the width of my parent. Without calc(), I have no way to do this. Even if I set box‑sizing: border‑box, I still have to account for my margins. Using calc() I can subract off my left and right margins and set width: calc(100% - 20px).

The calc() function works best when I have the box sizing set to border‑box, because then I only need to worry about my margins. The padding and borders are already accounted for.

The calc() function is less needed now that we have the newer Flexbox and Grid layouts. Even so, I find that this is often the easiest way of accomplishing some otherwise thorny layout problems.

Setting Body Height

It doesn't happen to me as much anymore, but when I was new to CSS layout I'd often get burned by this one. I'd have a layout that I intended to fill the full page of the browser. I was certain everything was correct, but my inner child element wouldn't expand to fill the full height of the browser. Instead, it would collapse down to the height of its children.

The problem is that the html and body tags themselves were not expanding to the full browser height. We can set those easily enough. I also usually set padding and margin to 0 on those element as well. My CSS generally has a rule it it like:

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%;
}

Other Display Types In the old days of CSS 2.1, we only had the lowly display: block and display: inline to work with. But with the introduction of CSS 3, we gained a whole host of new display options. We now have display types dedicated to list and table displays, and with the new Flexbox and Grid layout modules, we've gained even more flexibility. The layouts are discussed further down the page.
Media Queries

Media queries allow us to design interfaces that are responsive to a wide variety of device capabilities. Our page layouts should contemplate how the user experience will behave on different screen sizes and different device capabilities.

Originally introduced as media types in CSS 2, which provided some limited responsive design constructs, these capabilities were greatly expanded in CSS 3 with the introduction of media queries. CSS 2 only allowed us to query the type of the device, but with CSS 3 we can query the capabilities of the device. Does the device have a mouse? Does it support stylus or touch input? What is its aspect ratio? Etc.

Some measure of responsive design can be accomplished without media queries. When we use percentage height and widths in our CSS rules, telling the browser to stretch out our content to fill the space of the parent box, we're doing responsive design that can accommodate the user resizing their browser ... but only to a degree. That approach won't accommodate radical changes in screen size. What happens if the user accesses the site from their smartphone or tablet? It won't look good. We need more than just stretching our box to fill the space, we need a way to choose between entirely different layout options based on the capabilities of the device. Our beautiful side navigation pane looks great when the browser is at least 1200px wide, but for smaller sizes we want a dropdown list at the top of the page that doesn't require as much space. Those are the kinds of choices we can build into our CSS rules using media queries.

More Information

W3Schools - Responsive Web Design
W3Schools - Media Query Examples
W3Schools - Media Queries Overview
W3Schools - The @media CSS Rule
MDN - Media Queries Overview
MDN - Using Media Queries
MDN - @media

Floats

Originally designed for floating blocks of text around images, the float property became, prior to Flexbox and Grid layouts, one of the most commonly used tools for creating multiple column layouts on web pages. Another common use case is laying out a top navigation bar. You want some content in the navigation bar aligned to the left hand side, and other content aligned to the right hand side.

Floats are tricky to use, because after using the float to align the desired content, we need to clear the floats so that the follow-on content goes back normal. This makes the designing clean, well-organized, independently-formatted content more difficult. Floats are less needed now that we have Flexbox and Grid layouts, but they can still be useful in some situations.

More Information

W3Schools - Float and Clear
MDN - Floats

Positioning

Positioning allows you to take elements out of the normal document layout flow, and make them behave differently, for example sitting on top of one another, or always remaining in the same place inside the browser viewport.

Position Value Description
position: static; The default position of every element. It means put the element in it's normal position in the document layout flow.
position: relative; Once the positioned element has taken its place in the normal layout flow, you can then modify its final position (using the CSS properties top, left, bottom, and right).
position: absolute; An absolutely positioned element no longer exists in the normal document layout flow. It sits on it's own layer, separate from everything else. It's position is anchored by it's closest statically positioned ancestor, and is controlled with the CSS properties top, left, bottom, and right. You can also use z-index to control its position in a z axis, which can be affected by the opacity if it overlaps other elements.
position: fixed; Similar to absolute positioning, except the element is positioned relative to the browser viewport itself (as opposed to its closest static ancestor).
position: sticky; An experimental position that is not yet widely supported, it is a hybrid of relative and fixed. The element is relatively positioned until it is scrolled to a certain threshold point, after which it becomes fixed.

More Information

W3Schools - The position Property
MDN - Positioning

List Layouts & Styling

We tend to think of ordered an unordered lists as inherently being a way to style hierarchically arranged, bulleted lists. That is the default styling applied to those elements, but semantically speaking, the <ol> and <ul> are only meant to define a block that contains a list of items. They may be displayed as bulleted lists, and are by default, but ultimately it is up to the designer to style them. CSS provides us with mechanisms for doing so.

Lists can sometimes be used as a layout mechanism. For example, this article from MDN describes how to use lists as a way of composing a tab control, and this article describes how to use lists to create multi-column layouts. Lists can also be an effective way to mark up the items in a top or side navigation pane.


CSS Property Description
display: list‑item; Let the element behave like a <li> element
list‑style: [<type>] [<position>] [<image>] A shortcut property to set all list item properties with a single setting.
list‑style‑image: url(image‑location) Replaces the default item marker (typically a bullet) with an image.
list‑style‑position: inside; Indents the marker and the text. The bullets appear inside the content flow.
list‑style‑position: outside; The default. Keeps the marker to the left of the text.
list‑style‑type: value; Sets the type of bullet or number. There are over 20 bullet and numbering styles to choose from. More details.

More Information

MDN - Practical Positioning Examples

Table Layouts

Using the HTML table tags for layout purposes has always been frowned upon, primarily for these reasons.

The dogma always seemed a bit silly to me, especially considering how difficult is was to create certain layouts without tables, and how easy it was to do with tables. Take for example the so-called Holy Grail layout, and various attempts over the years to create them with tableless CSS rules. It hardly seems fair to give something the mystique of the Holy Grail, when there's a beautiful, solid gold, jewel-encrusted chalice laid out directly before you, surrounded by flashing neon lights emblazened with the headline Jesus Drank from this Cup.

But, using CSS tables instead of hard-coded HTML elements, we can avoid some of the downsides of tables. With Flexbox now becoming ubiquitous, there's less reason to consider CSS tables, but even so, it's good to keep CSS table layout tucked away in your bag of tricks. Any HTML element can be made to act as a table element using the CSS display property.


Display Setting Element Behavior
display: inline‑table; The element is displayed as an inline-level table
display: table; Let the element behave like a <table> element
display: table‑caption; Let the element behave like a <caption> element
display: table‑column‑group; Let the element behave like a <colgroup> element
display: table‑header‑group; Let the element behave like a <thead> element
display: table‑footer‑group; Let the element behave like a <tfooter> element
display: table‑row‑group; Let the element behave like a <tbody> element
display: table‑cell; Let the element behave like a <td> element
display: table‑column; Let the element behave like a <col> element
display: table‑row; Let the element behave like a <tr> element

More Information

The Anti-hero of CSS Layout
Why Tables Are Bad (For Layout)
W3Schools - The display Property

Flexbox

A new technology, but with support now fairly widespread across browsers, Flexbox is starting to become ready for widespread use. It allows for rapid creation of complex, flexible layouts, and features that have historically proved difficult with CSS.

More Information

Flexbox Examples
W3Schools - Flexible Box
MDN - Flexbox
CSS-Tricks - A Complete Guide to Flexbox
Solved by Flexbox

Grid Layouts

A nascent new browser feature that makes implementing a grid design much easier. Grid designs, such as those popularized by Bootstrap and other similar CSS toolkits have traditionally used floats or other layout features, and can sometimes prove tricky to implement.

The main difference between Flexbox and Grid is that Flexbox is designed for a one-dimensional layout, whereas Grid is explicitly designed to create two-dimensional layouts.

More Information

MDN - Grids
MDN - CSS Grid Layout
CSS-Tricks - A Complete Guide to Grid