Hi, welcome to our CSS Layout & Responsive Layout guide.
If you are following our guides so far, by now you might be coming across a handful of fundamental issues regarding layout. Basic HTML and CSS is great if you want a simple site that presents one thing after the other, but how do you create something with more of a layout or landscape? And how does that layout change depending on what device you're on (big screen? laptop? tablet? mobile?) Anyway, if you are having a lot of issues with CSS now, don't worry⦠this guide digs into more details about the weirdness and intricacies of CSS.
Note that learning CSS layout and positioning is not intuitive and requires study, practice, and trial and error. So be patient, open up your web inspector, and have fun!
Note: our weekly guides aim to provide a general landscape ... an overall survey of whatβs most essential about the technology at hand and the basics of how to use it. From a technical or skill perspective, our guides are not exhaustive or thorough because there are already many other resources on the internet that are just that. We encourage you to check them out -- weβve linked some.
Every material has a grain.
Take wood for example. Wood grain generally means which orientation the wood fibers go. One of the most fundamental sayings of woodworking is to cut wood βwith the grainβ which helps improve the strength of whatever youβre creating.
In other words, itβs good to first understand your material so you can work with it, not against it. You can best collaborate with your material if you understand its inherent tendencies.
The idea that the web has a unique grain comes from Frank Chimero, in his piece The Webβs Grain from 2015.
I believe every material has a grain, including the web. But this assumption flies in the face of our expectations for technology. Too often, the internet is cast as a wide-open, infinitely malleable material.
So what is the grain of the web?
The web was first created as a way to share documents with anyone. Like we mentioned, many of the first people using the web to share documents were academics, or professors. Youβll see many of their sites are mostly text-based, with an image or two here and there.
Because the web was designed to present content in the form of documents, we believe the webβs grain is most easily visible the way text moves when you make the browser window a different size.
Try opening these three webpages and resizing them by making them wide and narrow, and seeing how the content is affected:
Text is inherently responsive. It goes with the flow. That's why so many old websites that are mostly text are surprisingly responsive by default.
But learning from the above examples, besides text, we can format other media so it goes with the flow, too. And maybe in general we should design how we read β¦ left to right, top to bottom...
More broadly, responsive web design is a specific approach that focuses on websites rendering well on a variety of different devices β from mobile to tablet to desktop. A variety of techniques are employed to do this, including media queries which we touch on later in this guide.
Generally speaking, itβs not good good practice to design a rigid system with specific breakpoints for every device. Instead, exercise flow and come to terms with the difference of screens sizes and preferences are radically different form person to person, era to era.
Responsive design is a fascinating field, and experiments like responsive logos show that it happens at even with the smallest details. Being able to present the essence of a thing even at a small scale could be seen as a type literacy.
Today in 2020, there are many ways you can lay items across your pages using CSS.
But layout hasn't always been easy. In the old days (90s and early 2000s), using <table>
was one of the best strategies at the time to do layout. But a lot has changed since then, and we would recommend not using <table>
unless you're displaying tabular data, like a spreadsheet.
Check out this site about web design history for more context.
Thankfully today, there are new CSS layout methods β like Flexbox (since 2013) and CSS Grid (since 2017), that make things much easier.
But itβs important to understand the other properties and methods as a basis since youβll likely use a combination of techniques to attain your desired result...
By default, each element (or βboxβ) in HTML is either an inline or block element.
Inline elements βgo with the flow.β If you put a lot of inline elements together, youβll notice them flow left to right like text.
Some classic inline elements:
img
β¦ imagea
β¦ linkspan
β¦ generic inline element
In this example, we started with a bunch of <span>
, a classic inline element. We colored them all different colors so we can see them!
View in new tab (try opening this and resizing it to watch the lines move!)
<span class="one">How would I define pebble?</span>
<span class="two">Itβs a bit tricky,</span>
<span class="three">but if I were to start by the way of description,</span>
<span class="four">I should say that pebble is something somewhere between rock and stone.</span>
<span class="five">The obvious defect of my definition is that I canβt stop there:</span>
<span class="six">I have to continue defining stones and rocks all the way back to the flood</span>
<span class="seven">and perhaps even further than that</span>
.one { background: lime; }
.two { background: yellow; }
.three { background: cyan; }
.four { background: pink; }
.five { background: goldenrod; }
.six { background: coral; }
.seven { background: cornflowerblue; }
.eight { background: silver; }
Block elements "stack one on top of anotherβ β¦ like blocks. If you put a lot of blocks together, youβll make a very tall page.
Some classic block elements:
h1, h2, h3, h4, h5, h6
β¦ all the headingsp
β¦ paragraphdiv
β¦ generic block element
In this example, we added one line of CSS that makes the <span> not display: inline
but display: block
instead. (If you want to change an element from block to inline or vice-versa, you can just override the default style with CSS.)
Now that the <span>
are blocks, notice how they now go one on top of each other ... like stacked blocks.
/* add this one line of CSS */
span { display: block; }
Some other important differences between inline
and block
:
height
or width
properties. Also, you shouldnβt put a block element inside an inline element.<br>
(line break).Here is a good site for seeing what the default display value (inline or block) of every HTML element is: htmlreference.io
***
But there is also the possibility for elements to become inline-block. When you set something to display: inline-block
, you essentially have the best of both worlds of block and inline. Things go in a flow (like inline), but they can take height
and width
properties (like block). Note that no elements are inline-block by default.
In the example, we changed the CSS so now <span>
is now display: inline-block
. Great! Now we have some blocks that go with the flow... indeed, the best of both worlds...
View in new tab (try resizing browser window)
/* added a few new lines here */
span {
display: inline-block;
height: 140px;
width: 140px;
vertical-align: top;
margin-bottom: 5px;
}
When you position things with inline-block
, you might also want to use the property vertical-align
as well. With vertical-align
you can align them in different ways, as we did here with vertical-align: top
.
***
This philosophy could continue onto a whole site's design. If we design the way we read, which is left to right, top to bottom, then maybe we put the header or title in the first block... and the footer in the last.
This way, when the page is viewed on mobile or small screens, it automatically works without having to do anything fancy. We are simply embracing the web's grain.
View in new tab (try resizing browser window)
<header>
<h1>βThe Pebbleβ (excerpt)</h1>
<p>by Francis Ponge</p>
</header>
<span class="one">How would I define pebble?</span>
<span class="two">Itβs a bit tricky,</span>
<span class="three">but if I were to start by the way of description,</span>
<span class="four">I should say that pebble is something somewhere between rock and stone.</span>
<span class="five">The obvious defect of my definition is that I canβt stop there:</span>
<span class="six">I have to continue defining stones and rocks all the way back to the flood</span>
<span class="seven">and perhaps even further than that</span>
<footer>
<a href="https://francispongeonlineanthology.wordpress.com/2017/08/10/pebble-a-fragment-of-a-text-of-francis-ponge-translated-by-vadim-bystritski/">Source</a>
</footer>
body {
text-align: center;
}
span,
header,
footer {
width: 200px;
height: 140px;
display: inline-block;
vertical-align: top;
margin-bottom: 5px;
text-align: left;
}
header {
background: palegoldenrod;
}
footer {
background: silver;
}
h1 {
margin: 0;
font-size: 1.5em;
}
The two properties display
and position
can do a lot of heavy lifting when it comes to CSS layout. Let's check them out...
We just looked at the common display values above.
But for the record, every element on a webpage is a rectangular box. (Remember the bookmarklet Boxify?) The display
property determines exactly how that rectangular box behaves.
display: block
β default (depending on element)display: inline
β default (depending on element)display: inline-block
display: none
β this makes the element visibly disappear, although it still appears in the source code***
Want to center something horizontally on your page?
The method you use actually depends on the display value of your element.
To center a block
element, you need to specify the element's height
and width
and also give it a margin left and right of auto
.
<!-- a div is a block element -->
<div class="quote">
from <i>Domestic PensΓ©es</i><br><br>
βA garden is not an object but a processβ<br><br>
Ian Hamilton Finlay (2004)
</div>
body {
background: black;
}
.quote {
width: 275px;
margin: 2em auto;
/*
the above line is shorthand for
top and bottom margins = 2em
left and right margins = auto
more on margin property here:
https://developer.mozilla.org/en-US/docs/Web/CSS/margin
*/
padding: 1.5em;
background: yellowgreen;
border: 4px double black;
border-radius: 25px;
}
To center an inline
or inline-block
element, the parent element (element the inline thing is inside of) should have text-align: center
declaration.
<figure class="image-container">
<!-- an img is an inline element -->
<img src="images/strawberry.png" alt="A large painted sign of a strawberry advertising strawberries on the roadside">
</figure>
.image-container {
text-align: center;
background: black;
padding: 1.5em;
}
To center something vertically, that's a bit trickier. You'll find that in the Flexbox section below.
The position
property can help you manipulate the location of an element.
position: static
β defaultposition: relative
position: absolute
position: fixed
When you use either position: absolute
or position: fixed
, know that youβre removing that element from the normal βflowβ of the web page. Itβs good to keep in mind, especially as you start to think about websites that can easily adapt to smaller or larger screens (βresponsive designβ).
When you use either position: absolute
or position: fixed
,
youβll need to then include specific declarations that specify where your element should be.
For example, here is a "sticker" that goes on top of our previous page. You will see in addition to having position: absolute
, it also has top: 8px
and right: 8px
. These declarations tell it exactly where to go relative to the browser window.
<div class="sticker"></div>
.sticker {
position: absolute;
top: 8px;
right: 8px;
height: 100px;
width: 100px;
border-radius: 50%;
background: rgb(63, 94, 251);
background: radial-gradient(
circle,
rgba(63, 94, 251, 1) 0%,
rgba(252, 70, 107, 1) 100%
);
}
Another important property that goes along with absolute
and fixed
positioning is z-index
. Here we made the z-index: -1
. z-index
accepts integer values and lets you layer things below or on top of each other.
.sticker {
z-index: -1;
}
The relative
position is good when you want something to be positioned absolutely in reference to its parent container...
.container {
width: 300px;
margin: 2em auto;
position: relative;
padding: 0.5em;
border: 1px solid gray;
}
Finally, this is an example where instead of absolute
we used fixed
, so the sticker stays in one place while the background moves when you scroll.
***
Here is an example of a layout using position: absolute
and percentage values. Note that you can make this layout many ways, and this is just one of many ways to make it.
<header>Fruitful Orchard</header>
<main>
Welcome to our fruitful orchard! Please select a fruit in the brown menu to get
started.
</main>
<aside>
Fruits
<ul>
<li>π Grapes</li>
<li>π Melon</li>
<li>π Watermelon</li>
<li>π Tangerine</li>
<li>π Lemon</li>
<li>π Banana</li>
<li>π Pineapple</li>
<li>π Apple (red)</li>
<li>π Apple (green)</li>
<li>π Pear</li>
<li>π Peach</li>
<li>π Cherries</li>
<li>π Strawberry</li>
<li>π₯ Kiwi</li>
<li>π₯₯ Coconut</li>
<li>π₯ Mango</li>
</ul>
</aside>
<footer>βπ―π½β― π»πππΎπ ππΎπ
β―ππ ππβ΄πππ, π·ππ π»πΆπππ πππΎπΈπππβ</footer>
header {
position: absolute;
top: 0;
left: 0;
right: 0;
background: yellow;
}
aside {
position: absolute;
right: 0;
bottom: 0;
top: 3em;
width: 30%;
overflow-y: scroll;
padding-bottom: 3em;
background: sienna;
}
main {
position: absolute;
left: 0;
bottom: 0;
top: 3em;
width: 70%;
background: lime;
}
footer {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: cyan;
}
header,
main,
aside,
footer {
padding: 1em;
}
header,
footer {
text-align: center;
}
In CSS, there are many different units you can use. When thinking responsively, it's good to remember there are certain units that might be better to use than others.
px
are the most straightforward and inflexible
%
are flexible and dependent on their parent container
em
are dependent on whatever font-size
the parent container is. This is a relative unit. So 2em
equals 2 * whatever the font-size
of the parent is.
rem
are dependent on whatever the font-size
of the body
are. So this unit is more global than em
, since if I want to change the overall scale, I simply change the body font-size
!
vh
and vw
stand for viewport height and viewport width, which are relative not to the parent container (like percentages) but the browser window (the viewport), so 100vh
means "100 percent of the viewport height"
Here is an interesting example website where the font-size
is using vw
. Try resizing this and see how the font automatically scales depending on your browser width.
There are other units, but these are the most common!
calc()
is a native CSS way to do simple math right in CSS as a replacement for any number value. Being able to do math in code is nice and a welcome addition to a language that is fairly number heavy.
It has four simple math operators:
+
-
*
/
And this math can be combined with any number of units. For example:
width: calc(100% / 12);
height: calc(100vh - 2em);
top: calc(400px - (10% + 2em));
Here are a couple use cases for calc().
The idea of βfloatsβ comes from print layouts, where text wraps around an image on either left or right. On the web in CSS, the property float
specifies that an element should be placed along the left or right side of its container, allowing text and inline elements to wrap around it. The element is removed from the normal flow of the web page, though still allowing other elements to wrap around it.
video.left {
float: left;
margin-right: 1em;
margin-top: 0.5em;
}
video.right {
float: right;
margin-left: 1em;
margin-top: 0.5em;
}
<video width="320" controls class="left">
<source src="stream1.mp4" type="video/mp4" />
</video>
<p>
In the last few years, websites and social media platforms have
introduced explore pages/tabs into their interfaces. Usually these are
just feeds masquerading as explore pages...
</p>
<video width="320" controls class="right">
<source src="stream2.mp4" type="video/mp4" />
</video>
<p>
When I worked at <a href="https://indp.co">The Creative Independent</a>,
we talked about creating an explore page, but we never got far enough
along on the idea to define what the page would actually look like...
</p>
Note that sometimes you will need to clear your floats. You can see this in action in this example (where we try to recreate the previous layout but using float):
body {
margin: 0;
}
header {
background: yellow;
}
aside {
float: right;
width: 30%;
overflow-y: scroll;
background: sienna;
}
main {
float: left;
width: 70%;
background: lime;
}
/* float is cleared for the footer */
/* as an experiment, try not having this clear and see what happens */
footer {
clear: both;
background: cyan;
}
(Since 2013)
Flexbox "aims at providing a more efficient way to lay out, align and distribute space among items in a container, even when their size is unknown and/or dynamic." Since it's still a newer technology, note that some older browsers don't support it. For more details, check out caniuse: flexbox.Some useful resources for flexbox:
body {
/* vertical centering ... works on any child element */
display: flex;
align-items: center;
justify-content: center;
/* horizontal centering ... makes all text centered */
text-align: center;
/* delete the default margin on body */
margin: 0;
/* colors */
background: black;
color: white;
/* responsive font size, 5% of viewport width */
font-size: 5vw;
/* by default body is as tall as its contents,
and since we don't have much (just a sentence),
we need to fill up body 100% viewport height */
height: 100vh;
}
<body>
<div class="sentence">Welcome to my world!</div>
</body>
There are multiple methods to vertically center an element in CSS, but we like using Flexbox for how simple it is. More info
<div> would definitely have to be my favorite element. I think it's so special. <div> is a little home for anyone and everything. And I love the CSS style of flexbox, and I love putting flex on divs. Itβs my fav.
Here is an example of how to make the previous layout using flexbox.
The only thing to note is Flexbox isn't great for complex layouts like this, so we had to add one "container" element to make the middle two elements (lime and brown boxes) be side-by-side rather than on top of each other.
<header>Fruitful Orchard</header>
<!-- this is the start of our new container -->
<div class="body-container">
<main>
Welcome to our fruitful orchard! Please select a fruit in the brown menu to get started.
</main>
<aside>
Fruits
<ul>
<li>π Grapes</li>
<li>π Melon</li>
<li>π Watermelon</li>
<li>π Tangerine</li>
<li>π Lemon</li>
<li>π Banana</li>
<li>π Pineapple</li>
<li>π Apple (red)</li>
<li>π Apple (green)</li>
<li>π Pear</li>
<li>π Peach</li>
<li>π Cherries</li>
<li>π Strawberry</li>
<li>π₯ Kiwi</li>
<li>π₯₯ Coconut</li>
<li>π₯ Mango</li>
</ul>
</aside>
<!-- this is the end of our new container -->
</div>
<footer>βπ―π½β― π»πππΎπ ππΎπ
β―ππ ππβ΄πππ, π·ππ π»πΆπππ πππΎπΈπππβ</footer>
body {
margin: 0;
display: flex;
flex-direction: column;
}
header {
background: yellow;
}
.body-container {
display: flex;
flex-direction: row;
}
aside {
overflow-y: scroll;
background: sienna;
width: 30%;
}
main {
background: lime;
width: 70%;
}
footer {
background: cyan;
}
However, one cool thing about flexbox (and CSS Grid, as you'll soon see) is that they were designed with responsiveness in mind. They are easily and powerfully paired with media queries.
The below code might not make sense yet, but essentially this media query says "When the browser is 768px or less wide, put the things that were side-by-side before as their own columns, and reverse their order, too!" Try resizing the example to a small width to see this in action.
@media screen and (max-width: 768px) {
aside,
main {
width: 100%;
}
.body-container {
flex-direction: column-reverse;
}
}
(Since 2017)
CSS Grid Layout is "a CSS layout method designed for the two-dimensional layout of items on a webpage or application." It allows for "complex responsive web design layouts more easily and consistently across browsers." Like Flexbox, it's still a newer technology, so some older browsers don't support it ... caniuse: grid.
Some useful resources for CSS grid:
Here is an example of how to make the previous layout using CSS Grid:
body {
margin: 0;
display: grid;
grid-template-columns: minmax(200px, 3fr) minmax(200px, 7fr);
grid-template-rows: min-content 1fr min-content;
height: 100vh;
}
header {
background: yellow;
grid-column: 1/-1;
}
aside {
grid-column: 2/2;
grid-row: 2/4;
overflow-y: scroll;
background: sienna;
}
main {
grid-column: 1/2;
background: lime;
}
footer {
grid-column: 1/-1;
background: cyan;
}
CSS Grid is very powerful but not the most intuitive. Explore the example links above for more info.
The following small lines of code help tremendously when considering and coding responsive websites.
***
Remember to not forget this line of code in the <head>
of your document:
<meta name="viewport" content="width=device-width,initial-scale=1.0">
Whenever a mobile device views the page, this line of code in the <head>
makes sure the device doesnβt automatically resize the page but lets it appear the size it automatically is. (If you don't have this line, you might notice that your website is automatically scaling down when you view it on a mobile device.)
***
img { max-width: 100%; }
This line of CSS is very useful. It says that all images should be 100% of their parent's width unless they are smaller than their parent, and in that case, they wouldn't expand to fill their parent but just be the size they naturally are.
<div class="large container">
<img src="images/strawberry.png">
</div>
<div class="medium container">
<img src="images/strawberry.png">
</div>
<div class="small container">
<img src="images/strawberry.png">
</div>
img { max-width: 100%; }
.large { width: 333px; }
.medium { width: 222px; }
.small { width: 111px; }
.container { float: left; }
***
article { max-width: 800px; }
It's smart to use max-width
, especially when dealing with blocks of text. In this previous example, the element article
(containing all the text) has this CSS. Try resizing the page and seeing how the text automatically flows when the browser width gets smaller. If you used width
instead of max-width
, this wouldn't happen.
Media queries are a type of CSS that allow content to adapt to various conditions. They are a fundamental technology of responsive web design. There is a lot of flexibility built into media queries β you can target specific screen widths, specific devices, or specific outputs (like print).
Here is an experimental example. Open this and try resizing your browser window to see what happens. Here is the CSS:
body {
background: red;
transition: background 300ms ease-in;
}
@media screen and (max-width: 768px) {
body {
background: yellow;
}
}
@media screen and (max-width: 600px) {
body {
background: lime;
}
}
@media screen and (max-width: 480px) {
body {
background: cyan;
}
}
@media screen and (max-width: 320px) {
body {
background: magenta;
}
}
Here is a more common example in which a menu changes for mobile use. Again, open this and try resizing your browser window to see what happens. Here is the HTML and CSS:
<nav>
<ul>
<li><a href="#">About</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Garden</a></li>
<li><a href="#">Thoughts</a></li>
<li><a href="#">Feelings</a></li>
</ul>
</nav>
nav {
text-align: center;
border-bottom: 1px solid black;
}
ul {
margin: 0;
padding: 0;
list-style-type: none;
}
li {
display: inline-block;
list-style-type: none;
margin: 0;
padding: 1em 0.5em 1.5em;
}
a {
color: black;
text-decoration: none;
}
a:hover {
background: yellow;
}
@media screen and (max-width: 420px) {
ul {
margin: 1em 0;
}
li {
display: block;
padding: 0.5em;
}
}
The media query at the bottom says βonly apply these styles within this media query if your browser's viewport width is equal to or narrower than 420px.β So looking at those media queries inside, we see that, for example, the li
is now display: block;
instead of display: inline-block;
as it was before. When it applies or the condition is true, the CSS within the media query overrides the other CSS.
Here is another website example. This time, instead of resizing the browser window, try printing the website and saving as a PDF. See if you notice any changes between the website and the PDF.
Here a fragment of that website's CSS:
@media print {
#keyboard-arrows {
display: none;
}
#side-column {
height: auto;
overflow:hidden;
}
#main-column {
width: 100%;
margin: 0;
height: auto;
position: relative;
}
li.current path {
fill: #000000 !important;
color: #000000 !important;
}
li:not(.current) {
display: none !important;
}
}
The above are overrides for when the website is printed. They are here so that the "next" arrow button doesn't appear on the printout or the side column doesn't appear, for instance.
When Laurel was first designing The Creative Independent's homepage, she decided on a strategy of using many elements that were display: inline
or display: inline-block
because the website was made to grow. She didn't know how many menu items there might be, so she wanted to create a flexible system.
***
So to start something like TCI's homepage, let's start with a sketch. You'll see there are boxes inside of boxes, or elements inside of elements. Classic nesting tendency of HTML... it's good to think this way.
After making the sketch (and thinking which things are inside of which things), you can go to code. Here is a simplified TCI homepage following the sketch. Feel free to check out the source code, and remember to try resizing the page! :)
Demo: Fruitful social media profile
Create a profile page for yourself on the "Fruitful Orchard," a hypothetical social media where all you do is show 10 pics from your camera roll. This is a good excuse to try some new things with CSS layout ... including responsive design (sizing down to mobile) if you're up for it, using media queries!
requirements:
Watch our demo video for reference:
Watch on YouTube John's profile code Laurel's profile code
When you're done, upload this file to your personal
demos/demo3/
folder in the portal.