Flex Layout
Flex layouts allow for more flexible control of item sizing in comparison to the more rigid, structured layout grid offers, at the cost of only allowing for control of one axis at a time. Items in a flex layout, by default, cannot span multiple columns and rows at the same time. To ensure no horizontal overflows occur, our flex layouts is geared towards creating columns inside a row-based layout that wrap to a new line when there is no more space left to fit the flex item into the current row (flex-wrap: wrap;).
Use the .layout-flex or .layout-inline-flex classes to create a flexible box layout. Like our grid layout, items are stacked on top of one another by setting their default width to 100%, to mimic the behavior of grid layouts without defined grid columns:
<div class="layout-flex">
<div>
<div>Flex item 1</div>
</div>
<div>
<div>Flex item 2</div>
</div>
<div>
<div>Flex item 3</div>
</div>
</div>
Consider carefully whether using a rigid flex layout is the right approach for your use-case. In many situations, Grid Layouts are better at creating a structured grid system, while flex layouts excel more at creating a layout where the flex items decide their own sizes individually of one another, shrinking and growing across the main axis as needed, rather than being controlled by a parent grid. If you require a flex layout without any defined column sizes, consider using the .display utility classes instead, as demonstrated below:
<div class="display-flex flex-wrap g-16">
<div>
Flex item
</div>
<div>
Another flex item
</div>
<div>
Yet another flex item
</div>
</div>
The key difference, aside from the ability to define columns, is that our rigid flex layout creates a wrapping container where the flex items take up the full size of the row by default. When using .display-flex, we retain the default wrapping behavior (flex-wrap: nowrap;), and flex items are sized using their default scaling algorithm (fit-content as default width, without growing to fill space, but allow shrinking up to min-content to create additional space in the row for new flex items.)
Changing the size of flex items
You can set the widths of individual columns inside a rigid flex layout using the responsive .col- utility classes. The utility classes are generated using a mixin, with the maximum number of classes generated being determined by the value of $document-grid-column-count inside _variables.scss (12 by default). The computed width of the flex item is equal to calc((100% / <column-count>) * <column-width>). For example, assuming a default 12-column grid, .col-3 creates a flex item that is (100% / 12) * 3 = 25% the width of the flex container wide.
Unlike regular flex layouts, Flex items inside our grid will not shrink to accommodate space for new flex items; they will only shrink if the row becomes too narrow to fit a single flex item's contents (up to min-content).
<div class="layout-flex">
<div class="col-6">
<div>Flex item 1</div>
</div>
<div class="col-4">
<div>Flex item 2</div>
</div>
<div class="col-2">
<div>Flex item 3</div>
</div>
</div>
You can also choose to omit the numeric value of the .col- utility class by simply declaring the .col class on the flex item. This will create a flex item that does not have a defined width (its flex-basis value is 0), but will instead grow to fill up all remaining space inside the row it is placed in (its flex-grow value is 1). This is not the same as the default behavior, which forces all flex items to have a defined width of 100% the size of the container and stack on top of one another; it will simply grow to fill the row it is placed in if space is available.
Alternatively, you can also declare the .col-auto class on a flex-item. This will create a flex item that takes up only the space it needs to fit its contents (its width is set to auto) instead of a defined, percentage-based width. This is similar to the default behavior of flex items in a regular flex layout, except that it will not shrink to create space for other flex items, only when its own contents do not fit inside the flex container's width.
These utility classes, in addition to the numeric .col- utility classes, allows for the creation of a mixed rigid-flexible layout where some flex items have a specified column width, some will take the width defined by its contents, while others have an undefined width and will only take up leftover space inside the row it is located in:
<div class="layout-flex">
<div class="col-3">
<div>Width equal to 25% of the flex container</div>
</div>
<div class="col">
<div>No defined width; takes up any leftover space</div>
</div>
<div class="col-auto">
<div>Width taken from contents</div>
</div>
</div>
Setting the number of flex columns
Our flex layout has a default set of 12 columns (as defined by $document-grid-column-count inside _variables.scss). To change the number of columns inside the flex layout, you can use the .flex-cols- utility classes. Like .col-, these utility classes are generated using a mixin, with the maximum number of possible columns also being determined by the value of $document-grid-column-count. The classes do not compute any CSS properties themselves; instead, they create a CSS custom property named --_flex-column-count. This is used by the .col- utility classes to determine their widths. Consider the following example:
.flex-cols-defined
<div class="layout-flex flex-cols-6">
<div class="col-3">
<div>Width equal to 50% of the flex container</div>
</div>
<div class="col">
<div>No defined width; takes up any leftover space</div>
</div>
<div class="col-auto">
<div>Width taken from contents</div>
</div>
<div class="col-12">
<div>I use .col-12, but because there are only 6 columns, I take up the full width of the container instead because my max-width is 100%.</div>
</div>
<div>
<div>I am an undefined column. I take up 1 column of space because the parent grid has <code>.flex-cols-</code>defined</div>
</div>
</div>
In this grid, the .col-3 item takes up 50% of the width instead of 25%. This is because of the .flex-cols-6 class declared on the container, which defines --_flex-column-count and sets its value to 6. When this custom property is not defined, it falls back to the default value, which is 12 taken from $document-grid-column-count. Looking at the formula used by the .col- utility classes to determine the width once again: calc((100% / <column-count>) * <column-width>). For .col-3, this now creates a flex item that is (100% / 6) * 3 = 50% the width of the flex container. To avoid overflows when the value of .col- is greater than the number of columns defined by .flex-cols-, we set a max-width of 100% on flex items by default.
The default values of flex items inside a flex layout with an explicitly-declared column-count is also different; instead of stacking vertically on top of one another by default, the flex item will now take up 1 column of space, similar to a grid layout with a defined grid-template-columns.
Because the .col- utility class sets a percentage-based width on the item that takes the value of $document-grid-column-count as fallback in situations where --_flex-column-count is not defined, the .col- utility classes may also be used outside the context of our flex layout to set the width an element:
--_flex-column-count: 10; defined
<div class="col-3">Not a flex item, but still 25% the width of the parent</div>
<div style="--_flex-column-count: 10;">
<div class="col-5">I am a .col-5 but take up 50% of the width of my parent because it has <code>--_flex-column-count: 10;</code> defined</div>
</div>
Creating column gaps
One limitation of Flex layouts is that we do not have access to the fr unit to control how much space each item should have. This means that creating a rigid grid system using a flex layout requires the use of percentage widths, which do not take the space created by the gap properties into account, leading to overflows. The best workaround for this is to force the column-gap to 0 on the flex container using !important (to ensure the gap utility classes do not overwrite it), setting a negative margin on both sides of the flex container equivalent to 50% of the width set by the gap utility class, and then adding that space as padding on both side of the flex item. The reason why this works is because, in addition to setting the gap, row-gap and column-gap CSS properties, these utility classes also define a CSS custom property with the same value. Because we forced only our column-gap to 0, vertical gaps are still created using the gap or row-gap utility classes, while the column-gap is created using the custom property's values as negative margins on the flex container and paddings on the flex items:
Flex container:
margin-inline: calc(var(--_column-gap, var(--_gap)) * -.5); // use the value of --_column-gap if it is present. If not, try --_gap instead.column-gap: 0 !important; // column-gap does not work in a flex-layout with %-based columns because it creates overflows.
Flex items:
padding-inline: calc(var(--_column-gap, var(--_gap)) * .5); // Create spacing inside the flex items instead.
<div class="layout-flex g-16 gx-24">
<div class="col-6">
<div>Flex item 1</div>
</div>
<div class="col-4">
<div>Flex item 2</div>
</div>
<div class="col-2">
<div>Flex item 3</div>
</div>
</div>
Because the column-gap property will not work, you must overwrite the value of --_column-gap or --_gap on the flex container instead if you want to define your own column gaps without using utility classes. Furthermore, setting backgrounds on the flex items will negate the spacing because it will cover the padding that was used to simulate the gaps. If flex items need a background, create a <div> inside the flex item and set the background on that.
Creating column offsets
Grid layouts allow for you to set a starting position for a grid item using grid-column-start. This allows you to create 'empty' columns inside the grid. Because flex layouts do not create columns natively, the only way to create such empty 'columns' in our flex layout is to simulate them by adding margins to our columns to push / pull them to a specific position inside the row equal to the size of a 'column'. Offsets will also push all subsequent items along with the item the offset is declared on, which means no overlapping occurs normally.
You can use our responsive .offset- utility classes to make this process easier. Like our .col utility classes, these classes are generated by a mixin, with the maximum number of classes also being determined by the value of $document-grid-column-count. It also uses the exact same formula as the .col- classes to determine the size of the offset (calc((100% / <column-count>) * <column-width>)), using the value of --_flex-column-count as a reference value if it is available, and falling back to 12 (the default value of $grid-column-count) otherwise:
<div class="layout-flex g-16 gx-24">
<div class="col-3">
<div>Flex item 1</div>
</div>
<div class="col-2 offset-2">
<div>Flex item 2</div>
</div>
<div class="col-3">
<div>Flex item 3</div>
</div>
<div class="col-2">
<div>Flex item 4</div>
</div>
</div>
You can also pull items to an earlier position, instead of pushing them by using our .offset-n utility classes. Like with our regular offsets, pulling items to an earlier 'column' in the grid will also pull all subsequent items along with it. Using negative offsets allows you to (partially) overlap items inside the grid, which is similar to declaring the same value for grid-column on multiple items inside a grid layout:
<div class="layout-flex flex-cols-10 g-16 gx-24">
<div class="col-3">
<div>Flex item 1</div>
</div>
<div class="col-2 offset-n1">
<div>Flex item 2</div>
</div>
<div class="col-2">
<div>Flex item 3</div>
</div>
<div class="col-3 offset-1">
<div>Flex item 4</div>
</div>
</div>
Changing the wrapping behavior
We set flex-wrap: wrap; on our flex containers to ensure the flex children get pushed to a new row once the container runs out of room to accommodate another flex item. Should this not be the desired behavior, you can modify the wrapping behavior with our responsive .flex-wrap, .flex-nowrap or .flex-wrap-reverse utility classes. Similarly, you can use these utility classes to make non-rigid .display-flex or .display-inline-flex layouts wrap.
Changing the Flex direction
Unlike grid layouts, which stack items one atop of another by default, regular flex layouts places items next to one another because the default flex direction is 'row' (e.g. 'place items next to each other in the same row'). With our responsive flex direction utility classes, you can modify how flex containers place their items. For example, you can invert the order of the items by applying .flex-row-reverse, or stack items on top of one another with .flex-column.
Changing the alignment of flex items
The justify-content, align-content, align-items and align-self CSS properties can be used the control the alignment and positioning of flex items inside the grid. Our alignment utility classes for each of these properties offer a responsive, convenient solution to this to limit the amount of custom CSS that has to be written:
.justify-contentcontrols how flex items are distributed inside the grid's main axis (horizontal by default). Declare on the flex container..align-contentcontrols how flex items are distributed inside the grid's cross axis (vertical by default). Declare on the flex container..align-itemscontrols how flex items are aligned vertically in relation to other flex items in the same row (or column if the flex-direction is set to 'column'). Declare on the flex container..align-selfcontrols how individual flex items are aligned vertically in relation to other flex items in the same row. Takes priority overalign-items. Declare on the flex item.
.justify-items and .justify-self do not work because flex layouts do not generate columns for flex items to align within; the size of each column inside our flex layout is determined by the width declared on the individual items themselves, not by the parent container. align-items can be used because the height of rows (or width of columns if flex-direction is set to 'column') is equal to that of the largest flex item, and all other items inside the same row can be aligned along the main axis accordingly. However, we cannot do so along the cross-axis because the parent container only has control over 1 axis at a time.
You can use our live flex layout generator below to test the effect of these utility classes and their supported values in an actual flex layout.
Flex Layout generator