Give us a call
Drop us a message
To contact us, please fill out the form below, or email us at hello@cloudnc.com
One of the key challenges involved in laying out elements on a web page is to decide on the best approaches for positioning items. Whether it’s global navigation, tabular data or a thumbnail grid of images, we must consider the best techniques for our needs when laying out horizontal and vertical groups of elements. This approach should be reused across the site as a means to display content in the same way. In doing so, we create:
Before the days of Flexbox and CSS Grid, it was often tricky to implement design features such as vertical centring, equal height columns and sticky footers. Developers would be forced to create all sorts of workarounds and hacks to implement these features, often with exhaustive DOM traversing through JavaScript, which in turn brings its own complications. As time went on, such workarounds became unfavourable and developers needed more sophisticated methods of implementation. Thankfully, along came the introduction of Flexbox and CSS Grid.
On deciding whether or not to use Flexbox or CSS Grid, we must decide on which direction our content needs to flow. Flexbox and CSS Grid can position objects both horizontally and vertically, and it’s possible to combine the two. However, generally speaking it’s more straightforward to use only one.
The main question you should ask yourself is:
In which direction does my content need to flow?
If you have elements you need to position in one direction at a time, Flexbox is likely the preferred choice. With Flexbox, the browser will calculate things in one direction, ignoring the other direction.
Whereas if these elements form a kind of tabular or geometric layout in both directions (horizontally and vertically) simultaneously, then CSS Grid is likely going to be more appropriate. The browser calculates all elements’ positions with respect to one another, both horizontally and vertically.
We can demonstrate both in a simple example.
We have a container which holds five child elements, each of which have internal flex properties to alter their behaviour using flex-grow
and flex-shrink
from an initial flex-basis
value (flex: 1 1 200px
is shorthand for: flex-grow: 1; flex-shrink: 1; flex-basis: 200px
). We also enable flex-wrap to ensure that once the flex items reach the maximum size of the container, they will wrap on to a new row.
HTML:
<div class="c-container">
<div class="e-element">One</div>
<div class="e-element">Two</div>
<div class="e-element">Three</div>
<div class="e-element">Four</div>
<div class="e-element">Five</div>
</div>
CSS:
.c-container {
display: flex;
flex-wrap: wrap;
}
.c-container > div {
flex: 1 1 200px;
padding: 20px;
background: #56e499;
border: 1px solid teal;
border-radius: 8px;
}
We can see two of the items (“Four” and “Five”) have wrapped on to the row underneath, because we set flex-wrap: wrap
. Consequently, they form a “new” flex container (the whole width of a new row) and fill up all the available space in that row. Remember, flexed items will always try to take up the entire available space along a row (or column) unless you tell them not to. If we didn’t have flex: wrap
set, the items would fill the entire width of the first row only.
Suppose we want to align items “Four” and “Five” with “One” and “Two”, leaving an empty space in the bottom right. Like so:
This is still possible using Flexbox. In actual fact, here, we simply set a max-width
on each flexed item, which Flexbox will respect. However, we can achieve this more elegantly with CSS Grid. Given this would be laid out across two dimensions, not one, CSS Grid makes this possible with ease.
With CSS Grid, we can use a flexible unit fr
to position elements into available grid spaces. Fr
is a fractional unit, whereby 1fr
represents one cell of the available grid. Elements within the grid are placed into grid areas.
In this example, we can create the same layout using CSS Grid. We declare three columns with 1fr
column tracks. The items automatically position themselves according to where we tell them to go from the parent level. We can see they remain in a geometric grid consisting of rows and columns. Note our HTML does not change:
HTML:
<div class="c-container">
<div class="e-element">One</div>
<div class="e-element">Two</div>
<div class="e-element">Three</div>
<div class="e-element">Four</div>
<div class="e-element">Five</div>
</div>
CSS:
.c-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
Besides thinking as to whether we want our content to flow in one direction or two directions, another factor in helping us to decide which approach is most suitable is what the content is itself, the importance of alignment, and whether the content’s size will change from element to element.
Flexbox works from the element’s perspective outwards, i.e. we have elements in a container, which must be spaced out evenly, but are not all guaranteed to be of equal size and therefore will not necessarily align with each other, row by row or column by column. If the elements wrap on to a new row or column, they will calculate their position and spacing only in accordance with that row or column.
CSS Grid works from the outer container inwards. If you have fixed elements of equal size, and are concerned about the alignment of the elements as a whole, CSS Grid is likely the most appropriate.
Gone are the days of alignment hacks and workarounds, where for years, implementing a design feature that seems simple proved otherwise. Vertical centring, content reordering and equal height columns were once so much more difficult than we realised. Flexbox made these problems disappear, and nowadays it’s easier than ever to implement these kinds of design features.
We can demonstrate Flexbox’s alignment controls quite simply. Take a look at the following example:
HTML:
<div class="c-container">
<div class="e-element">One</div>
<div class="e-element">Two</div>
<div class="e-element">Three</div>
</div>
CSS:
.c-container {
display: flex;
align-items: flex-end;
min-height: 200px;
}
.c-container > div {
padding: 20px;
background: #56e499;
border: 1px solid teal;
border-radius: 8px;
}
.c-container > div:nth-child(1) {
align-self: stretch;
}
.c-container > div:nth-child(2) {
align-self: flex-start;
}
We can take note of two properties that Flexbox provides us: align-items
and align-self
.
The first, align-items
, provides us with the ability to align all elements to a certain point horizontally within a flexed container, i.e. along either a row or a column. We initially set each item’s alignment to flex-end
, i.e. the bottom of the container (equivalently, this would be the right hand side of the container if we were flexing vertically in a column). However, if we want, we have the ability to override this behaviour using the nth-child pseudo class, which can often come in handy when dealing with dynamic elements, such as a container containing an unknown number of elements.
If we apply stretch
behaviour to the first nth-child “One”, we see this aligns to both the top and bottom of its parent container. This would be a really clever use case for achieving equal height columns, whereby the widest or tallest element within such a group would dictate the width or the height of the flexed container.
In addition, flex-start
provides us with the ability to align items to the top of the container, as shown in the second nth-child position “Two”.
The third “Three” nth-child position doesn’t have a CSS rule defined, so instead listens to the align-items
property set on the .c-container
div, as this is inherited by immediate children of flexed items. In fact, it’s important to note that all immediate descendants of containers with display: flex
will always inherit the flex
property. Subsequently, this can be useful when wanting to construct nested layouts consisting of many containers, but it’s important to always consider the use case and maintain code rigidity if containers are added or removed (either manually or via DOM manipulation).
With CSS Grid, we can achieve the same layout. In this case, we allocate each item in the grid to a grid area, rather than letting the items dictate where they go (moreso the case with Flexbox).
CSS:
.c-container {
display: grid;
grid-template-columns: repeat(3,1fr);
align-items: end;
grid-auto-rows: 200px;
}
.c-container > div {
padding: 20px;
background: #56e499;
border: 1px solid teal;
border-radius: 8px;
}
.c-container > div:nth-child(1) {
align-self: stretch;
}
.c-container > div:nth-child(2) {
align-self: start;
}
The way the items align with one another is rather quite different. With Flexbox, elements position themselves freely unless we code them to be spaced out in a particular way, or assign them a max-width
value. Additionally, the container or viewport width (if defined along a row) or height (defined in a column) will dictate how the items wrap. In our earlier example, we saw our five flexed items wrap along two rows, with three items distributed along the first row, and two items distributed along the second. This meant that the items didn’t line up, since flexed items will always be as wide as they can be to fill up the available space.
Contrastingly with CSS Grid, items will always conform to the specific number of rows or columns that we define when we set up the grid, irrespective of how wide or tall the container or viewport is. CSS Grid is much more like a table, whose elements will always be positioned within the grid cells (fr
).
Note that with both Flexbox and CSS Grid, it’s possible to position our elements regardless of their size. CSS Grid has the advantage here of overlapping content, where by grid cells can be told to be a certain size and will be that size even if it causes an overlap in content. Overlapping is not possible with Flexbox, since items will always position themselves adjacent to one another.
This article has covered some of the basic concepts of Flexbox and CSS Grid. Each have their pros and cons in terms of how they align and distribute content across rows and columns, and each have their own use cases, albeit with some overlap since each have shared possibilities.
Jen Simmons provides a useful and easy to understand video on the fundamentals of Flexbox and CSS Grid. Personally, I find her presentation style simple to grasp and visualise: https://www.youtube.com/watch?v=hs3piaN4b5I
The following resource demonstrates examples that use some other features of CSS Grid, for example the minmax() function, cell ordering and grid area assignment. We can see how other functions of CSS Grid can be utilised such as auto-fill, auto-fit and the possibilities for nested grids: https://gridbyexample.com/examples
Fancy a challenge? The following game will help you to learn the basics of Flexbox, by using align and distribution properties to help frogs land on to lily pads: https://flexboxfroggy.com/ .