Tutorial: Create ruler using Flexbox layout

Introduction

Flexbox coming with CCS3 is an useful, handy way to do layouts in CSS. Learning using flexbox is pretty simple and you can find out a bunch of resource to learn this. In this post, I give a tutorial to apply flexbox to create ruler with pure HTML and CSS.

Plan ahead

Before getting started, we need to imagine and break down components needed to form a ruler. There are some you may think of:

  • Ruler board
  • Major sticks
  • Minor sticks
  • Value for major sticks

For example, we are going to create one like this:

Ruler

We have 11 major sticks that go with 11 corresponding values. For each segment between 2 adjacent major sticks, there are 9 minor sticks or you can think there are actually 11, but the first and last one are hidden behind the major sticks.

Let’s do it

Great! We have the image of ruler in mind, we know necessary components to create it. Let’s do it now.

Step 1: HTML first

Creating HTML structure is vital step before moving ahead to later steps, that is why I put it to be the first step we need to do. Keep this in mind:

Better HTML structure we have, easier we style to achieve what we desire.

We are going to create HTML as the plan above. We have:

  • 1 tag for the board
  • 11 tags for major sticks
  • Inside each major stick’s tag, we put 11 tags for minor sticks and its value
<div class="ruler">
    <ul class="stick-container">
        <li class="stick">
            <ul class="minor-stick-container">
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
            </ul>
            <span class="stick-value">0</span>
        </li>
        <li class="stick">
            <ul class="minor-stick-container">
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
            </ul>
            <span class="stick-value">1</span>
        </li>
        <li class="stick">
            <ul class="minor-stick-container">
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
            </ul>
            <span class="stick-value">2</span>
        </li>
        <li class="stick">
            <ul class="minor-stick-container">
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
            </ul>
            <span class="stick-value">3</span>
        </li>
        <li class="stick">
            <ul class="minor-stick-container">
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
            </ul>
            <span class="stick-value">4</span>
        </li>
        <li class="stick">
            <ul class="minor-stick-container">
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
            </ul>
            <span class="stick-value">5</span>
        </li>
        <li class="stick">
            <ul class="minor-stick-container">
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
            </ul>
            <span class="stick-value">6</span>
        </li>
        <li class="stick">
            <ul class="minor-stick-container">
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
            </ul>
            <span class="stick-value">7</span>
        </li>
        <li class="stick">
            <ul class="minor-stick-container">
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
                <li class="minor-stick"></li>
            </ul>
            <span class="stick-value">8</span>
        </li>
        <li class="stick">
            <span class="stick-value">9</span>
        </li>
    </ul>
</div>

Wait! Why does the last major stick having no minor ones inside? Good question! Don’t worry, I will explain in next steps.

  • div.ruler is just like the ruler board, a super container. It helps positioning our ruler anywhere in page easier. Moreover, we can do stuffs with padding, margin and even decoration here.
  • ul.stick-container acts as flex container, where we do layout magics using flexbox. It contains all major sticks.
  • li.stick is a major stick and flex item as well. It contains its minor sticks and value inside.
  • ul.minor-stick-container is similar to ul.stick-container but for minor sticks.
  • li.minor-stick is similar to li.stick. However, it has nothing inside at all. It just draws minor stick itself.
  • Finally, span.stick-value is where we put value of major stick.

Step 2: Bring flexbox into game

You may be asking where flexbox will be used. The question is in style of major sticks and minor sticks. As explained above, we have:

  • ul.stick-container and ul.minor-stick-container are flex container.
  • li.stick and li.minor-stick are flex item.

Therefore, we are going to use flexbox in these 4 classes.

Flex container

.stick-container, .minor-stick-container {
  display: flex;
  justify-content: space-between;
}

We define .stick-container and .minor-stick-container as flex container by setting display property to flex. This turns on flexbox layout for itself and all its direct children.

Before talking about justify-content: space-between, just look back the ruler image. We want segments that are between 2 adjacent major sticks occupy the whole width of their container (ul.stick-container) and they have to have identical width. Likewise, we want all segments between 2 adjacent minor sticks fill in full width of the container (ul.minor-stick-container) and also equal to each others.

