There are a number of ways to build grids with HTML and css. Let's look at a few of the most common.
We're going to build four grids, each very visually similar, but using
different techniques. However, many of the styles will be
shared across all four grids, and therefore each grid will have
two classes: one that they all share (grid
)
and one that is specific to the technique (using-floats
,
using-inline-block
, using-flex
, or
using-grid
). Pay attention to the instructions, because some
rules will be applied using the shared class, and some with the specific
class!
table
element
Stop right there! Don't do it. While the
table
element does indeed produce a grid of
cells, its semantic purpose is actually to present data that is tabular,
like a spreadsheet of numbers. It is not intended to be
used as a layout tool for page content. It also handles
responsiveness (the ability of the page to adjust to the
width of the window on any device) poorly. So, we're skipping it!
It is possible to use the float property to create grids, and
it is perhaps the oldest technique for doing so.
We'll take a look at how it's done, but be advised that personally I
find other grid techniques to be friendlier, and I only use
float
when I actually need to wrap text around an
element.
Note that in this example and with others following, we'll use a
ul
element to represent the grid, and
li
elements for each cell in the grid. This is
because in most cases, a grid is conceptually a list that we're just
'presenting' in rows/columns because it's an effective way to
communicate small multiples of a thing — like portraits in a
yearbook. Semantically, those portraits are just an alphabetical list.
I've started a list below, with a single item. Let's begin by populating the HTML of our list. Don't be alarmed: The pictures are going to be huge. We'll take care of that in a minute when we add css.
li
element below to make a new
li
for eight people. You should end up with a
single ul
containing eight list items, each
item with a photo and name.
Okay, let's get these images under control so we can see what we're doing.
img
elements
inside .grid
. This is the shared class, so this rule will
apply to all of the grids we build.
width: 150px;
The images are now small, but the list-items are still displaying as a bulleted list. Let's override the default list styles.
.grid
class, and add the rule
padding: 0;
. This should remove default padding on the
ul
that wraps our grid.
li
elements within .grid
. Add
the rule display: block;
.
Bullets are gone, padding is gone, but our images are still not aligning
side-by-side. This is where float
comes in.
li
. Use .using-floats li
. We're
using the specific class because this rule applies
only to this grid. Set float: left;
.
WARNING: This is going to make the page look very broken. It's
okay, keep going... but this is why I don't like using
floats!
Our elements are now side-by-side, but $#!% went sideways. Remember why?
Everything following a floated element tries to wrap around it.
That's good, it's what's making our items go side-by-side... but we need
to clear the floated elements at the end of the grid. There is
a clever technique we can use to do this. We'll use the
::after
pseudo-element to insert an element at the
end of the list, and apply our clear: both;
rule to it.
.using-floats::after
.
content: "";
so the pseudo-element exists.
display: block;
. This makes pseudo-element
the width of its container, even though we cannot see it.
clear: both;
.
At this point, our grid starts to look like it makes sense. But lets
take a few more steps to tidy things up. We'll apply these rules using
the shared grid
class, so we don't have to do them again
for the next grid.
.grid li
and set the following
rules:
width: 25%;
Ensures our grid is "4-up" (25% * 4 = 100% of
the available width).
text-align: center;
Centers the image and name within
each box.
font-size: 0.8rem;
Makes the text a bit smaller.margin-bottom: 1rem;
Adds some space below each item.
img
, change
the width to width: 90%;
. This means "be 90% the width of
your parent." The parent li
is 25% of the total page
width. This ensures the image has a bit of space on either side within
its parent item, even on small devices.
We have a serviceable grid! But oh, so many steps to get here. There must be a better way, right?
We've discussed how some elements are inline elements and some
are block elements.You may have figured out by now that we can
control this behavior with the display
css property. Even
though a code
element (for instance) is
normally inline, we can force it to be a block element
with css like this: code { display: block; }
.
There exists a 'hybrid' of these two behaviors:
display: inline-block;
. Elements with this rule applied
will be styleable like blocks (all of the padding, margin, etc), but
will not expand automatically to fill the width of
their parent. Instead, they will only be wide enough to hold their
content, and more importantly, they will align themselves horizontally
like words, fitting themselves left-to-right until wrapping to a new
line. We can use this behavior to make a grid!
ul
grid from the previous
section, and paste it here, then change it's class list to be
class="grid using-inline-block"
. Note the space, it means
there are two classes on this element.
Look, we picked up a bunch of existing styles from the shared
grid
class, so our images are already sized, the text is
centered, etc. Hurray for shared classes to avoid repetition!
Let's start out like we did for floats, except this time, the
li
element will be
display: inline-block;
. Don't forget, we're styling a new
grid now, with a different specific class name, so you'll make a new set
of selectors to control styles specific to this grid, prefixed with
.using-inline-block
!
li
elements, set
display: inline-block;
. Be sure you aren't styling using
the shared .grid li
selector! Instead, what we're doing
here is overriding the existing rule with a new one.
This grid is shaping up fairly quickly, but there's one quirk. Our
shared styles say the li
elements should be
width: 25%;
... so why aren't they 4-up? The answer lies
with a rendering detail of inline-block
elements. Because
inline-block elements wrap like words, it turns out the browser
pays attention to the space character between these elements
in the HTML code — just like it pays attention to a
The solution is some creative css!
.using-inline-block
, and set
font-size: 0;
.
We've shrunk the space between the
li
elements to nothing, so we're back to a
perfect 25% × 4.
However: if we hadn't explicitly set a font-size for the
li
elements earlier (remember
font-size: 0.8rem;
?), our names would have disappeared
too, because they'd have inherited font-size: 0;
from the
surrounding ul
.
Try using the inspector to 'un-check' the font-size
style
rule for .grid li
and see for yourself.
flex
Flex Layout, or flexbox, is a very powerful collection of layout tools in css.This lesson will not even attempt to get into all the intricacies of flex layout, but we can at least scratch the surface by seeing how it can be used for simple grids like ours. If you want to dig deeper, the Complete Guide to Flexbox is a fantastic resource.
To demonstrate, let's copy our grid ul
once
again.
ul
grid from the previous
section, and paste it here, then change its class list to be
class="grid using-flex"
.
Again, our shared styles are already applied, because this
ul
has the shared grid
class. So
all we need to do are add the few specific rules for this technique.
display: flex;
flex-wrap: wrap;
A nice tidy grid once again! In previous methods, the critical rules for
making the grid were appled to the child elements, the
li
s. This time, we're applying a rule to the
parent element, the ul
. Flex layout can feel a
little strange at first because we control children indirectly through
rules applied to the parent container, but when you're used to it, it's
a very convenient and, uh, flexible (sorry) system.
(It's also the approach I normally use for grids myself.)
As with Flex layout, Grid layout is a very involved suite of tools, and we'll just use the most basic example here. For a complete reference, use the Complete Guide to Grid.
Let's copy our grid ul
a final time.
ul
grid from the previous
section, and paste it here, then change its class list to be
class="grid using-grid"
.
ul
using
it's specific class, and add the following rules:
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
The fr unit stands for fraction, so the above rule is instructing our grid to have four columns, each with an equal fraction of the available space.
You'll see that our images got tiny. Oops! In this case, our shared rule
setting the li
elements to be
width: 25%;
is working against us. Since the grid column
rule defines a conceptual parent 'column' in which each
li
resides, we can tell each
li
to be 100% of it's parent. We only want to
do this for this grid, so we will not modify the shared rule.
Instead, we will override it.
.using-grid li
, and set
width: 100%;
.
We are now back to having the images fill their column correctly, and our grid is complete!
That's the end of our grid examples (finally!), but it's worth
noting that an extremely important part of this whole lesson has been the
application of a shared class, in the grid
class. Doing so
helped avoid repititious work, it also helped avoid repetitous stylesheet
code. If you find yourself copying entire blocks of css code then only
changing the selector and one tiny detail in the ruleset,
you're doing it wrong. This is a prime use-case for a shared
class!