I've been building an application called StoryTracker that is meant for users to have a high-level overview of a given Pivotal Tracker project. I am now in phase of initial UI/UX for a v1.0.0 milestone. Maybe I like to make things hard for myself, but I decided to try and throw traditional grid frameworks out the window and opt for display: flex. Here are my takeaways thus far:

Re-education

Having experience in a whole ecosystem of grid frameworks I went in completely blind to how its trained my way of thinking about layouts. The first thing I did in my new layout.html was:

<body>
  <div class="container">
    <div class="row">
      <!-- content -->
    </div>
  </div>
</body>

Wait a second! The concept of a row isn't a required concept in the flexbox world as it is in float-based grids. That is because flexbox simply lets items that are too wide to fall to the next line (assuming you've set flex-wrap: wrap; and flex-direction: row;).

Thinking in flexbox is tricky

layout screenshot

To clarify what I mean when I say 'tricky', I am referring to the image posted above. If I was using a standard grid framework the markup would look something like this.

<div class="columns-12 story">
  <div class="row details">
    <div class="column-8">
      <div class="column-3 watch">...</div>
      <div class="column-3 activity">...</div>
      <div class="column-3 type">...</div>
      <div class="column-3 risk">...</div>
    </div>
    <div class="column-4 text-right">
      <div class="column-6 author">...</div>
      <div class="column-6 external">...</div>
    </div>
  </div>
  <div class="row title">
    <h4>Expected codegen a TABLE with ARRAY(), ...</h4>
  </div>
</div>

The above snippet assumes the framework supports nested columns, like Foundation, Neat, or Bootstrap. Also verbose CSS classes are used for illustrative purposes.

Now translating to display: flex;

<div class="story">
  <div class="details">
    <div class="item watch">...</div>
    <div class="item activity">...</div>
    <div class="item type">...</div>
    <div class="item risk">...</div>
    <div class="item author">...</div>
    <div class="item external">...</div>
  </div>
  <div class="title">
    <h4>Expected codegen a TABLE with ARRAY(), ...</h4>
  </div>
</div>
.story {
  box-sizing: border-box;
  margin-left: auto;
  margin-right: auto;
  * { 
    box-sizing: border-box;
  }
  .details {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: flex-start;
    align-items: baseline;
  }
  .item {
    flex: 0 1 100px;
    &.author {
      flex: 1 1 100px;
    }
  }
}

The eye opening moment

Wrapping my head around how to parse flex: 0 1 100px; took quite a bit even with the help of an excellent CSS-Tricks Flexbox summary. I thought I'd understood what flex-basis, flex-grow, and flex-shrink were supposed to do, but three hours later it was clear I was mistaken (sigh).

In an effort to help others with this here is how I understand their functions now:

  • flex-grow is the base multiplier for expand operations
  • flex-shrink is the base multiplier for condense operations
  • flex-basis is the value to combine with the multiplier set on flex-grow/flex-shrink (depending on the operation).

Simplified Mental Model

In our above example of flex: 0 1 100px that would roughly look like:

For a grow operation flex-grow: 0 and flex-basis: 100px turns into 100 + (0 * 100) means the item will not grow past the basis of 100px.

For a shrink operation flex-shrink: 1 and flex-basis: 100px turns into 100 - (0 * 100) meaning the item can shrink up to a width of 0.

I'll leave the other flex: 1 1 100px; as a reader exercise.

Oversimplification?

The math and details provided above are intentionally generalized. The CSS-Tricks article and MDN articles do an excellent job on the technical specifics of how flex functions in various situations. My intention here was to propose a simplified take on those documents in hopes it gets folks into a place to have an 'Ah ha!' moment.

To flex or float?

They have their definite plus and minuses. Overall though I'm going to stick with flexbox for the foreseeable future. When it comes to responsive design and @media CSS queries, it is easier for me to think "Ok instead of a new column layout, I'll just change from flex-direction: row; to flex-direction: column; to switch this list from horizontal to vertical on mobile."