Notes from MDN web docs taken while following What The Flexbox course from Wes Bos.
Flexbox is short for Flexible Box Module
. A layout model that allows easy control of space distribution and alignment between html elements [2].
Flexbox controls positioning in just one dimension at time (row or column). For two dimension control CSS Grid Layout comes in place [2].
Given the following template:
<body>
<div class="container">
<div class="box box-1">1</div>
<div class="box box-2">2</div>
<div class="box box-3">3</div>
<div class="box box-4">4</div>
<div class="box box-5">5</div>
<div class="box box-6">6</div>
<div class="box box-7">7</div>
<div class="box box-8">8</div>
<div class="box box-9">9</div>
<div class="box box-10">10</div>
</div>
</body>
The default behavior for the above divs, respecting the normal html document flow, is to be rendered from top to bottom, left to right and to take the entire body width, since its display
property defaults to block
.
When display: flex
is applied to the .container
div, all direct child divs become flex-items
, and gain new behavior [2]:
flex-direction
defaults to row
item stretches to fit cross axis (height in this example). If items have different heights they will stretch to the tallest one height
flex-basis
defaults to auto
(item width will be set by its contents)
flex-wrap
defaults to nowrap
(if the container is not wide enough to fit the items, they won’t wrap, they will overflow instead)
For visualization purposes let’s stretch the container to take the entire height.
display: flex
makes the container expand the whole width available. As opposed to display: inline-flex
, which makes the container collapse to the content’s width.
Once declared as a flex container, that element can be thought of in two axis. The main axis, defined by the flex-direction
property. And the cross axis, which is perpendicular to the first [2].
There are four values for the flex-direction
property: row
, row-reverse
, column
and column-reverse
.
The default value is row
, and it sets the main axis horizontally, from left to right and the cross axis intercepts it vertically, from top to bottom. Analogously, the column
value sets the axis vertically, from top to bottom and the cross axis from left to right. The reverse
property on both options reverses main axis 180°. The cross axis remains the same [1][2].
The flex-items behavior for those values can be observed below:
flex-wrap
is the property that deals with the flex items when space in the container isn’t big enough to fit them all [3].
By default flex-wrap
is set to nowrap
, which means that if the container cannot fit the items in a row with their original width, they will shrink to fit. If for some reason they are not able to shrink they will then, overflow the container [1][3].
By setting a 300px width to the items, the nowrap
option outputs this result:
in which, each item has shrank to approximately 70px to fit the container.
When the property is updated to wrap
, items’ width will now actually have their original value, 300px. Instead of overflowing the container, when the first row is not wide enough to fit 300px, the item will wrap to a new line [3]. Each line should be thought of as an individual flex container. The space distribution in one container does not affect the other ones neighboring it [2].
But why are flex items taking the whole screen height? In the first section, container height was set to 100vh
, so the space available is divided equally by the four rows necessary to fit the 300px items. Hadn’t we set the 100vh
, container height would then respect the item content height, as in the image below [1]:
Another option is wrap-reverse
, that inverts the cross axis. Set from top to bottom by the flex-direction
property, wrap-reverse
transforms it into bottom to top [1].
By inverting the main axis with flex-direction: column
, the elements that don’t fit wrap to another column and remaining space is evenly divided [1].
And the wrap-reverse
option along with column
direction inverts the cross axis from right to left, producing the following output:
Since flexbox is a single dimension layout, on reversing the wrap, items are laid out from bottom to top (for row direction), but keep the left to right structure. Only the cross axis is altered.
flex-direction
and flex-wrap
can be declared in a single property: flex-flow: [direction] [wrap]
[2].
.flex-container {
flex-flow : column wrap;
}
Back to row/wrap. The entirety of the container can be filled by Applying width: 33.3333%
to items:
But if you wish to have a gap between the child divs, they won’t wrap as expected:
That can be solved by calc()
CSS function [1]:
.flex-item {
width: calc(33.33333% - 40px);
margin: 20px;
}
To get rid of the space in the edge of the container use negative margin on the container [3]:
.flex-container {
margin: -20px;
}
The order
property allows change to the visual order items appear in. Order is assigned to groups.
By default all flex items are set to order: 0
, which means that all items belong to the same group, and they will be positioned by source order. In case of two or more groups, groups are ordered relatively to their integer values [4].
In the example below, there are three ordinal groups
, -1
, 0
and 1
, laid out in that order.
.box-3 { order: 1; }
.box-7 { order: 1; }
.box-8 { order: -1; }
This property redistributes items visually, but keeps their original source position on interactions like traversing them with tab key. That may be taken under consideration if items order matter for accessibility. the same goes for flex-direction
[4].
In Flexbox, items alignment and space distribution along axis can be controlled by four properties [5]:
justify-content
: aligns all items in the main axisalign-items
: aligns all items in the cross axisalign-self
: aligns single items in the cross axisalign-content
: controls space between flex lines on the cross axisApplied to container, justify-content
handles items across the main axis. The six most-used options for its value are: flex-start
, flex-end
, center
, space-around
, space-between
, space-evenly
, being flex-start
the default.
Also applied to container, the align-items
property handles alignment along the cross axis. Its default value is stretch
and the other option are flex-start
, flex-end
, center
and baseline
[5].
The stretch
option makes all items stretch either to the container height, if set, or to the height of the tallest item [5]. The first picture shows container height set to 100vh
, in the second one height not set.
The last of the four properties applied to flex container, align-content
distributes spaces between flex lines in the cross axis. As the latter, its initial value is stretch
and similarly justify-content
, accepts the following options: flex-start
, flex-end
, center
, space-around
, space-between
, space-evenly
[5].
The align-items
property actually works by setting align-self
on all flex items inside a container. By setting align-self
individually, it’s possible to override the general value. It accepts the same values as align-items
and ‘auto’ [5].
The auto
option resets the align-self
to the value defined globally for the container by align-items
[5].
Sizing and flexibility of items can be controlled by three properties: flex-grow
, flex-shrink
and flex-basis
. All three act on the main axis [2].
flex-grow
: if there is extra space, how each item should be enlargedflex-shrink
: if there is not enough space, how each item should be reducedflex-basis
: before setting both properties above, what size should the item beThe flex grow factor
set by this property is a ratio that handles items size in relation to each other [7].
The default value is 0, which means that if there is available space, place it after the last item [1].
In the above example, direction
is set to row
, and each flex item width
is set to 60px
. Since the container is 980px
wide, there is 680px
of available space. That space is called positive free space
[7].
By setting flex-grow
to 1
, the amount of positive free space is equally divided between flex items. Each item will get its width increased by 136px
, totaling 196px
[7].
By appling flex-grow: 2
to the third item, it gets twice the amount of positive free space available, 286px
than the remaining items, 173px
[7].
The picture below shows items with the flex-grow
property set to its content value.
flex-shrink
handles items size, when there is not enough available space to fit them all in a container. So, it divides the negative free space
among items by shrinking them [7].
The next picture shows the 980px
container, which holds five 300px
wide items. Since there is no room to accommodate the 1500px
needed, the default flex shrink factor
value of 1
makes every item shrink evenly to 196px
.
By setting a ratio of 2
for the third item, it becomes two times smaller than the rest.
The last picture in this section shows each item holding its content value as flex shrink ratio.
flex-basis
is the property that checks what is the size each item should have before it actually setting how much space available there will be. The default value is auto
, and the item width is either explicitly set by width
property, or it takes the content width. It also accepts pixels values [7].
The gif below shows a 800px
wide container and five flex items set to flex-basis: 160px
. This tells the browser: ideally there is enough room to place all items, respecting their 160px
width, and there is no positive/negative free space. In case there is not enough space, since flex-shrink
defaults to 1
, all items are shrunk evenly. In case there is extra space, flex-grow
defaults to 0
and the empty space is place after the last item.
Next gif shows item 1 set to flex-shrink: 10
and item 4 set to flex-grow: 10
. For negative free space, item 1 get 10 times less width. And for positive free space item 4 gets 10 times more width than others.
flex-basis
also accepts the value content
, which regardless of width
being set or not, the width considered for free space calculation is the item’s content. If you do not want to consider item width for that calculation set basis to 0
.
flex
is the shorthand property for flex-grow
, flex-shrink
and flex-basis
, in that order [2].
It accepts the following predefined values:
initial
: resets to flexbox defaults, same as flex: 0 1 autoauto
: flex-items have the ability to grow/shrink as needed, same as flex: 1 1 autonone
: makes items inflexible, same as flex: 0 0 autoflex: 1
: flex-items have the ability to grow/shrink and flex-basis
is set to zero, same as flex: 1 1 0For cross browser compatibility is important to set properties with all necessary prefixes, in order to assure full support [1].
Auto prefixing every property by hand can be a very tedious task, besides making the styles very hard to maintain. Gulp is an alternative for automating those tasks.
In order to use Gulp, we have to add it to the project as a dependency. That’s done in the package.json
file, responsible for tracking dependencies and its versions. To create the file type in the terminal [1]:
🌹 npm init
You will be prompted for project’s info. Just hit enter until it’s done. Output file will be something like this:
{
"name": "project-name",
"version": "1.0.0",
"description": "Project description",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Author Name",
"license": "ISC"
}
Install gulp globally:
🌹 npm install gulp -g
Install gulp and gulp-autoprefixer as a project dependencies:
🌹 npm install gulp --save-dev
🌹 npm install gulp-autoprefixer --save-dev
They should appear in package.json
file under devDependencies
key.
Create a gulpfile.js
file:
🌹 touch gulpfile.js
Add the following [9]:
//gulpfile.js
var gulp = require('gulp');
var autoprefixer = require('gulp-autoprefixer');
gulp.task('styles', function() {
return gulp.src('./styles.css')
.pipe(autoprefixer({ browsers: ['last 2 versions'], cascade: false }))
.pipe(gulp.dest('build'));
});
gulp
extracts the content out of styles.css
and passes it through gulp-autoprefixer
. The result is placed under build
folder.