Flexbox model in CSS – make a calendar

I wanted to print a calendar for April, but there was no satisfying solution on the Internet. What else could I do? I wrote one using CSS flexbox model.

This article will show the basics of flexbox model recreating this calendar step by step.

Starter

We have a single block somewhere inside a web page, and now we want to embed a calendar inside. We just set the #calendar height and width to 100%.

Make a block flexible

Inside the #calendar, there is a header and two sections. We want them to occupy whole space and maintain the given ratio.

For #calendar, we use new flex display property. A browser will place elements in given direction (either as a column or a row). Our blocks have zero height, so we set proportions for children. flex-grow says how much of a remaining space should get a particular element.

#calendar { width: 100%; height: 100%; display: flex; flex-direction: column; }
#calendar > header { flex-grow: 7; }
#calendar .day-names { flex-grow: 5; }
#calendar .days { flex-grow: 88; }

Since no space was occupied, our blocks are sized ideally 7:5:88. Every child is a block, therefore takes the whole width by default.

Calendar content

There’s some JS to fill the calendar with the content. The script creates a block for every day in the month and spacer blocks for days from previous and next weeks. I won’t go into details; you can check the code yourself.

A thing to notice is, now there is little free space to allocate. Since ratio for .days is much bigger, it receives nearly all the remaining pixels. Please see the demo for a better view.

Centering headers

The new model makes it so easy to center a child inside an element that you will never again use display: table (hurray!).

align-items is to place elements perpendicularly to flow direction. For example, we have a column flow, and we want to align all elements to the right. We set the property to flex-end, and we’re done.

justify-content works along this flow direction. It lets us center child elements, give them equal spacing, etc. I advise you to see the link and read more; it’s a useful feature.

We know how growing works, the only new thing is to center month name. Please notice you have to align day names to the center. Otherwise, labels will show moved to the left.

#calendar > header { flex-grow: 7; display: flex; align-items: center; justify-content: center; }
#calendar .day-names { flex-grow: 5; display: flex; align-items: center; }
#calendar .day-names p { flex-grow: 1; text-align: center; }
#calendar .days { flex-grow: 88; display: flex; }
#calendar .days > div { width: calc(100% * 1/7); }


You can notice I set the days to take 1/7 of the width, but they don’t listen 🙂 It’s because browser tries to pack all the children inside the block, and there are 35 (that is, more than seven). How to fix this?

Flexbox and wrapping

Flex elements can wrap content. That’s great because we can create grids (with fixed number of columns) quickly. Flow direction is a row, so our days will get stretched vertically by default. If we need six rows (imagine April on the screenshot having 31 days), all the sizing will be done automagically.

#calendar .days { flex-grow: 88; display: flex; flex-direction: row; flex-wrap: wrap; }

Add some polish

That’s all regarding arrangement. A few lines of CSS and there’s the final version:

Further reading