'When small men begin to cast big shadows, it means that the sun is about to set.' -Lin Yutang, Hard-to-Solve Cryptograms

Using Nested FlexBoxes to Create Tables

by Ethan Glover, Sun, Sep 17, 2017 - (Edited) Sun, Sep 17, 2017

I know, the homepage of this website has never been pretty. Simple tables displaying blog lists from simple categories. I like it. I like keeping the design minimal, simple, and easy to navigate. However, I've still always had issues. When I first built this design, I depended on HTML tables. An obfuscated method of organizing information. One that doesn't work with responsive design.

Eventually I moved to using CSS + unordered lists. This gave me the power to make the design responsive, but it still had its problems. Primarily each row in the tables had its own height. Meaning the tables for categories themselves were never a universal height. This made for an annoying look. Not only that, but I had great difficulty getting images to stay within those rows and next to the articles they represent.

I still haven't solved the issue of images entirely. At the moment, all images are scaled down to perfect squares. The aspect ratios are not matched to the image dimensions and the result is scrunched or stretched images. But they're small, so I'm willing to deal with it until I come up with an answer.

The purpose of this post is to share how I solved the problem of unordered lists creating oddly sized tables. As it is now, each row will stretch or shrink to fit the text contained in it. However, the tables themselves all stay the same size, making for a prettier, easier to read look.

I was able to achieve this using CSS flexboxes. Or, in this case specifically, nested flexboxes. Here's how it works. The HTML is laid out as such:

<div class="flex-container">
    <div class="flex-table">
        <div class="flex-title flex-item">Category Title</div>
        <div class="flex-item">Blog Details</div>
        <div class="flex-item">Blog Details</div>
        ...
        <div class="flex-archive flex-item">Archive Link</div>
    </div>
    <div class="flex-table">
        <div class="flex-title">Next Category</div>
        ...
    </div>
</div>

The homepage contains four tables to link to blogs from four categories. All four of those tables are contained in the flex-container class. Then, each table is separated using the flex-table class. And of course, as you can see, each row is represented by flex-title, flex-item, or flex-archive. (With the top and bottom rows represented by title and archive.)

The CSS handles this as such:

.flex-container {
    display: -webkit-flex;
    display: flex;
    -webkit-flex-flow: row wrap;
    flex-flow: row wrap;
    justify-content: center;
}
.flex-table {
    -webkit-flex: 1 1 0;
    flex: 1 1 0;
    display: -webkit-flex;
    display: flex;
    -webkit-flex-flow: column nowrap;
    flex-flow: column nowrap;
    -webkit-justify-content: center;
    justify-content: center;
    padding: 5px;
    max-width: 460px;
    min-width: 320px;
}
.flex-table div:nth-child(even) {
    background-color: #ADCDEA;
}
.flex-title {
    background-color: #5B9BD5;
    color: #ffffff;
    font-family: 'Bookerly-Bold', serif;
}
.flex-item {
    -webkit-flex: 1 0 auto;
    flex: 1 0 auto;
    -webkit-justify-content: center;
    justify-content: center;
    -webkit-align-items: center;
    align-items: center;
}
.flex-archive {
    font-family: 'Bookerly-Italic', serif;
}

OK, flex is much more simple than it seems once you get used to it. First, the container is set as 'row wrap.' Meaning, each table in the container is organized by row (horizontally as opposed to vertically). But are also set to wrap. So if the screen is small enough, the last table will drop down, then the next, and so on. So that on a mobile device, you should see one table at a time with each underneath the other. On desktop with a large screen, you'll see them side by side. The justify center attribute is just to make sure that the tables altogether are centered on the page.

Within the table class, you see the flex attribute as 1 1 0. The first two numbers represent "grow" and "shrink." As you resize the page, each table grows and shrinks on a 1:1 ratio. If I were to set flex-title to 5 1 0, for example, the title would grow at 5 times the rate as the items and archive rows. On a large screen, it would be roughly 5 times as big.

The 0 is flex-basis. The initial length of each item. In this case, the initial width of each table. It can be set to a percentage, px, em, or auto. I set it to 0 so that it follows exactly the 1:1 ratio. In the table case the max-width and min-width is set to 460px and 320px respectively. The tables will follow this rule while keeping each width at the 1:1 ratio. Meaning they'll always be the same width.

Further in the table class, I set up a new display: flex environment. Same as the container, except this time the flow is set to column nowrap. This means each item in the table class is organized as a column and do not wrap. If they did wrap, if you shrink the page on the horizontal access, each item would jump up to try to fit on the page. This doesn't make sense from a responsive viewpoint as it'd be easier to just allow you to scroll up and down.

In flex-item, I've set the flex attributes to 1 0 auto. What this means is that each item in the table will grow to fit the table, but will not shrink. These attributes are what helped me achieve what I was looking for. Basically, each row will automatically grow to fit the table (thanks to the auto basis) but they will not shrink to match their content.

Breaking that down, say there are two blog posts in a table. One with a long description. One with a short description. Both will grow enough to fit the content. Meaning, the one with a long description will take up more space relative to the short. However, they will not shrink in such a way that they do not fill the table as a whole. This is what keeps each table at the exact same height. But each row is a different size according to the amount of content contained within.

As an example, take a look at the picture below. The politics category contains longer descriptions so the title and archive rows are only big enough to display the content. But on the code category, the title and archive, as well as each row, are stretched to fill extra space.

I'm really happy with the way this turned out. I've never been too concerned about the looks of this site. As long as the articles are easy to read with neutral colors, and good font styles/sizes, I'm OK. But the unordered list style of creating tables always got on my nerves a bit. And flex provided a great solution.

If only I could figure out a way to get those images to resize properly... Know of a way? Let me know below.