Equal height cards with flexbox
Design | Ivan Basic

Equal height cards with flexbox

Wednesday, Jul 29, 2020 • 2 min read
Nice vertical alignment of the column based content can be difficult to achieve using only HTML/CSS, but here's a simple and elegant solution using `flexbox`.

Nice vertical alignment of the column based content can be difficult to achieve using only HTML/CSS, but here’s a simple and elegant solution using flexbox.

Let’s start with a set of simple content cards with different amount of content. Of course, we will exclude the usage of the fixed height in these examples.

If you use float for the layout of cards, you will not be able to equally align cards by height, and you will be compelled to use JavaScript to do the job. Using display: table property solves the problem in a single row, but it doesn’t help with multiple rows.

Mihael Tomić

Mihael Tomić

Principal Designer at Mono

Looking for quality frontend solutions? Let’s schedule a call and discuss how I can help!

By using flexbox we get a pretty good solution. We have equal heights by default and we get additional options to control card behavior. The code is very simple and elegant - please refer to the examples below.

Setting equal heights on cards

First, let’s assemble some HTML code for the cards. We will use three cards in a row. Note that we will need two wrappers around cards to make this work.

<div class="card__wrap--outer">

    <div class="card__wrap--inner">

        <div class="card">
          Card 1 content
        </div>

        <div class="card">
          Card 2 content
        </div>

        <div class="card">
          Card 3 content
        </div>

    </div>

</div>

Now, let’s add some CSS (it is written in postCSS syntax for better readability).

.card {
    display: flex;
    flex-direction: column;
    width: 100%;

    &__wrap {

        &--outer {
            display: flex;
            flex-direction: row;
            flex-wrap: wrap;
            width: 100%;
        }

        &--inner {
            display: flex;
            flex-direction: row;
            width: 33.33%;
        }
    }
}

Note that all three main elements, .card, .card__wrap—outer and .card__wrap—inner need to have display: flex property to achieve equal heights. By adding some more content and styling it (code will be shown at the end of this post), we will arrive at something like this:

Default equal heights card layout with flexbox Default equal heights card layout with flexbox

Areas marked in red in the image above show the dead space inside the content that we get by default. To resolve that, and to get more control over card’s dead space behavior, we can simply add flex-grow property to the element inside the content element we want to scale. Here’s the updated HTML:

<div class="card__wrap--outer">

    <div class="card__wrap--inner">

        <div class="card">
            <div>Title</div>
            <div>Subtitle</div>
            <div class="flexible">Copy</div>
            <div>Footer</div>
        </div>

        <div class="card">
            <div>Title</div>
            <div>Subtitle</div>
            <div class="flexible">Copy</div>
            <div>Footer</div>
        </div>

        <div class="card">
            <div>Title</div>
            <div>Subtitle</div>
            <div class="flexible">Copy</div>
            <div>Footer</div>
        </div>

    </div>

</div>

We only need to add the folowing CSS:

.flexible {
    flex-grow: 1;
}

Now we will get something like this:

Adjusted equal heights card layout with flexbox Adjusted equal heights card layout with flexbox

Here you can see that by adding a simple flex-grow CSS property on certain element inside the card content, we get control over the scaling of the content that will be displayed. This solution also supports multi-row layouts.

Some may say that we can use justify-content property, but in that case we loose control of the spacers between content items.

Here’s the complete code and playground for the solution described above.

See the Pen Flex Cards by Ivan Bašić (@IvanMono) on CodePen.