<div>
tags are an important building block for controlling the layout.
HTML5 introduced new semantic elements to help with this. And although they are a fantastic addition to the language, they are a bit like decorating our soup with
<div>
elements.
With the advent of CSS Grid, we no longer need to rely on
<div>
elements to create page structure or even more complex component. The structure is literally determined by the parent element, not by how the content is located inside it.
This means that we can get a nice simple layout that structures the content without paying attention to how it was originally organized using the
<div>
elements.
CSS Grid can be complicated, but Flexbox too
I have heard many people complain that the Grid is too complex and that Flexbox does the same job. I would say that they are just comfortable using Flexbox and therefore have no desire to learn more about CSS Grid.
CSS Grid technology does introduce a lot of new features and value, so yes, there is a learning curve. But Flexbox is also quite complicated.
Can you talk about the benefits of using the
flex-basis
property instead of
width
? Or how does Flexbox calculate the width of flex elements if we haven’t explicitly defined it?
For example, if you show the example below to someone who has never used Flexbox, how do you explain the fact that it has the same layout and styles for both sets of columns? To make matters worse, the second column in both cases is 50% wide. Obviously, a width of 50% does not actually set the element size to 50%.
“Well, it all starts with the fact that the elements are compressed if there is not enough space in the container, therefore, even if we set the element width = 50%, it does not have enough space, so it starts to compress to squeeze into the container, since the other
<div>
requires more space. 50% is more likely the ideal size for the block, but not the actual size. ”
“Thus, in the example above, the content of the first block is so large that it creates a problem, because, as a flex element, by default it tends to shrink to accommodate the content. In this example, this element has a lot of content, so ...
So yes, flexbox is great and does a great job of creating layouts, but please don't tell me it's simple. As soon as you move from ideal examples to work tasks, such behavior is often far from intuitive understanding, and sometimes it can be frankly strange.
A grid is complex because it entails many new properties and values, but they give us much more control than flexbox.
In this article, I would like to consider how this additional level of control helps simplify our markup and allows us to write less code, all without even having to learn how to use a number of its bizarre functions.
Flexbox Limitations
Even if we take a simple component and create it using flexbox, due to the fact that it acts only in 1 dimension (flex elements are either rows or columns, they cannot be both), we have a lot the number of elements used to create rows, which can then be divided into columns.
For example, if we are working on a card like this:
This is not a complicated layout, but we still need to organize our content in a rather specific way to make it work.
The yellow and orange blocks in this situation are needed so that when adding the display: flex property for the .card element (red block), two columns are created. Thus, to structure all the content, we get markup that looks something like this:
<div class="card"> <div class="profile-sidebar"> <!-- --> </div> <div class="profile-body"> <!-- , , --> </div> </div>
Once you understand how Flexbox works, understanding this structure will be easy.
When we add the
display: flex
property for the
.card
element, we get two columns, after which we will need to stylize each of them separately.
Here is a working example with all styles:
The fact is that when we create content columns, we get a little more complicated markup, and we also limit ourselves, as we force different parts of the content to group together.
Simplify everything with CSS Grid
Since CSS Grid is two-dimensional, it allows us to create rows and columns at the same time, which means that the grid container (to which we set the
display: grid
property) has full control over the layout within ourselves.
Previously, this required additional elements, as in the Flexbox example above. Using the Grid, we can completely get rid of them.
<div class="card"> <img src="https://i.pravatar.cc/125?image=3" alt="" class="profile-img"> <ul class="social-list"> ... </ul> <h2 class="profile-name">Ramsey Harper</h2> <p class="profile-position">Graphic Designer</p> <p class="profile-info">Lorem ipsum ...</p> </div>
From the point of view of markup, doesn't that make more sense?
There is an element with the class
.card
in which we put its immediate contents. We do not need to worry about the structure and layout of elements, we just put the content that we need and move on.
Structuring the layout
Just as when using Flexbox, we still need to structure the layout, although due to the specifics of the Grid, it looks a little different.
This is one of the situations in which people can argue that the Grid is more complicated, but in fact, I just draw blocks around each piece of content.
Using Flexbox, we created two blocks that stood out as columns. When using the Grid, instead, we configure the entire grid for the parent element, and then indicate to the child elements where to sit on this grid.
To set up the grid, we can do something like this:
.card { display: grid; grid-template-columns: 1fr 3fr; }
The fr unit of measure is unique to the Grid, and indicates the proportion of available space. This use is very similar to installing two columns in Flexbox and determining its widths of 25% and 75%, respectively.
Placing items on a grid
Perhaps due to the fact that for many years I used float to create markup, now situations in which elements are simply located exactly where they are needed seem like little magic.
You could use
grid-row
and
grid-column
for each element to place them exactly where we want, but the more I use Grid, the more I fall in love with the
grid-template-areas
property and place elements using area definitions.
This approach takes a little more time, but it is worth it, especially when we create an adaptive design (we will get to this soon).
First we need to define
grid-template-areas
for the
.card
element, after which we can assign all the child elements to these areas:
.card { ... display: grid; grid-template-columns: 1fr 3fr; grid-column-gap: 2em; grid-template-areas: "image name" "image position" "social description"; } .profile-name { grid-area: name; } .profile-position { grid-area: position; } .profile-info { grid-area: description; } .profile-img { grid-area: image; } .social-list { grid-area: social; }
In the example below, you can see all this in action:
It is so simple
One of the reasons I love to use
grid-template-areas
is that if someone else looks at the code, they will immediately understand what is happening ...
If someone shows you the code in which
grid-row
and
grid-column
are specified using numbers and
span
, it is quite simple to calculate and understand where and how they will be located elements. For simple layouts or for using span in some places, I consider their use appropriate, but much more pleasant, just looking only at the code of the parent element, immediately understand how the whole layout will look .
When using a Grid, it’s easier to know the actual size of an element
In our very first example, where we set the width of one of the flex elements = 50%, in fact it was not equal to 50%. If you understand why this happened, great, but sometimes it can still be annoying. This is easy enough to get around, but when using a Grid, it becomes a much smaller problem.
Since we define the whole layout, we also specify exactly how much space elements should occupy.
And of course, we have at our disposal the
minmax()
function and the units of measure
fr
, which stir up the water a bit, since they allow us to define sizes more flexibly (like the ones we use in the example above), but even then we still have full control over their flexibility, and all this is controlled by the parent, without the need to set some properties for the parent, and some for the children.
Limited Changes
If we look at the Flexbox example, we cannot make it look like the layout below without changing the HTML markup:
We limited ourselves to how we grouped elements together using a
<div>
. We had to use these
<div>
to make the layout work, but now it has become an obstacle for us.
With the children of our grid container located at the same level, you can do everything . And as an added bonus, since we configured everything using
grid-template-areas
, making these changes is very easy.
.card { /* grid-template-areas: "image name" "image position" "social description"; */ /* */ grid-template-areas: "image name" "image position" "image social" ". description"; }
Playing with
grid-template-areas
in this way, you can quickly and easily shift the icons of social networks to where we want to see them (the dot in the last part indicates an empty cell).
It makes life easier when working with media queries.
As I mentioned several times, this is the case when using
grid-template-areas
warranted. We can fully control our layout only using the properties of the parent:
.card { /* */ display: grid; grid-template-columns: 1fr 3fr; grid-column-gap: 2em; grid-template-areas: "name" "image" "social" "position" "description"; } .profile-name { grid-area: name;} .profile-position { grid-area: position; } .profile-info { grid-area: description; } .profile-img { grid-area: image; } .social-list { grid-area: social; } /* */ @media (min-width: 600px) { .card { text-align: left; grid-template-columns: 1fr 3fr; grid-template-areas: "image name" "image position" "social description"; } .profile-name::after { margin-left: 0; } }
CodePen below contains a fully styled example. You can study it, play with grid areas and see how easy it is to completely rebuild the layout.
Flexbox still has its own scope
I use Grid more and more, but I think Flexbox still has its own scope. If I have a logo and navigation located next to each other, it would be nice to have an easy way to do something like this and know that they will be where I want them to be:
.header { display: flex; justify-content: space-between; }
The same goes for the
<ul>
that we use for navigation, just to get the elements following each other, or, as you can see in the example with the card that we examined, it is ideal for
.social-list
.
For simple components where we don’t need a complicated layout, this really works well. But more and more, I notice a movement towards Grid, sometimes because of the obvious need for them, sometimes because I want to use the
minmax()
function or the units of measure
fr
.
But in the end, I think the best thing about Grid is the ability to greatly simplify our markup.
We are still forced to use the
<div>
, but thanks to the Grid, we can use them less and less.
In conclusion
No matter how good Flexbox is, it is no simpler than Grid. It really works great in certain situations, but when working with more complex layouts, the Grid allows us to have a lot more control. This control is enhanced while working with responsive design when making changes to media queries.
When using Flexbox, the greatest we can change is the
flex-direction
. Using the Grid, we can quickly and simply completely change the design of a component.
Both Flexbox and Grid have much more features. Each has its own purpose, but if you feel that you don’t know which approach to take, or you’re stuck trying to understand responsive design in general, I recently announced a course at Scrimba that goes deep into responsive design called The Responsive Web Design Bootcamp.