How can we achieve this? Maybe you are thinking of percentage, you are right, it can solve this. However, flexbox offers much better and more flexible approach. Imagine that you have 5 major sticks, it means 4 segments, then you set width of each segment to 25%. Now you change your mind, you want 6, you have to change the width to 20%. The same is also applied for minor sticks. It is a bit inconvenient, right?

Flexbox solves that in a beautiful way. All you need is justify-content: space-between, plus one more in next section. justify-content tells flexbox container how to distribute their free space. space-between specifies that free space should be distributed between flex items as long as first and last item are at begin and end position respectively.

Flex item

Pair with justify-content: space-between above, we need one more thing to have all major segments sit equally in ul.stick-container.

.stick {
  flex-grow: 1;
}

flex-grow property specifies weight of flex item in its container. On the other hand, it is how many flex item should expend its width to fill up its container’s width. We give all li.stick the same flex-grow value, means all of them have equal width.

However, there is one exception. Remember the question in HTML? I will explain it here. All major sticks have their minor sticks, except the last one. Because the last one does not have any minor sticks, we do not want it to take space in the container. Instead, we only set width of it.

.stick:last-child {
   flex-grow: 0;
   width: 2px;
}

That is for major ticks. For minor sticks, there is small difference.

.minor-stick {
    width: 1px;
}

With major sticks, we do not know exact width of each, but with minor sticks, we do. Thus, instead of using flex-grow, we set explicit width for each minor sticks. Then, let justify-content: space-between of ul.minor-stick-container do the rest, means it automatically gives equal space between minor sticks. This is an advantage of using flexbox, compared with old school percentage way.

There are only 9 minor sticks in fact, but 11 tags, is it weird? Yes, it is with intention. Because the first one is always sit backward the major stick and the last one is always sit closely the next major stick, we need to add 2 more sticks to assure there are 9 sticks between 2 major sticks. Of course, we also need to hide those 2 sticks.

.minor-stick {
  &:first-child, &:last-child {
    width: 0px;
  }
}

Step 3: Be an artist

Until now, we have gone through substantial parts in this tutorial. Things left is to style and make it really work.

.ruler {
  position: relative;
  height: 50px;
  margin: 10px;
  padding: 0 10px 0 10px;
  background-color: #F6C199;
}

We set position property of div.ruler to relative to make sure major sticks’ values positioned correctly later.

.minor-stick-container {
  height: 50%;
}

.stick-container {
  .stick {
    flex-grow: 1;
    height: 100%;
    border-left: 2px solid #C39466;
    &:last-child {
      flex-grow: 0;
      width: 2px;
      background-color: #C39466;
    }
  }
}

We use border-left of li.stick to create major sticks visually. It also explain why we explicitly set width of the last one.

.minor-stick-container {
  .minor-stick {
    width: 1px;
    height: 100%;
    background-color: #ECB177;
    &:first-child, &:last-child {
      width: 0px;
    }
  }
}

.stick-value {
  position: absolute;
  bottom: 0;
  transform: translateX(-50%);
  color: #A79E9F;
  font-weight: bold;
  font-size: 1.2em;
}

Because we set position property of div.ruler to relative, position of value is relative to this tag. That is how we can pull values to bottom of the ruler. One more thing, we use transform: translateX(-50%); to make major stick and its value are center to each other.

Demo

You can find complete code of this tutorial here.
Feel free to fork and explore it yourself. And if you find any bug, let me know as well, you are welcome.

Conclusion

There are lots of ways to take advantage of flexbox to layout. You can mix flexbox and traditional layout method to super charge your power and make layout work easier and more flexible than ever.

This is just one example I find interesting to use flexbox and share with you. There are still more things out there and can’t wait to see what you can do with flexbox.

Read more

If you would like to learn more flexbox, here is my recommendation A Complete Guide to Flexbox. It is an awesome guide to start with flexbox.

You know others better? Please share me too, thanks!

Tags: , , ,

About ninjapro

It is better to feel by yourself about me

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: