CSS Layout
tutorial html cssNow you know how to use HTML to create webpage content, and you know how to use CSS to style that content.
This tutorial talks about different ways to position elements in your page.
Divs
By now, you’ve probably seen HTML tags that specify different kinds of content, like <h1>
and <p>
. There’s another HTML tag that’s especially handy for creating layouts: the <div>
tag! If you’re new to HTML and CSS, you might not have used it much, so here’s a quick intro.
The <div>
tag represents a division of content. It lets you group other tags together into sections, and you can style those sections using CSS. Here’s an example:
This code creates a yellow div that contains some content, including two other divs. The red div contains some text, and the blue div contains other HTML tags.
There are other HTML tags related to layout, like <main>
and <article>
, but <div>
is the one you’ll see most often.
By default, divs are shown on their own line, so multiple divs will show up on top of each other. The rest of this tutorial talks about how to change that default behavior.
Brief History
CSS has a few different ways to position elements, and I’ve personally found it really confusing to have so many options to choose from. Should I use floats? Or inline blocks? Or both? Or neither?? I found that understanding the history of CSS has helped me understand CSS itself much better. So let’s run through a brief history of layouts in CSS.
HTML was released around 1993. In the early days of web development, there was no such thing as CSS! Styling was done with HTML tags like <center>
and with attributes like color
(as in <font color="red">
). Layout was done using HTML <table>
elements, which let you place content into a grid.
Tables
For example, to create a webpage with a left nav and a content section, here’s how you might have done it before CSS:
Using tables for layout might work, but it’s generally considered a bad idea. It’s harder to maintain, and it doesn’t work well with screen readers. I’m including this example here to provide historic context, but nowadays you shouldn’t use tables for layout.
CSS 1
The first version of CSS was released in 1996, and it mostly dealt with styling text content: stuff like fonts and colors, not layout. Positioning elements was still done using HTML tables.
HTML 3.2 was released in 1997, and it included the <div>
tag.
CSS 2
Then CSS 2 was released in 1998, and it included rules for positioning content. For example, you could set the float
property of an element to left
or right
so that it displayed to the left or right of other elements, and you could set the display
property of an element to block
or inline-block
to change how other elements were laid out around it. You could also set the position of an element manually if you really wanted to.
Floats
Here’s how you’d create the left nav using floats:
Floats are still commonly used in CSS layouts, although they come with a few downsides. The browser treats floated elements as if they take up no space- that’s why the content div has a left margin. Try removing that style to see what happens. Then try adding a footer to the page to see why floats can be tricky to work with.
Blocks
And here’s how you might do it with inline blocks:
Like floats, inline blocks are also still used in CSS layouts, but they also have their own downsides. For example, browsers will wrap an inline block onto the next line if the content gets too wide. Try adding some long text to the content div and then making your browser less wide to see what I mean!
Flexbox
After CSS 2, the history of CSS gets pretty complicated, mostly because CSS was split into a bunch of different modules with their own histories. But long story short, CSS 3 was built on top of CSS 2, and one of the features added to CSS 3 was flexbox in 2017.
Flexbox lets you define the relationships between parent elements and child elements. By itself that might not sound very useful, but it’s an extremely powerful tool when you’re trying to position a bunch of content in your page. For example, with flexbox you can tell the browser to display several elements in a row, and you can give every child element different rules about how to size themselves. And the browser does the rest of the work for you!
To use flexbox, set display: flex
on a parent element (an element that contains other elements), and then set other flex properties on both the parent and child elements to customize your layout.
For example, here’s the above left nav example, this time using flexbox:
Flex Properties
To use flexbox, set display: flex
on a parent element (an element that contains other elements), and then set other flex properties on both the parent and child elements to customize your layout.
Here are a few common flex properties:
display: flex
This is the property that kicks it all off. Set this on a parent element (often a div) to tell it to use flex rules to lay out its children (the elements it contains).
.container {
display: flex;
}
flex-direction
By default, flex containers (elements with display: flex
) lay out their children in a row. You can set the flex-direction
property to column
to change this.
.container {
display: flex;
flex-direction: column;
}
flex-wrap
By default, flex containers lay out their children in a single row or column. If the container contains more elements than will fit into a single line, then those elements get smooshed.
To wrap child elements instead of smooshing them, set flex-wrap
to wrap
.
.container {
display: flex;
flex-wrap: wrap;
}
The default value is nowrap
.
For flex containers with wrapped children, you can also set the align-content
property to specify the spacing of the wrapped content.
justify-content
By default, flex containers lay out their children starting at the far left (or top for containers with flex-direction:column
) without any space between them.
To change how children are spaced, set the justify-content
property.
.container {
display: flex;
justify-content: space-around;
}
There are a few values to choose from:
-
flex-start
is the default -
center
puts children in the center, with no space between them -
space-between
adds space between the children, but not before the first item or after the last item -
space-around
adds space between the children, including before the first item and after the last item -
space-evenly
adds space between the children, and makes it so the first and last item have the same space as middle children
Try changing this code to see the difference:
align-items
By default, flex containers align their children to the top (or to the left for containers with flex-direction:column
) and set their height (or width) to fill the remaining space.
To change how children are aligned, set the align-items
property.
.container {
display: flex;
align-items: center;
}
There are a few options to choose from:
-
stretch
is the default -
flex-start
aligns children to the top (or to the left for containers withflex-direction:column
) but does not stretch them to fill the remaining space -
flex-end
aligns children to the bottom (or right) but does not stretch them to fill the remaining space -
center
aligns children to the center
Try changing this code to see the difference:
gap
By default, flex containers do not add any spacing between their children. You can change that with justify-content
, align-items
, and align-content
. You can also manually set the gap
property.
.container {
display: flex;
gap: 25px;
}
flex-grow
By default, elements inside flex containers will not expand to fill extra space in the container.
You can tell an element to fill any extra space using the flex-grow
property.
.container {
display: flex;
}
.child {
flex-grow: 1;
}
The flex-grow
property takes a number, which represents how much that child will grow compared to its siblings.
That’s a little confusing, so here’s an example:
In this example, the .red
class has the default flex-grow
value of 0
, which means it does not grow at all. Then the .blue
and .green
classes have flex-grow
values of 1
and 2
respectively, which means that .green
will grow twice as much as .blue
.
Try changing the code to see the effect of different values.
flex-shrink
By default, if a flex container is not wide enough (or tall enough for containers with flex-direction:column
) to fit all of its child elements, then those child elements all shrink equally.
To have different child elements shrink at different rates, set their flex-shrink
property.
.container {
display: flex;
}
.child {
flex-shrink: 2;
}
This is similar to flex-grow
in that the value is a number that represents how much a child will shrink compared to its siblings. The default is 1
, but you can set it to 0
to never shrink, or to a higher number to shrink it more.
flex-basis
By default, elements inside flex containers set their own sizes, either through the width
and height
properties or from their content.
Instead of relying on an element’s own size, you can set its initial size using the flex-basis
property.
.container {
display: flex;
}
.child {
flex-basis: 200px;
}
flex
The power of flex-grow
, flex-shrink
, and flex-basis
might not be obvious. Why should you use those instead of setting the width
and height
properties?
There are a couple reasons:
- You won’t always know the size of the user’s browser window. Will they be on a laptop? On a widescreen monitor? On a phone? Making sure your content fits on every screen is really hard!
- You won’t always know the size of your own content. That might sound surprising, but do you want to adjust the widths of every element on your page whenever your content changes? This is especially true if you’re fetching content from other places (like an API, or a backend) instead of writing it yourself.
With flexbox, you can set the flex-grow
, flex-shrink
, and flex-basis
properties to tell your content how to lay itself out. What should grow when it’s viewed on a widescreen monitor? What should shrink when it’s viewed on a phone? What size should everything be by default, before the growing and shrinking?
In fact, these three properties are so useful that you can combine them into a single property named flex
.
So if you have this CSS:
.child {
flex-grow: 1;
flex-shrink: 2;
flex-basis: 300px;
}
You can shorten it to this:
.child {
flex: 1 2 300px;
}
To understand why this is useful, try changing the width of the parent div in this example:
(It might help to view the fullscreen version.)
The children all start out at certain sizes, thanks to their flex-basis
properties.
When you make the parent div bigger, the red child does not grow at all, because its flex-grow
is 0
. The green child grows faster than the blue child, because their flex-grow
properties are 2
and 1
.
When you make the parent div smaller, the red child shrinks faster than the blue child, because their flex-shrink
properties are 2
and 1
. The green child doesn’t shrink at all, because its flex-shrink
is 0
.
This means you can set these properties and then not worry about the exact size of your content, or the exact size of the user’s browser window.
Learning More
We covered the fundamentals of flexbox above, but there are other properties and values you can use. To learn more about them, check out A Complete Guide to Flexbox on CSS Tricks.
And of course, don’t be afraid to search the internet when you’re not sure about something. There are plenty of great resources out there!
Grid
Flexbox is most useful when you have a single row (or column) of content. Flexbox containers can wrap their content into multiple rows (or columns) using the flex-wrap
property, but you don’t have much control over the alignment of those items.
That’s probably okay for many layouts, but if you want more control over how your elements are positioned, you can use the grid layout.
To put grid layout in historical context, technically it hasn’t officially been released yet, but as of 2022 almost every browser already supports it anyway. CSS is weird!
Here’s the above left nav example using Grid:
Grid Properties
To use grid, set display: grid
on a parent element, and then set other grid properties on both the parent and child elements to customize your layout.
display: grid
This is the property that kicks it all off. Set this on a parent element (often a div) to tell it to use grid rules to lay out its children (the elements it contains).
.container {
display: grid;
}
By itself, that’s not very interesting, because by default a grid is a single column of elements.
grid-template-columns
By default, a grid is a single column of elements.
To split your grid into multiple columns, use the grid-template-columns
property.
.container {
display: grid;
grid-template-columns: 100px 1fr 2fr;
}
The grid-template-columns
property takes a space-separate list of sizes, and will lay out the content in that many columns, with those sizes.
The sizes can be a few different kinds of values:
- Specific lengths like
100px
or10em
that give the column a predefined width. - Percentage lengths like
50%
that tell the column to take up that percent of the parent’s width. - Fraction lengths like
1fr
or2fr
that tell the column to take up a width relative to the other columns in the grid. You can think of this as similar to howflex-grow
worked above: a column with2fr
will take up roughly twice as much width as a column with1fr
. -
auto
tells the column to size itself based on the elements in it, as well as the size of the container and of the other columns in the container.
See grid-template-columns on MDN for other kinds of values.
The above example of grid-template-columns: 100px 1fr 2fr
creates three columns: one that’s 100px
wide, and then a middle column that will take up about half the width of the third column.
grid-template-rows
Similar to grid-template-columns
, grid-template-rows
lets you specify the heights of each row.
By defining both grid-template-columns
and grid-template-rows
, you can create a grid of content!
.container {
display: grid;
grid-template-columns: 1fr 2fr;
grid-template-rows : 100px 50px 100px;
}
Try changing this code so it has 3 columns and 2 rows instead!
Placing Items in the Grid
By default, items take up one cell in their parent grid, and they appear in the order that you list them in your HTML.
You can make an element take up more than one cell using these properties:
-
grid-column-start
andgrid-column-end
tell a cell which columns to occupy -
grid-row-start
andgrid-row-end
tell a cell which rows to occupy
.container {
display: grid;
grid-template-columns: 1fr 2fr;
grid-template-rows : 100px 50px 100px;
}
.child {
grid-column-start: 1;
grid-column-end: 3;
}
.other-child {
grid-row-start: 2;
grid-row-end: 4;
}
Here’s an example:
The red div starts at column 1 and goes until column 3, so it takes up both columns. The green div starts at row 2 and goes until row 4, so it takes up rows 2 and 3.
Also notice that the green div appears before the blue div, even though it comes after in the HTML. This can be handy for making sure your main content is first in your HTML, which can help with things like screen readers and SEO.
You can also use the grid-column
and grid-row
shorthand:
.container {
display: grid;
grid-template-columns: 1fr 2fr;
grid-template-rows : 100px 50px 100px;
}
.child {
grid-column: 1 / 3;
}
.other-child {
grid-row: 2 / 4;
}
Named Cells
The above examples use numbers to specify which cells an element occupies.
You can instead name your cells, and then specify element locations using those names.
First, add names to your container columns and rows using []
square brackets:
.container {
display: grid;
grid-template-columns: [left] 1fr 2fr [right];
grid-template-rows : 100px [middle] 50px 100px [bottom];
}
You’re actually naming the lines between cells. This is the same CSS as above, except now a few of the lines between cells have names.
Then, use those names to place your child elements:
.red {
background-color: red;
grid-column-start: left;
grid-column-end: right;
/* Could be shortened to grid-column: left / right; */
}
.green {
background-color: lime;
grid-row-start: middle;
grid-row-end: bottom;
/* Could be shortened to grid-row: middle / bottom; */
}
Here’s the full code:
Other Grid Properties
Grid has many other properties, and shortcuts for writing fewer lines of code. Rather than trying to list them all here, I encourage you to read through A Complete Guide to Grid on CSS Tricks, CSS Grid Layout on W3Schools, and CSS Grid Layout on MDN.
More importantly, I encourage you to try stuff out! If you want to experiment with grid layout (or flexbox, or anything really) then the best thing you can do is create a scratch file or a CodePen project and try it out! Get something working, and then see if there are other ways to write your code.
The Holy Grail Layout
One particular layout is so popular that they gave it a name: the holy grail.
The holy grail layout is a website that has a header, a left sidebar, a main content area, a right sidebar, and a footer. You can probably name a few websites that use this layout.
Here are a couple examples of the holy grail layout:
Using flexbox:
Using grid:
If you want a challenge, and if you want to understand what makes flexbox and grid so popular, try implementing the holy grail layout only using floats or blocks!
Nesting Layouts
I’ve listed a few approaches to creating layouts above, but you don’t have to choose just one! In fact, most websites use a combination of all of the above.
For example, you might use grid to create your outermost layout that positions a header, a sidebar, the main content, and a footer. Your header might use flexbox to create a row of navigation links. The main content might contain images that are floated to the left or right.
Try thinking about each section of your page as its own layout, and then use whichever tools make the most sense for that specific section.
Responsive Design
Making sure your website works on everybody’s monitor has been a big part of layout and design, ever since the early days of HTML.
But this became even more challenging in the late 2000s and early 2010s, as cell phones became more popular for browsing the web. How do you make sure your website looks good on a tiny cell phone, a widescreen monitor, and everything in between?
One popular way to think about it is responsive design. Responsive design is the idea that your website should respond to changes in the screen size. Maybe your page only shows the main content on narrow devices, but adds a left sidebar on medium-sized devices, and splits the content into multiple columns on widescreen devices.
Mobile-First Design and Progressive Enhancement
Responsive design means that you show a different layout on different screen sizes. You might think of this as hiding parts of your website on smaller screens, but another way to think about it is that smaller screens contain all of the essential content, and larger screens show “extra” content that’s not strictly required.
Starting your design by thinking in terms of small screens is called mobile-first design, and thinking in terms of adding additional features to wider screens is called progressive enhancement.
These are a little buzzword-y, but I do find them helpful in thinking about how to design the layout of a webpage.
You can read more about responsive design on at Responsive design - MDN and Responsive web design - Wikipedia.
To show a different layout depending on the screen size, you can use a CSS feature called media queries.
A media query uses the @media
keyword, then a media type (you probably want screen
, but you can also customize what your website looks printed out with print
), then a media feature that lets you set up rules for different kinds of displays. Then inside { }
curly braces, you put any rules you want to apply to your query. Here’s an example:
(It might help to view the fullscreen version.)
By default, the .content
class has a thin solid black border and a cyan background. But on screens that are wider than 700 pixels, the .content
class will have a lime background. Because we aren’t changing the border on wide screens, it maintains the thin solid black default.
Here’s a more complex example that displays content in a single column by default, and in the holy grail layout on devices wider than 500 pixels:
(It might help to view the fullscreen version.)
This example also completely hides the left sidebar on mobile.
See the Beginner’s guide to media queries on MDN and CSS @media Rule on W3Schools for more info.
When you’re creating and debugging layouts in CSS, your best friend is your browser’s developer tools! They can help you understand why things are aligning a certain way, or where that extra few pixels of space is coming from.
You can even use device mode to see what your webpage looks like on different devices. This is much easier than constantly resizing your window!
Learn More
Here are a few resources to help you learn more about layouts in CSS:
Comments and Questions
Happy Coding is a community of folks just like you learning about coding. Do you have a comment or question? Post it here!
Read the full article on Happy Coding at https://happycoding.io/tutorials/html/layout Replies to this post will show as comments on the original article!