CSS layouts have changed significantly within the past several years due to flexbox and to grid. In order to bridge the gap between developers who started before this modern era (such as myself), and between developers starting now (who are wondering what clearfix
is), let's take a look at solutions we did in the past and how they compare to the (much easier and more versatile) methods of today. Although it's unlikely anyone new to development is using the older methods, you will still encounter these layouts if you work on older sites.
Special shoutout to Rachel Andrew, Jen Simmons, CSS Tricks, MDN and Scrimba for providing so many online resources and books on this topic
Originally posted on Codepen on Nov 24, 2019.
The Past, Present and Future
- Pre-Dawn Layouts (No CSS / Tables)
- The Age of Floats and Hacks
- The Modern Era of Flex and Grid
- Other Layout Methods
- Backwards Compatibility
- More Information
Pre-Dawn (No CSS / Tables)
Before we had CSS, all the "styling" was done using HTML because there was no way to separate it.
- Document flow - order of elements in the HTML
- Tables for layout
- No separation of content and presentation
- Complicated / time-consuming to update
- Not responsive
- Not semantically correct use of
<table>
tags
I've had to modify my fair share of web sites built entirely with tables, and it was quite unpleasant. At one point in order to accomplish the design on a site I didn't build, I stuck a complete div
within a td
cell. (I wasn't proud but it worked and passed W3C validation!)
The Age of Floats and Hacks
Floats were initially designed to wrap text around an image or other element. Then some really smart developers figured out a way to hack this tool to make multiple-column layouts by setting widths of floats within a container.
Float works well for columns with equal height:
Unfortunately float does not stack well when columns have different heights. In the example above, because the 2nd card is longer, it blocks the 4th card from being able to form a new row directly below the 1st card.
The solution was to add a wrapper around each row with clearfix in HTML. This makes each row its own container:
Bootstrap 3’s grid system follows this logic:
- Rows have negative margins on both left and right sides to account for left/right padding of floated divs
- This method doesn't work well with dynamic content or when you don't know how many items will be in each row
There is no easy way to vertically align content when the elements are floated.
An alternative method that does allow vertical alignment is inline-blocks:
However there are complications with using inline-block elements for layout:
- Inline elements contain properties of both
block
andinline
, which means you can set a width (because of theblock
property) but items that areinline-block
always preserve horizontal white space in order to maintain spaces between words (because of theinline
property) - This means there is always an inherent margin between items
- You either need to zero out the margin or make sure widths never add up to 100%
How do I get my heights to match???
Neither floats nor inline-block force the elements to be same height.
Let's make everything a table again?
None of these solutions are ideal and/or require a combination of different CSS properties. I started out my career using floats and got pretty good at it, but after avoiding using it at all the past couple of years, I don't miss it at all.
The Modern Era - Flex and Grid
Flexbox and grid are modern solutions to the previous issues we had with layout methods. Both layouts have their specialties but let's clear up some things:
- Flexbox was implemented first
- The addition of grid does not make flex obsolete. Some things you can do in flex that you cannot do in grid
- There is overlap in which both can be used to achieve the same visual effect
- If you can, use the right one to take advantage of its unique inherent features
- You can use both of them to accomplish things neither can do by itself
When to use Flex vs Grid
Use Flex when:
- Content is priority
- Need horizontal or vertical alignment
- Layout is one-dimensional
- Need better older browser support (but use prefixes!)
Use Grid when:
- Things need a set width regardless of content
- Need two-dimensional layout (items in one row or column need to align with the item in the previous row or column)
- Elements need to overlap
The terms one-dimensional vs. two-dimensional are very confusing if you're completely new to these layout methods, because you can have multiple rows or columns using flexbox, and you can only use grid for one row or column only.
Because flex only considers one direction at a time, I think of flex as forgetting what it did previously. If you have 2 rows of items using flex, once you get to the 2nd row, flexbox doesn't remember what it did in row 1. It follows the flex properties that are set; if this happens to cause the items in row 2 to align with the items in row 1, that just happens to be the case that they are all the same width. It doesn't necessarily have to line up.
With grid, think of a Connect Four game board. You can drop the plastic tokens and line up multiple red pieces together to form one big red section, or giant blue sections, but the pieces must always slot within the row and columns. Nothing can ever fill half a row or column.
Flexbox
- Content-driven
- Enables easier vertical and horizontal alignment
- Allows children to "flex", "either growing to fill unused space or shrinking to avoid overflowing the parent" - W3
- Only considers one direction (row or column) and only processes one at a time
You CAN set widths on flex items but if you're setting widths on everything in the flex container, you aren't taking advantage of flex and should use grid instead.
Flexbox is a savior when it comes to vertically aligning things within a container. Previous methods I would use commonly were:
- Setting line-height equal to the height of the container (and thus blowing up if text ever wrapped to multiple lines)
- Creating a wrapper around the item and using a combination of
display: table
anddisplay: table-cell
- Using
transform: translateY()
Flexbox Examples
Let's look at the default Flex settings and compare with different values for flex-grow and flex-shrink:
Remember when we couldn't do both equal-height containers and vertical alignment? We can with flexbox:
Playing around with flex-grow and flex-shrink can allow us to fill the row if we don't have an equal number of items per row. This is an example of flex forgetting what it did previously; it only obeys the content-sizing rules you have set up.
Here are two simple navigation bars using flex, which is a good example of what flex is inherently good at versus grid. Each flex item extends to the width of the content; grid would not be useful here. The first groups links to the left and aligns one to the very right to separate it:
The second navigation bar allows all items to be equally spaced when we don't know how many links or how long the link names will be. This wasn't hard to do using floats or inline-block; it just required manually updating the margins every time a new item got added or the text was updated:
Finally here's a masonry-type gallery we can build with flex. We wouldn't be able to accomplish this exactly with grid because everything using grid would have to align to both the horizontal and vertical tracks set up:
Grid
Grid is the first CSS module designed specifically for layouts - something we've been lacking ever since CSS was created.
Grid can handle both rows and columns, meaning that it will always align items to the horizontal and vertical tracks you have set up. Grid is mostly defined on the container, not the children as it is with flexbox.
Grid Examples
Here's a basic non-responsive layout using fractional units. Notice how much shorter the code is versus the previous methods.
Note that this same layout can be accomplished with flexbox as well as long as you set the width property on all the flex children. This will cause them to neither grow nor shrink (or flex) anymore, which means you are no longer taking advantage of the inherent properties of flex. It's still better than using floats or inline-block, but if you are able to use grid in this scenario, then that is a better case for grid.
Here's a responsive layout using auto-fit and repeat. Notice the lack of media queries:
Here's the same idea except for a photo gallery. Notice that there is a fallback for older browsers that do not support grid by using a feature query:
Advanced Grid Examples
We can control the exact location of items by specifying the row/column numbers and where they start/end. This method can be confusing if you are used to other programming languages where arrays start at 0. With grid, the lines each start at 1 instead. I would highly recommend using Firefox or Chrome's Developer Tools to easily debug these layouts:
Here's the exact same layout, but instead of using grid and row numbers, we are using named areas instead:
Because we can control the exact size of items using column and row spans, we can create a variation of the flex masonry gallery above using the grid property grid-auto-flow: dense
. Note that this rearranges items differently than how they were laid out in the html source order.
Supercombo of Flex AND Grid
This layout uses grid to align the cards and make them equal heights across all the rows (finally!). Flexbox is then used to align the button to the bottom of every card. It seems simple now but this was one of the most frustrating experiences I had using floats; I would have to set min-height
and hope that the content never fluctuated wildly afterwards, but this means needing to change the height multiple times using media queries.
Other Layout Methods
As awesome as they are, flexbox and grid don't make every previous method obsolete. The document flow of the HTML is still the OG layout. We're probably not going to display: grid
on the body tag. Other layout methods are still fine too provided we use them for their actual purpose:
- Use floats to wrap items around another item (ex: text wrapping around an image)
- Use tables for tabular data (this is better semantically as well)
- Use position: absolute / fixed / sticky for any element that must be taken out of the HTML flow
- Use multi-column layout for flowing continuous content
Backwards Compatibility
But what about [outdated browser]?
Flexbox and grid are only fully supported in modern browsers. Internet Explorer 10 supports flexbox with caveats around some properties (particularly the flex shorthand), and IE11 has its own prefixes for grid and doesn't support all the other properties. As of 2021, you probably don't have to support IE much anymore.
I used to find coding web pages for older browsers to be a giant pain, especially IE9 and below. It can still be frustrating occasionally, but recently I've subscribed to the idea that websites should always be as backwards-compatible as they can be because that was the entire purpose of the web. Web sites are not applications in terms of being versioned and then failing to run completely if your browser is too old. They should always be accessible as possible.
What I was doing wrong when I was testing in IE was trying to match the design exactly across every single desktop browser. Then I kept hearing about the idea: why does the site have to look exactly the same in IE8 vs modern browsers? We already have different experiences for mobile and tablet, and even the same browser will render slightly differently on different computers.
If your client's users are mainly IE11, then yeah you shouldn't be doing everything in grid. Ideally the design would keep that in mind as well. But if we're working off designs that are based on modern browsers, then we should use modern methods but make sure that these still look and function well in all the older browsers.
Layout Comparison
Let's take the same simple 3 boxes layout that we started with at the beginning and look at how they compare across floats, flex and grid:
Notice that the float method doesn't make the items equal heights - not unless you add a min-height
and even then if the content in one of those boxes gets longer you're back to square one. Maybe that's okay for older browsers; maybe they won't get that nice polish of having beautifully aligned buttons, but the content and images and order are still presented in the same manner and everything is still readable.
Resilient CSS
I really like the term "resilient CSS" by Jen Simmons. The site's CSS should use the cascade properly in terms of failing and overriding. CSS properties not understood by the browser will just not run and skip to the next line.
Knowing this we can arrange our CSS in a way to maximize compatibility. If we use feature queries, we need to take into account that modern browsers will run all the CSS, including the ones we intend for older browsers. So if we set a width first on a CSS property for older browsers (let's say we're using display: inline-block
), and we intend to use grid on that same element for modern browsers, we would need to override that width property within the feature query because the modern browser will run everything. We have to be sure to 'cancel' out or undo the other CSS.
Look back at this example to see what what I'm talking about:
So double-edged sword, browser compatibility can be frustrating but I appreciate that everyone can still view web sites from 20 years ago and that this is one of the reasons the web is so special. I have had discussions with coworkers on why even jump to these newer methods so soon if we have to spend more time and write additional CSS to account for older browsers,
It's going to be personal preference as a developer - how much do you want to fit the site within the budget versus your long-term growth in web development. But that is the nature of the web development, things change constantly and it's hard to keep up with everything, but these CSS layout methods are so fundamentally different and better than the tools we've used before. As flexbox and grid continue to add new properties, the investment in learning these new methods will pay off and make the web better in the future.
If we use newer methods, we can:
- Keep up with web development field
- Build more complicated layouts more easily
- Make sites easier to maintain in the future
- Still maintain backwards compatibility for older browsers
Start using newer methods gradually and browser test components and you'll be on your way to awesome new designs.
More Information
- The New CSS Layout by Rachel Andrew
- Complete Guide to Flexbox: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
- Complete Guide to Grid: https://css-tricks.com/snippets/css/complete-guide-grid/
- What’s the Difference between Flex and Grid: https://css-tricks.com/quick-whats-the-difference-between-flexbox-and-grid/
- IE and grid: https://rachelandrew.co.uk/archives/2018/07/17/should-i-try-to-use-the-ie-version-of-grid-layout-revisited-for-2018/
- CSS Grid Layout and Progressive Enhancement
- Layout Land: https://www.youtube.com/watch?v=FEnRpy9Xfes&list=PLbSquHt1VCf1x_-1ytlVMT0AMwADlWtc1
- Resilient CSS series: https://www.youtube.com/watch?v=u00FY9vADfQ
Free Lessons and Tools
- Quick screencast videos: https://scrimba.com/
- Flexbox game: https://flexboxfroggy.com/
- Grid generator: https://cssgrid-generator.netlify.com/
Top comments (6)
Between tables and the float-based grid systems, there was also an age of layouts-by-positioning as pioneered by Wired.com. See Professional CSS: Cascading Style Sheets for Web Design for details.
Ah yes, I remember needing to modify a few absolutely-positioned sites years ago. Not fun.
This is extremely thorough, very well done. Love the interactions with codepen.
I'm still astonished these layouts took so long to arrive.
It's amazing how developers were able to get around this lack of layouts for so long.
You worked with what you had. It's not fundamentally different from the situation today. There's still plenty of styling things you can't do in CSS, and we work around those, or live with the inability, just the same. There was just less you could do in the past. So long as users can consume the content, the rest is just fluff.