Add a little flexibility to your layouts
Flexbox is a mighty little CSS layout model that allows for flexible (hence it's name) one-dimensional layouts. Where items of a flex container can be laid out, aligned and distributed in a single direction either horizontally or vertically along the main primary axis, even when the size of the items are unknown or can change.
But to start with we need to make our parent element a flex container:
body {
display: flex;
}
Within a Flex container the Primary axis controls the direction that flex items stack, also where the stack will start and end. The Cross axis then runs perpendicular to it and controls the direction the flex items will stretch to fill the Flex container.
Once we grasp this simple rule of Flexbox where everything is based around the primary axis and cross axis, we can then start to understand how to control and switch our layout directions.
flex-direction
The direction of flex items can be controlled by changing the default flex direction of the primary axis from left to right, to top to bottom. This will change your flex items from being stacked horizontally in a row side by side, to being stacked vertically on top of each other in a column. We can do this using the flex-direction property and adding either the value row or column.
We can also change the start and end points of items within the Flex container by reversing them along the primary axis too. We should point out that the default direction of a flex container is row, so unless you are needing to override something else it's not necessary to state this.
body {
display: flex;
flex-direction: column; /* row (default direction) - row-reverse - column-reverse */
}
Alignment
Flexbox has several properties that allow us to distribute our flex items within our container, though depending on which axis you are wanting to control items on, will determine what properties you use and how they behave, plus whether you target the flex container or the flex item.
Primary axis
Along the primary axis we control items as a group rather than as individual items, whilst evenly distributing the remaining free container space around, between or next to them.
.flex_container {
justify-content: flex-start;
}
By targeting the flex container we can move the group along this axis using the property justify-content and the values:
flex-start (start): items are grouped at the start of the primary axis.center: items are centered on the primary axis.flex-end (end): items are grouped at the end of the primary axis.
Or we can space out the group along this axis using the values:
space-between: items are evenly distributed along the primary axis, first item at the start, last item at the end.space-around: items are evenly distributed along the primary axis with equal space around each one. Visually the space around and between the items will be different. As the first and last item will have one unit of space against the containers edge, but two units of space between it and the next item, because that next item has its own spacing too.space-evenly: items are evenly distributed along the primary axis with equal space between each item and the containers edges.
Cross axis
When we come to items on the cross axis we can either control them individually or as a group, as each item is on its own axis.
.flex_container {
align-items: flex-start;
}
To move them as a group we target the flex container using the property align-items with the values:
flex-start (start): items are placed at the start of the cross axis.center: items are centered on the cross-axis.flex-end (end): items are placed at the end of the cross axis.stretch (default): items stretch to fill the container (still respect min-width/max-width).baseline: aligns the items so that their baselines match. ("baseline" refers to the line upon which most text sits, if a flex item contains text or inline elements, this ensures that the text of all items is lined up along their respective baselines, even if the items have different heights).
Or to move items individually we target the flex item its self using the property align-self with the same above values like this:
.flex_item {
align-self: flex-start;
}
Wrapping
We know that flex items will stack along the primary axis but if the container element doesn't have enough space to fit them all, then we can make them wrap around onto another row or column by using the flex-wrap property with the values of:
nowrap (default): all flex items will be on one line.wrap: flex items will wrap onto multiple lines, from top to bottom.wrap-reverse (end): flex items will wrap onto multiple lines from bottom to top.
.container {
flex-wrap: nowrap; /* wrap - wrap-reverse */
}
Size isn't everything
We already mentioned that a flex container (parent element) can flexibly lay out, aligned and distribute flex items (child elements) even when the size of those items is unknown, because flexbox allows the flex items to grow and shrink within the flex container. Though things aren't just that simple, as a flex item is limited to how big it can be/grow by the dimensions of the flex container it is in.
This is due to the layout mode of Flexbox. Where usually an items given width is a hard constraint and determines the width of the parent element, as a flex item that width becomes a "hypothetical size" the size it could be if the containing parent elements width wasn't constraining it. e.g. you have an item that is 1000px wide but the flex container's width is only 600px, then the flex item can only ever be a max-width of 600px too.
This hypothetical size is why we can create more size responsive layouts, which sounds simple if we have only have one flex item within our flex container. But what if we have multiple items? Does it also effect the height of items too? Also what happens if we change the flex direction?
These are all great questions which can be solved with the help of these further flexible properties flex-basis, flex-grow and flex-shrink.
Flex-basis
So far we've learnt how everything in flex works in connection to either the primary or cross axis and only behave in a certain way no matter which way the flex-direction is set, but flex-basis flips that rule on its head.
It was created to be a generic hypothetical size property that works along the primary axis no matter which direction it is set, but it changes how it behaves depending on whether the it is horizontal or vertical. So when the flex direction is set to be a horizontal row it acts like width, but when we change the direction to a vertical column it changes its behaviour to be height.
Because of this it makes it a versatile property, but we can also control the initial size of a flex item either by using keywords, numerical lengths or percentages with these values:
auto (default): The browser calculates the flex-basis based on the item's content.0 or 0%: sets the flex-basis to zero, effectively shrinking the item down to its minimum size.length: you can set a fixed length value, such as 250px, 10rem, etc.percentage: a percentage can be used to set the flex-basis relative to the flex container's main size.content: adjusts the flex-basis according to the item's content. (note - only recently supported by some browsers but now has over 94% global coverage so is ok to use).
.flex_item {
flex-basis: auto;
}
Flex-grow
By default flex elements will shrink to their minimum possible size, leaving you faced with the possibility of extra spare space within your containing element. So we can use the flex-grow property to fill this empty space by defining how much a flex item (or items) will grow relative to the other items within the flex container.
The default flex-grow value for a flex item is 0 meaning it won't grow, but if we change this to the value of 1, the flex item will grow taking up any remaining space within the flex container. We can also specify a flex-grow value on multiple flex items too. This can be the same value so they equally grow and share the spare space, or different values so one will take up more of the space than the others.
flex-grow: 0;: The flex item will not grow. It will take up only the space defined by its width or height.flex-grow: 1;: The flex item will grow to fill the remaining space in the flex container. If all flex items have a flex-grow value of 1, they will share the remaining space equally.flex-grow: 2;: The flex item will grow twice as much as a flex item with flex-grow: 1. Essentially, it means that this item takes twice the amount of space compared to the others.
.flex_item_1 {
flex-grow: 1;
}
.flex_item_2 {
flex-grow: 2;
}
Flex-shrink
As we've already learnt a flex item's width becomes a hypothetical size and as well as grow it can also shrink to the size of the flex container. Even if we have two or more over sized items which are of similar or differing sizes. They will each shrink, scaling proportionally and keeping the ratio between them until they fit within the flex container.
But what if we want to control the ratio our items shrink by, in the same way we controlled how they grew?
That's where the flex-shrink property can help. It defines how much a flex item shrinks relative to the other items and the ratio we set when there isn’t enough space in the container.
For example, an item with flex-shrink: 2; will shrink twice as much as an item with flex-shrink: 1; as we have set a ratio of 2:1. So because it's all to do with the ratio even if the flex values said flex-shrink: 100; and flex-shrink: 50; the result would be the same as the ratio would still be 2:1.
Though if the flex-shrink is set to 0, the item will not shrink at all, regardless of available space.
.flex_item_1 {
flex-shrink: 1; /* Default shrinking */
}
.flex_item_2 {
flex-shrink: 2; /* Shrinks twice as much as item1 */
}
.flex_item_3 {
flex-shrink: 0; /* Will not shrink at all */
}
Min & max
An issue to watch out for is that max-width and min-width can sometimes cause unexpected side effects when using flex-grow and flex-shrink. So if you find your flex containers and/or items aren't behaving as you expected them to, go check your CSS for any min or max widths that maybe overriding your flex size properties.
Gaps
The properties column-gap, row-gap along with the more recent and widely used addition of gap are used to control the spacing between flex items, simplifying layouts without relying on margins.
gap: applies uniform spacing between adjacent flex items along both the primary axis and the cross axis. Flexbox layouts are usually one-dimensional (either a row or column), so in most cases, gap is applied along the primary axis, as there are no grid-like rows and columns.column-gap: controls the horizontal spacing between flex items when the flex direction is row. It's particularly useful when managing horizontal spacing in row-based layouts.row-gap: specifies the vertical spacing between rows of flex items when wrapping occurs. When flex items wrap to a new row, row-gap determines the space between those rows.
.container_1 {
gap: 20px; /* 20px of space between each flex item */
}
.container_2 {
flex-direction: row; /* Default direction */
column-gap: 15px; /* Horizontal spacing between items of 15px */
}
.container_3 {
flex-wrap: wrap; /* Allows items to wrap onto new rows */
row-gap: 10px; /* 10px of vertical spacing between rows */
}
While gap is widely supported for Flexbox, the independent row-gap and column-gap properties are just extensions of this functionality.
Order
The order property can be used to control the order in which flex items are displayed, regardless of their original order in the HTML structure.
How it works
Default Value: by default all flex items have an order of 0 which means it stays in its original source order.
Reordering Flex Items: You can assign a positive or negative integer to the order property to change the sequence of the items. Flex items with lower order values appear earlier, while those with higher values come later.
.flex_item_1 {
order: 2; /* This item will appear third */
}
.flex_item_2 {
order: -1; /* This item will appear first */
}
.flex_item_3 {
order: 1; /* This item will appear second */
}
This allows us to change a layouts view without modifying the HTML structure, and maintaining its semantic integrity when:
- Reordering for Mobile and Desktop Views: You might want to display a sidebar first in mobile view but keep it as a secondary element on desktops.
- Reorganising Forms If you have a multi-column form and want to rearrange the input fields visually in different resolutions.
- Priority-Based Layouts You might need to display priority items more prominently. Such as an e-commerce website could prioritise featured products.
- Interactive Dashboards often have widgets like graphs or controls, and the order property can help rearrange their positions dynamically based on user preferences or screen size.
Drawbacks to reordering
We should note though that whilst changing the source order by using CSS properties like order can be practical, it may have drawbacks and is often discouraged depending on the context.
- Accessibility Concerns Screen readers and assistive technologies rely on the HTML source order to navigate content. If you visually reorder elements using CSS without changing the actual source order, it can confuse users who depend on these tools. For example, the reading flow might no longer match the visual order, creating a disjointed user experience.
- SEO Implications Search engines prioritise content based on the HTML structure. By changing the visual order but not the source order, you might inadvertently de-emphasise important content in terms of SEO rankings. Search engine crawlers read the source code, not the CSS styling.
- Maintainability Issues When the visual order diverges from the source order, it can make the codebase harder to understand and maintain for developers. Future contributors may misinterpret the HTML structure or get confused about why certain elements are rendered out of order.
- Behavioural Side Effects Reordering elements purely visually could cause unexpected behaviours in user interactions. For instance: Focusable elements (like buttons or inputs) may follow the source order for keyboard navigation, leading to a counterintuitive tabbing experience. Dynamic features like animations or JavaScript-driven interactions might fail to account for the reordered layout.
- Content First Design A semantic and logical HTML source order ensures that the content hierarchy is preserved and meaningful. Relying heavily on CSS for reordering undermines this principle, potentially reducing the clarity and coherence of the document structure.
So we advise that you're best using this property sparingly and only when really necessary.
Go Flex your creativity
We hope that this little insight into the world of flexbox properties will help you flex your creative muscles enough to build your next project with it, or expand on what you have made with our templates and tutorial. Though as always if you have a questions about anything we've covered here, please don't hesitate to ask us.
Page Last Edited: