top of page

CSS - Flex

CSS has many layouts, and the default one is the flow layout.

Each layout has its own CSS properties or sub-language.

We can change from flow to flex using the display property.

If we change the display to flex, we can unlock the pandora box of flex properties.

As we know from layouts, a property's behavior is based on its context, and layouts provide context.

We know flow has inline and block, and its layout is primarily for document reading(texts and paragraphs).

This is the flow layout and block elements.

Block - Flow layout

If we change to flex,

Flex layout

Notice the change?

Suddenly block elements behaves as inline elements.

Because we changed the context, the element was in --> from flow to flex.

Each layout solves a particular problem.

Flow is meant for documents.

Then what does flex solve?

Flex means flexible.

And flexible is all about covering the space.

In general, space can be filled, unfilled, and the gap between filled.

Filled space --> Occupies element content based on size(width and height).

Unfilled space --> If space is available after spacing all the contents, then it is unfilled space.

Gap space --> Spacing between contents.

And Flex is all about controlling the space(both horizontal and vertical).

What controls the content? Flex layout.

To control something, you need to be at the top.

Therefore flex is declared at the parent.

The children of flex parents will be flex items.

So flex is about controlling and arranging the items in rows(horizontal) or columns(vertical) space.

What problem does flex solve?

I would like to quote Josh W Comeau

Flexbox is all about arranging a group of items in a row or column and giving us a ridiculous amount of control over the distribution and alignment of those items.
As the name suggests, Flexbox is all about flexibility. We can control whether items grow or shrink, how the extra space is distributed, and more.

As mentioned, flex layout is to control row or column.

By default, flex arranges items in a row.

The above example changes the block element to inline--> That's a row in a flex.

We can change the row to the column using the flex-direction property.

If the flex-direction is row, the primary axis is X or row.

If the flex-direction is 'column,' the primary axis is Y or column.

I am saying this because flex doesn't care about X or Y or row or column, and all it cares about is which one is the primary axis.

All flex-related properties are based on the primary axis.

And the axis perpendicular to the primary axis is the cross axis.

In general,

Primary axis --> children will be placed at the start of the container unless we specify a different value.
Cross-axis --> children will stretch to fill the entire container.

flex-direction: row(primary-axis) and cross axis(column) is stretched

flex-direction: column(primary axis) and cross axis(row) is stretched

All calculations in flex are based on the primary axis.
Controlling primary axis:

Regarding the primary axis, we think of a group and not a single child of the flex container.

All children bunched together are called a group,

The property to control this group is justify-content.

Source: CSS-tricks
Controlling cross-axis:

For the cross-axis, things will work a bit differently, and the property used to control is called align-items.

Why it is not align-content but align-items?

The mental model for understanding this is beautifully modeled by Josh W Comeau.

It all boils down to the axis.

The primary axis is a single axis.

Source: Josh W Comeau

Either you move as a group and can't be isolated individually. Let's demonstrate now.


Regarding the primary axis, you can think of distributing in terms of groups.

But cross-axis, we can see in terms of individual items.

Source: Josh C Comeau

You can arrange items individually. Let's demonstrate,

Source:Josh C Comeau

So that's the difference between primary and cross axis, which in turn difference between content and items.

Justify --> to position something on the primary axis!
Align --> to position something on the cross-axis!
content --> to position as a group!
items --> single items that can be positioned individually!
Width is not what you give in flex!

Flex layout width depends on the parent container.

It adjusts the child's width according to the parent's width even though it is greater than the parent's container width.

That's why it is called flexible and fluid as it adjusts to the constraints.

The above 2000px we specified to the child is called hypothetical size.

The same applies to column direction flex.

Hypothetical size = size when no constraints are there!
If the size is flexible, what is the point of giving values to the property width and height?
If the size is flexible, how does it grow and shrink?

Welcome to the three fundamental properties of flex-basis,flex-shrink, and flex-grow.


We know we have flex-row and flex-column, and the primary axis is decided accordingly.

We know width/height is not what you give to a flex child. It is just a hypothetical size.

If we change flex-direction to the column, the width doesn't change to height.

The above all applies to height if flex-direction is the column.

We know that,

flex-direction = row = primary-axis = width is controlled
flex-direction = column = primary-axis = height is controlled

This gives birth to the flex-basis.

Flex-basis gives effective control over size in the primary axis.

Flex basis may be difficult to understand so I have this mental model.

  • If you give width or height, it doesn't know which is the primary axis because width/height is general property and not particular to flex layout.

  • But flex layout calculations are based on the primary axis.

  • Flex layout is fluid and flexible, and hence size you give is hypothetical size.

  • To connect the primary axis and size control, CSS creators created a property called flex-basis.

Flex-grow: (container-size > content-size)

By default, the element occupies its minimum comfortable size along the primary axis.

This default behavior creates extra space.

Say we have a viewport width of 1000px, and a combined width of all children is 300px.

Therefore we have 700px extra space.

How this extra space is utilized?

That's where flex-grow property kicks in.

By default, it is zero(0) --> meaning it doesn't fill the extra space when container size is greater than content size.

We will demonstrate every bit now.

I am giving the first box, flex-grow, as 1.

What if multiple children are given flex-grow?

Extra space is proportionally divided between items based on respective flex-grow values in this case.

Let's demonstrate,

If you inspect individual elements in the dev tool(chrome),

You have two regions - one dotted and another plain.

The dotted represents the element's original width -> 100px.

The plain region represents the proportion of extra space the element utilizes due to its flex-grow.

Flex-shrink: (container-size < content-size)

It is the reverse of flex-grow.

When the parent's size is lesser than the children's, child items tend to shrink.

By default, 1 --> all items shrink equally to fit in the container.

If we give flex-shrink as zero, what would happen?

Pause and ponder.




Items won't shrink to fit the container. That's it.

We will calculate how the browser implements flex-grow and flex-shrink values for individual elements in separate article!
The minimum size thing!
  • When you give flex-shrink, the content shrinks according to the value we give.

  • When you give min-width/height, the item won't shrink below the min-width/height value even though we provide flex-shrink.

  • It will overflow if the item falls below the min-width/height value.

  • Flex shrink won't work below the min-size value.

The curious case of auto-margin in flex!

Usually, the margin adds space around the element.

In some layouts (flow or positioned), when the margin is 'auto' it centers the element horizontally and vertically.

In the case of flex layout, pardon me for not using my own words. I borrow it from CSS tricks blog,

"Setting the margin property on a flex child will push the child away from that direction. Set margin-left to auto; the child will push right. Set margin-top to auto, and the child will push to the bottom" - CSS tricks

This interesting behavior can be leveraged in navbar styling.

The CSS is,

.container {
    display: flex;
    background-color: brown;
    font-size: 2rem;
    color: darkgray;
.item1 {
    margin-right: auto;

The result is

Since item-1 margin-right is 'auto,' it pushes away from the direction.

Whatever items after it(item 2 and item 3) are pushed to the right.

It's one of the common tricks we use in CSS.


Till now, we have seen elements placed side by side in the case of a row and stacked in the case of a column.

It tries to occupy all the elements with the concept of fluidity.

This fluidity or flexibility compromises the hypothetical size of each element.

Let's demonstrate,

I have a container width of 100% and an element width of 250px each.

The 250px would be a hypothetical size.

Let's see the result.

Since all elements will accommodate in a single row by default, elements will have actual width lesser than the hypothetical width.

We will change this default by the property called 'flex-wrap.'

I am giving 'flex-wrap: wrap'

Let's see the result now,

When we set flex-wrap: wrap, items won't shrink below their hypothetical size.

Here we have multiple rows.

How does justify-content work?

Here every row will behave as a mini-flex container.

For each row, justify-content will work separately.

Then what about align items?

It works the same as before for cross axis but for each row.

We have multiple rows in the flex layout.

If we have a cross-axis, it will intersect at all rows.

Each row has items, and the cross-axis touch each row.

There is a group of items and its cross-axis.

Therefore the property name is align-contents.

Please refer to this demo:

bottom of page