Dropping CSS Frameworks for Grid and Flexbox
I changed my mind recently and decided to rework my website with Tailwind CSS and use its built in grid and flexbox properties. [2024-1-17]
I was developing in a world full of CSS hacks going back from 2000 to 2010. I was used to floating, inline-blocking and clearfixes to manage layout. I had tried to learn to use flexbox a few years ago, but it was when it was first introduced and most of the properties were browser-prefixed and didn’t always work consistently. So I just gave up and put down front-end development down for a while I waited for things to mature.
I avoided the pain by subscribing to the camps that used things like Bootstrap, Foundation and Skeleton. These were safe harbors where I could build applications quickly and focus on providing solid backends.
My interest was sparked again when I walked over to my coworker and asked him what he was working on. He showed me two tutorials of CSS grid and flex and gave me a quick proof-of-concept of what they both could do together and I was blown away.
I decided to build a page without a CSS framework only using grid and flexbox. I have to say that I am very pleased with how straightforward and simple it was to make a functional layout without worrying too much about the structure of my HTML.
What does a CSS grid and flexbox workflow for a fixed-width layout look like?
Here’s the HTML
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Test Grid Layouts</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<header>
<nav>
<div id="logo">Using Grid</div>
<ul>
<li><a href="#">About</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
</header>
<main>
<div class="content">
<section class="hero">
<h3>Color Me Black</h3>
</section>
<article>
<h1>Title</h1>
<p>I love content!</p>
</article>
</div>
</main>
<footer>
<nav>
<div class="siteinfo">Made by Angelo</div>
</nav>
</footer>
</div>
</body>
</html>
And the CSS
:
html, body {
margin: 0;
padding: 0;
height: 100%;
font-family: 'Roboto', 'Helvetica', sans-serif;
}
.container {
display: grid;
min-height: 100%;
grid-template-rows: 48px [stage] auto 48px;
grid-template-columns: 100%;
}
#logo {
color: #FFFFFF;
font-size: 1.5em;
}
header {
display: grid;
grid-template-columns: auto [head-center] 832px auto;
height: 48px;
background-color: #000000;
}
header > nav {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
grid-column-start: head-center;
grid-column-end: span 1;
}
header > nav ul {
margin: 0 0 0 auto;
}
header > nav ul li {
display: inline;
padding-left: 8px;
}
header > nav ul li a {
color: #FFFFFF;
text-decoration: none;
text-transform: uppercase;
}
header > nav ul li a:hover {
color: #AAAAAA;
}
main {
display: grid;
grid-template-columns: auto [main] 832px auto;
grid-template-rows: auto;
grid-row-start: stage;
grid-row-end: span 1;
}
main > div.content {
grid-column-start: main;
grid-column-end: span 1;
}
main > div.content .hero {
height: 300px;
width: 100%;
background-color: #000000;
color: #FFFFFF;
}
main > div.content .hero h3 {
padding: 16px;
}
footer {
display: grid;
grid-template-columns: auto [foot-center] 832px auto;
grid-template-rows: 48px;
background-color: #000000;
}
footer > nav {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-end;
align-items: center;
grid-column-start: foot-center;
grid-column-end: span 1;
}
footer > nav > .siteinfo {
color: #FFFFFF;
}
I have some other nifty things in here to make things look pleasant,
but we should really focus on where display: grid
and display: flex
is used.
The .container
element is our top-level grid:
.container {
display: grid;
min-height: 100%;
grid-template-rows: 48px [stage] auto 48px;
grid-template-columns: 100%;
}
Here, we use grid-template-rows
to define our top-level rows (from
top to bottom). These can be a fixed size, a percentage or
auto
. Each specification under the property is mapped to a child
item in the order of definition. For example, the first 48px
entry
is my first row, auto
(which is aliased to stage
) is my second
row, and 48px
is my final and last row. I’ve also specified that I
want the grid-template-columns
to expand the full width of my
container.
Now that I’ve done this, I have to think about the direct child elements that I create from that grid element because all the properties I applied are to the direct children of this parent element.
My child elements (my grid items) from this parent of .container
are
header
, main
and footer
. I define properties on these items to
tell them where they should go on the grid.
Let’s take a look at main
:
main {
display: grid;
grid-template-columns: auto [main] 832px auto;
grid-template-rows: auto;
grid-row-start: stage;
grid-row-end: span 1;
}
I’m doing several things here. I’m defining another grid under the
top-level .container
grid and I’m telling this grid item to start
where the stage
row begins and then extend (or span
) 1
cell
space down from it. If I had not aliased the starting row to stage
,
then I would have to count the number of rows down I would want to
start from and enter that number (in this case, it would have been
2
).
This is basically all there is to it. While this is not like the
HTML
To me, the two most important concepts to get are the parent element
where the
You can nest
While I used
For
So it’s best to get experimenting. Go ahead and copy the HTML
directly to a file and save it as
Assuming you have Python 3 installed and you have a unix shell
available you can serve these up:
Then open up a browser to http://localhost:8000 and start adjusting
CSS values using the built-in developer console in your browser or
edit the files directly on disk and hit refresh on the browser for
every change you want to make.
Also, try it with some of the mobile views. You’ll quickly see the
width is fixed. Can you make it work in a fluid or responsive way?
Here’s a hint: Look at the HTML and CSS of this blog site.
There are lots of things you can do with grid. You can throw in
media queries and you can make your layouts completely fluid if you
wish. Most modern browsers support grid and flex.
Take a look at the grid guide
and the flexbox guide or at the spec
itself to get more information
and most importantly – throw away your hacks! tag, it’s mental model of placement is very
similar. You can think of
colspan
and rowspan
working very much
like the span
property above.
grid
layout is defined and the child elements where each
“item” is defined. An item is a DOM element that is mapped as
content to a certain location in the grid.grid
to get more complex layouts. I did this so I
could extend the backgrounds of my header and footer across the width
of my page, but also maintain an “internal” grid on the main
element
where content would be centered with margins that have an automatic
width.grid
to manage the layout, I used flex
to manage
the positioning behavior of child elements within the layout. This
is not just vertical and horizontal positioning, but relative spacing
between children and even ordering. Flex is great at this sort of
thing and can (and has) been used for layouts, but in the end, it
starts to really feel hacky as your DOM gets more complex. So use
grid
if you are trying to design big picture components.grid
, there are also more things to think about like lines,
tracks, areas and cells. I’ve also made heavy use of aliases. These
are all things you should play with and understand.index.html
and then save the CSS
as styles.css
and plop them in a folder.$ cd YOUR_FOLDER
$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
In Summary
References