🏷️ #frontend #html #css

How to Position and Arrange Content Using CSS

When designing a webpage, you must understand that the elements are not independent, and you have to consider the relations between them. These elements should be arranged in a way such that it is easy for the users to make the connection visually. For example, when comparing different products, it is easier for people to see the differences when they are placed next to each other horizontally.

product compare

By default, the block-level elements will be arranged vertically, as they take all the horizontal space available. So, how can we arrange them differently to create a layout like the above example? This will be the primary problem we will tackle in this chapter.

Before we continue, please consider buying the e-book version of this course.

By purchasing this e-book, you will get access to all the accompanied source code. Thank you for your support! Happy coding! 🖥️✨

Purchase e-book || Download a sample

Display types #

Recall that at the beginning of this course, where we explored the basics of HTML, we introduced the block and inline elements. Block elements are those that automatically takes all the horizontal space available, but you can define custom width and height. Inline elements, on the other hand, only take as much space as necessary, and defining width and height has no effect on these elements.

Inline #

However, when working on real-life projects, you sometimes need to be more flexible. For example, you are trying to build a navigation bar that sits on top of the page, and you have a list of links here:

1
2
3
4
5
6
<ul>
  <li><a href="#">Link1</a></li>
  <li><a href="#">Link2</a></li>
  <li><a href="#">Link3</a></li>
  <li><a href="#">Link4</a></li>
</ul>

By default, <li> is a block element which occupies the entire horizontal line.

block list item

This would waste a lot of vertical space. To fix this issue, you can change how the <li> element is displayed using the display property.

1
2
3
li {
  display: inline;
}

inline list item

And now, the <li> will be displayed as an inline element.

Block #

You can also make an inline element behave like a block element in a similar way.

1
<div><span>#1</span><span>#2</span></div>
1
2
3
4
span {
  border: 2px solid black;
  display: block;
}

span block

Inline block #

If you need an inline element but you want to be able to specify its width and height, you can use inline-block instead.

1
2
3
4
5
6
span {
  border: 2px solid black;
  display: inline-block;
  width: 100px;
  height: 50px;
}

inline block

display vs. visibility #

display can also control whether or not an element is rendered in the webpage. If you set display to none, the element will not be displayed. This can create useful features when combined with JavaScript, allowing you to toggle the element on and off.

This is very similar to another CSS property called visibility. Their difference is that when visibility is set to hidden, the element is still in the webpage, just not displayed by the browser. It will take up the same space as before. When display is set to none, the element will be completely removed from the webpage.

The display property is probably the most important property we are going to cover in this chapter. It also accepts values such as grid, flex, etc. These values require a deeper understanding of CSS, so we will come back to this topic later. Let’s start easy and first discuss how to place individual elements in a webpage.

How to position elements #

The position property controls how you wish to position an element. There are five different position methods available, including static, relative, fixed, absolute, and sticky. static is the default positioning method, meaning the element is not positioned in any special way. But things start to get more interesting, starting from the relative position.

Relative position #

With the relative positioning, the element will be placed relative to its default position. Its position can be adjusted by setting the left, right, top, or bottom properties.

1
2
<p>. . .</p>
<p class="relative">. . .</p>
1
2
3
4
5
6
7
8
p {
  border: 2px solid black;
}

p.relative {
  position: relative;
  left: 100px;
}

position relative

Fixed position #

fixed position means that the element is positioned relative to the viewport. This method can be useful when you need to create a component, such as a navigation bar, that always stays at the top of the webpage, no matter the user’s scrolling position. Or when you need to pop up window that stays at the bottom right corner.

1
2
<p>. . .</p>
<p class="fixed">This element is fixed.</p>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
p {
  border: 2px solid black;
}

p.fixed {
  border: 2px solid orange;
  background-color: bisque;
  height: 100px;
  width: 100px;
  position: fixed;
  right: 0px;
  bottom: 0px;
}

position fixed

The right and bottom properties together anchor the <div> element to the bottom right corner of the webpage.

Absolute position #

If an element has the absolute position, it will be placed according to its closest positioned ancestor (has position method other than static).

1
2
3
4
<div class="relative">
  This div has relative position
  <div class="absolute">This div has absolute position</div>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
div.relative {
  border: 2px solid black;
  width: 500px;
  height: 100px;
  position: relative;
  left: 10px;
}

div.absolute {
  border: 2px solid red;
  width: 250px;
  height: 50px;
  position: absolute;
  right: 10px;
  bottom: 0px;
}

absolute position

In this example, .relative is a 500x100px box with relative position, and .absolute is a smaller box placed inside .relative. As you can see, the .absolute box is positioned relative to the .relative box, instead of the viewport.

If the absolute element does not have a positioned ancestor, it will be positioned relative to the viewport, making it behave like a fixed element.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
div.relative {
  border: 2px solid black;
  width: 500px;
  height: 100px;
}

div.absolute {
  border: 2px solid red;
  width: 250px;
  height: 50px;
  position: absolute;
  right: 10px;
  bottom: 0px;
}

absolute position without positioned ancestor

Sticky position #

The sticky option is similar to fixed, except that the element will only be fixed when a specific scroll threshold is reached. Like the left sidebar in this page.

1
2
3
4
5
<p>Lorem ipsum dolor sit amet . . .</p>
<p class="sticky">
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatibus, sit!
</p>
<p>. . .</p>
1
2
3
4
5
6
p.sticky {
  border: 2px solid orange;
  background-color: bisque;
  position: sticky;
  top: 0px;
}

position sticky

Transforming elements #

After you’ve placed the element to the desired position, sometimes you also need to transform that element, like rotating or scaling it, to make the webpage look more appealing. This is the job for the transform property, which accepts the following functions/methods:

  • translate(), translateX(), and translateY()
  • scale(), scaleX(), and scaleY()
  • rotate()
  • skew(), skewX(), and skewY()
  • matrix()

The translate(x,y) method moves the element along the X-axis and Y-axis. For instance, translate(20px, 30px) will move the element 20px to the right and 30px down.

1
2
<div class="original">Original</div>
<div class="transformed">Transformed</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
div {
  border: 2px solid orange;
  background-color: bisque;
  padding: 5px;
  width: 100px;
  height: 60px;
  position: fixed;
  top: 0px;
  left: 0px;
}

.transformed {
  transform: translate(20px, 30px);
}

Having a fixed position ensures that both blocks start at the same location.

translate

Negative values are also accepted here, which moves the element to the left or up.

1
2
3
.transformed {
  transform: translate(-20px, -30px);
}

translate with negative values

translateX(n) and translateY(n) are two of its variants. translateX(n) moves the element along the X-axis, and translateY(n) moves the element along the Y-axis.

The scale(width, height) alters the size of the element based on its original size. For instance, scale(3,2) will increase the element’s size to three times its original width and two times its original height.

1
2
3
4
.transformed {
  transform: scale(3, 2);
  background-color: rgb(255, 228, 196, 0.5);
}

scale

To shrink the original element, use decimal numbers.

1
2
3
4
.transformed {
  transform: scale(0.3, 0.2);
  background-color: rgb(255, 228, 196, 0.5);
}

scale shrink

Similarly, scaleX(width), and scaleY(height) are two of its variants.

The rotate(degree) method, as the name suggests, rotates the original element along its center point, either clockwise (positive values) or counter-clockwise (negative values).

1
2
3
4
.transformed {
  transform: rotate(45deg);
  background-color: rgb(255, 228, 196, 0.5);
}

rotate clockwise

1
2
3
4
.transformed {
  transform: rotate(-45deg);
  background-color: rgb(255, 228, 196, 0.5);
}

rotate counter-clockwise

The skew(x,y) method skews the element along X-axis and Y-axis.

1
2
3
4
.transformed {
  transform: skew(20deg, 30deg);
  background-color: rgb(255, 228, 196, 0.5);
}

skewed

And just like the other variants, skewX(n) skews the element along the X-axis, and skewY(n) skews the element along the Y-axis.

Lastly, the matrix() method combines all the methods discussed above, allowing you to define multiple transforms at once. The syntax is as follows:

1
matrix(scaleX(), skewY(), skewX(), scaleY(), translateX(), translateY())

Notice how rotate() is missing from this syntax? That is because the rotation degree (θ) can be derived from the following equation:

1
θ = atan2(skewY(), scaleX()) * (180 / π)

Where atan2(b, a) is an arctangent function that takes two values and returns the angle whose tangent is the quotient of b and a. (180 / π) then converts radiant to degrees.

I know that is a lot of math for a web development course, so I suggest you avoid using the matrix() function if possible. You might have to write more code and use more functions to achieve the same result, but it will make the code much easier to understand, and sometimes, that is much more crucial than writing fewer code.

How to align elements #

Aligning elements is another important topic in web design. Making sure the elements are properly aligned allows you to create well-structured and visually pleasing webpages. Let’s start by discussing how to center an element.

Horizontally center an element #

Recall that we discussed the box model in the previous chapter and learned about margin, which is space added outside the border. To horizontally center an element, you can simply set the left and right margin to auto.

1
2
3
<div>
  <p>Lorem ipsum dolor . . .</p>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
div {
  border: 2px solid black;
  width: 500px;
  height: 300px;
}

p {
  border: 2px solid red;
  width: 250px;
  height: 150px;
  margin-left: auto;
  margin-right: auto;
}

horizontally center element

In this example, we have two boxes with different sizes. By setting the horizontal margin of the smaller box to auto, your browser will automatically add equal space on both the left and right side of the paragraph element, hence centering the box horizontally.

Vertically center an element with padding #

When it comes to vertically centering elements, things get more complicated. The first solution is to add vertical padding to the bigger box <div>. Unfortunately, there isn’t a simple auto option you can use here, and you’ll have to do some calculations.

The bigger box is 300px high, and the smaller box is 150px high. The center of the smaller box is at 75px. So if we push the box down 75px, it should align with the center of the bigger box, which is at 150px.

However, when you implement this solution, you will get a different result.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
div {
  border: 2px solid black;
  width: 500px;
  height: 300px;
  padding-top: 75px;
}

p {
  border: 2px solid red;
  width: 250px;
  height: 150px;
}

vertically center element with padding

The top space is smaller than the bottom space. That is because we haven’t set the box-sizing property yet. By default, when the browser is calculating the height/width of an element, it only counts the content and does not include padding or the border width. For example:

1
2
3
4
5
6
div {
  border: 10px solid black;
  padding: 20px 0;

  height: 100px;
}

This box has a 10px thick border and 20px vertical padding. And we define its height to be 100px. But the actual height, as you can see, is 160px.

box sizing

The actual height, if you are counting border to border, equals two borders (20px), plus two paddings (40px), and plus the height of the content (100px), which is 160px.

This can be very annoying as when we define the size of an element, we mean the box, from border to border, not just the content. Luckily, this can be changed using the box-sizing property we discussed in the previous chapter. It is set to content-box by default, and you need to change it to border-box.

1
2
3
4
5
6
7
div {
  box-sizing: border-box;
  border: 10px solid black;
  padding: 20px 0;

  height: 100px;
}

border box

Now, go back to our original problem. When trying to center an element using paddings, you must set box-sizing: border-box;, so that the browser counts the border width and paddings as part of the total height.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
* {
  box-sizing: border-box;
}

div {
  border: 2px solid black;
  width: 500px;
  height: 300px;
  padding-top: 75px;
}

p {
  border: 2px solid red;
  width: 250px;
  height: 150px;
}

Using the wildcard selector (*) makes sure that all boxes in the webpage have the same behavior.

vertically center element

But wait, now we have another problem. The bottom space is now smaller than the top. This is because the <p> element comes with a default 16px vertical margin. So you are actually pushing the element down 75px + 16px = 91px. To fix that, you need to set the paragraph box’s margin to 0.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
* {
  box-sizing: border-box;
}

div {
  border: 2px solid black;
  width: 500px;
  height: 300px;
  padding-top: 75px;
}

p {
  border: 2px solid red;
  width: 250px;
  height: 150px;
  margin: 0;
}

margin removed

Personally, I like to remove all default margins and paddings for all elements, so I would put this at the top of my CSS file:

1
2
3
4
5
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

Vertically center an element using position and transform #

However, using paddings requires you to know the exact height of the boxes, but what if you don’t have that information? For example, you are trying to display texts submitted by the user, and you don’t know the length of that text. How can you vertically center it in this scenario?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
* {
  box-sizing: border-box;
}

div {
  border: 2px solid black;
  width: 500px;
  height: 300px;
}

p {
  border: 2px solid red;
  width: 300px;
  margin: 0;
}

center text of arbitrary length

In this example, the paragraph only has the width set. Its height depends on the length of the text, which we do not know. In this case, we could utilize the combination of position and transform we just discussed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
* {
  box-sizing: border-box;
}

div {
  border: 2px solid black;
  width: 500px;
  height: 300px;
  position: relative;
}

p {
  border: 2px solid red;
  width: 300px;
  margin: 0;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

First of all, the absolute position, along with top: 50%; and left: 50%; will place the top left corner of the red box to the center point of the black box.

absolute position, top 50% and left 50%

And then translate(-50%, -50%) shifts the paragraph element’s position back by 50% of its own width and height, aligning its center point with the black box’s center point.

center element with position and transform

This technique ensures that the smaller box will always be centered inside the bigger box, even if the text is longer or shorter.

center longer text

Centering an element inside another element sounds like an easy task, but as you can see, it actually requires you to have a deep understanding of CSS.

Left and right align elements #

When it comes to aligning elements to the left or right, the most straightforward solution is, of course, the absolute position.

1
2
3
<div class="container">
  <div class="div1">#1</div>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
.container {
  border: 2px solid black;
  width: 500px;
  height: 300px;
  position: relative;
}

.div1 {
  background-color: #e63946;
  position: absolute;
  right: 0px;
}

absolute position right align

However, what if you have multiple <div> elements and want to put them in the same horizontal line but aligned to the left/right? You could micromanage each of them, but you would have to know the exact width of each element. A better solution is to use another property called float.

The following chart shows a common webpage layout with images and texts. The text flows around the image instead of letting the image take up the entire line, which wastes a lot of space.

float

This effect is achieved with the float property. When an element is floated, it is taken out of the normal flow of the document, and other elements wrap around it based on the available space. For instance, you can make the image float to the left.

1
2
3
4
<div class="container">
  <img src="images/image.jpg" alt="image" />
  <p>Lorem ipsum dolor sit . . .</p>
</div>
1
2
3
4
img {
  max-width: 200px;
  float: left;
}

float left

Or you can also make the image float to the right.

1
2
3
4
img {
  max-width: 200px;
  float: right;
}

float right

Multiple elements can also float together.

1
2
3
4
<div class="left">#1</div>
<div class="left">#2</div>
<div class="right">#3</div>
<p>. . .</p>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
div {
  padding: 20px 40px;
  border: 2px solid black;
}

.left {
  float: left;
}

.right {
  float: right;
}

float multiple elements

Creating grids #

Creating layouts using CSS is one of the most fundamental skills a web developer must possess. A well-designed layout is the backbone of any successful website, as it improves user experience, visual appeal, and overall usability. There are two ways you can create a webpage layout using CSS, either with grids or the flexbox. Let’s start with the traditional method and discuss how to create a grid layout.

A grid layout consists of a grid container and several grid items. The grid container must have its display property set to grid or inline-grid. grid creates a block-level grid container, and inline-grid creates an inline-level grid container.

1
2
3
4
5
6
7
8
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
</div>
1
2
3
.container {
  display: grid;
}

All direct children of this container will automatically become grid items.

Grid columns and rows #

You can then specify how many columns you wish to create using the grid-template-columns property. The property accepts any number of values. The number of values determines the number of columns, and the value itself determines the size of that column. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
.container {
  display: grid;
  grid-template-columns: 100px 200px;
}

.item {
  font-family: Georgia, "Times New Roman", Times, serif;
  font-size: x-large;
  text-align: center;
  padding: 20px;
  border: 1px solid orange;
  background-color: bisque;
}

grid with two columns

I also added some styles for the grid items to make the grid look more pleasing, but it is not necessary here, so I will omit them in future examples.

1
2
3
4
.container {
  display: grid;
  grid-template-columns: 100px 200px 50px;
}

grid with three columns

If you want all columns to have equal size, simply set the values to auto.

grid with auto columns

Similarly, you can specify row sizes using the grid-template-rows property.

1
2
3
4
5
.container {
  display: grid;
  grid-template-columns: auto auto auto;
  grid-template-rows: 100px 150px;
}

grid with different row heights

However, this property does not determine the number of rows in the grid. If you specify extra values, they will be ignored.

Lastly, grid-template is a shorthand property for grid-template-columns and grid-template-rows with the following syntax:

1
grid-template: <row> <row> ... / <col> <col> ...;
1
2
3
4
.container {
  display: grid;
  grid-template: 100px 150px / auto auto auto;
}

grid template

Grid gaps #

When designing a webpage, it is good to leave some space between elements so that they are not too close to each other. By using the grid layout, you can easily add equal spacing between all grid items instead of micromanaging each margin. For example:

1
2
3
4
5
6
.container {
  display: grid;
  grid-template-columns: auto auto auto;
  row-gap: 10px;
  column-gap: 20px;
}

gaps

Alternatively, you may use the shorthand property, gap:

1
2
3
4
5
.container {
  display: grid;
  grid-template-columns: auto auto auto;
  gap: 10px 20px;
}

If you want equal spacing for column gaps and row gaps, specify a single value:

1
2
3
4
5
.container {
  display: grid;
  grid-template-columns: auto auto auto;
  gap: 10px;
}

gaps with equal spacing

Grid items #

It is also possible for you to customize individual grid items using CSS. In a real-life scenario, it is common for one grid item to take up multiple columns or rows. For example, you can define an item to span across multiple columns by specifying a start point (grid-column-start) and an end point (grid-column-end).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<div class="container">
  <div class="item-2col">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.container {
  display: grid;
  grid-template-columns: auto auto auto;
  gap: 10px;
}

.item {
  . . .
}

.item-2col {
  grid-column-start: 1;
  grid-column-end: 3;
}

grid item two columns

Keep in mind that the numbers refer to the column lines, not columns, as shown in the chart below.

column lines and row lines

So, for an item to span across two columns, it should start from 1 and end with 3.

You can also use the shorthand property grid-column to achieve the same result:

1
2
3
.item-2col {
  grid-column: 1 / 3;
}

Similarly, you can define a grid item to span across multiple rows using the grid-row-start and grid-row-end properties, or the grid-row shorthand.

1
2
3
4
.item-2row {
  grid-row-start: 1;
  grid-row-end: 3;
}
1
2
3
.item-2row {
  grid-row: 1 / 3;
}

grid row

If an item needs to span across multiple rows and columns, you can use the grid-area property instead, which is a shorthand for grid-row and grid-column. It has the following syntax:

1
grid-area: <row_start> / <col_start> / <row_end> / <col_end>
1
2
3
.item-area {
  grid-area: 1 / 1 / 3 / 3;
}

grid area

Grid alignment #

Just like aligning individual elements in a webpage, when aligning items in a grid, we also have to talk about horizontal and vertical directions. However, things are a bit more complex than that. There are six different alignment properties, as shown in the list below:

  • align-content
  • align-items
  • align-self
  • justify-content
  • justify-items
  • justify-self

Vertical alignment #

Let’s discuss each of them one by one. First of all, the align properties control vertical alignment. As an example, this is a grid with six items, and the grid container is 300px high:

1
2
3
4
5
6
7
8
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
</div>
1
2
3
4
5
6
.container {
  display: grid;
  grid-template-columns: auto auto auto;
  gap: 10px;
  height: 300px;
}

The align-content property is used to specify the alignment of rows when there is available space in the container. Common values include:

  • start

    1
    2
    3
    
    .container {
      align-content: start;
    }
    

    align content start

  • end

    1
    2
    3
    
    .container {
      align-content: end;
    }
    

    align content end

  • center

    1
    2
    3
    
    .container {
      align-content: center;
    }
    

    align content center

  • space-between

    1
    2
    3
    
    .container {
      align-content: space-between;
    }
    

    align content space between

  • space-around

    1
    2
    3
    
    .container {
      align-content: space-around;
    }
    

    align content space around

  • space-evenly

    1
    2
    3
    
    .container {
      align-content: space-evenly;
    }
    

    align content space evenly

  • stretch

    1
    2
    3
    
    .container {
      align-content: stretch;
    }
    

    align content stretch

align-items, on the other hand, is used to align individual grid items within their respective grid cells along the block axis. This is especially useful when grid items have different heights. Common values include:

  • start

    1
    2
    3
    
    .container {
      align-items: start;
    }
    

    align items start

  • end

    1
    2
    3
    
    .container {
      align-items: end;
    }
    

    align items end

  • center

    1
    2
    3
    
    .container {
      align-items: center;
    }
    

    align items center

  • stretch

    1
    2
    3
    
    .container {
      align-items: stretch;
    }
    

    align items stretch

  • baseline

    1
    2
    3
    
    .container {
      align-items: baseline;
    }
    

    align items baseline

Lastly, the align-self property works just like align-items, except it is used on individual grid cells, not the container. It will overwrite the alignment rule set by align-items.

1
2
3
4
5
6
7
.container {
  align-items: start;
}

.item-sm {
  align-self: end;
}

align self

Horizontal alignment #

The horizontal alignment, controlled by the justify properties, works in a similar way. First, the justify-content property defines how grid items are distributed horizontally along the main axis. Some common values are:

  • start

    1
    2
    3
    
    .container {
      justify-content: start;
    }
    

    justify content start

  • end

    1
    2
    3
    
    .container {
      justify-content: end;
    }
    

    justify content end

  • center

    1
    2
    3
    
    .container {
      justify-content: center;
    }
    

    justify content center

  • space-between

    1
    2
    3
    
    .container {
      justify-content: space-between;
    }
    

    justify content between

  • space-around

    1
    2
    3
    
    .container {
      justify-content: space-around;
    }
    

    justify content around

  • space-evenly

    1
    2
    3
    
    .container {
      justify-content: space-evenly;
    }
    

    justify content evenly

The justify-items controls how grid items are aligned horizontally within their cells. Some common values are:

  • start

    1
    2
    3
    
    .container {
      justify-items: start;
    }
    

    justify items start

  • end

    1
    2
    3
    
    .container {
      justify-items: end;
    }
    

    justify items end

  • center

    1
    2
    3
    
    .container {
      justify-items: center;
    }
    

    justify items center

  • stretch

    1
    2
    3
    
    .container {
      justify-items: stretch;
    }
    

    justify items stretch

Similarly, the justify-self property is used on individual grid items to overwrite the default alignment rule set by justify-items.

1
2
3
4
5
6
7
.container {
  justify-items: start;
}

.item-sm {
  justify-self: end;
}

justify self

Flexbox layout #

The flexbox is another layout model in CSS that provides an efficient way to design and structure complex layouts, but with a more flexible approach. It is particularly suited for creating one-dimensional layouts, either in a row or a column, as we will see later.

Just like a grid layout, a flexbox layout also consists of a flex container and several flex items. The container should have its display property set to flex, and all its direct children automatically become flex items.

1
2
3
4
5
6
7
8
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
</div>
1
2
3
4
.container {
  display: flex;
  gap: 10px;
}

With a flex layout, instead of rows and columns, you must define a flex-direction and a flex-wrap. The flex-direction specifies in which direction the container should stack its flex items. The accepted values are:

  • column

    1
    2
    3
    
    .container {
      flex-direction: column;
    }
    

    flex direction column

  • column-reverse

    1
    2
    3
    
    .container {
      flex-direction: column-reverse;
    }
    

    flex direction column reverse

  • row

    1
    2
    3
    
    .container {
      flex-direction: row;
    }
    

    flex direction row

  • row-reverse

    1
    2
    3
    
    .container {
      flex-direction: row-reverse;
    }
    

    flex direction row reverse

The flex-wrap property determines whether the flex items should wrap (automatically change to the following line when there is insufficient space).

  • wrap

    1
    2
    3
    
    .container {
      flex-wrap: wrap;
    }
    

    flex wrap

  • nowrap

    1
    2
    3
    
    .container {
      flex-wrap: nowrap;
    }
    

    flex nowrap

  • wrap-reverse

    1
    2
    3
    
    .container {
      flex-wrap: wrap-reverse;
    }
    

    flex wrap reverse

The flex-flow is a shorthand for flex-direction and flex-wrap properties.

1
2
3
.container {
  flex-flow: column wrap;
}

flex flow

Lastly, the alignment properties for the grid layout we discussed before also work for flexbox layouts. For example:

1
2
3
4
5
6
7
.container {
  flex-direction: row;
  flex-wrap: wrap;

  align-content: center;
  justify-content: center;
}

flex alignment

A practical example #

Before we wrap up this chapter, let’s go back to the original question: how do we create a product compare section with different products placed side by side like this:

product compare

Let’s start with the HTML code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Product Compare</title>

    <link rel="stylesheet" href="style.css" />
  </head>

  <body>
    <div class="container">
      <div class="product-card">
        <img src="images/1.jpg" alt="product 1" class="product-img" />
        <h2 class="product-title">Cat #1</h2>
        <p class="product-description">Lorem ipsum . . .</p>
      </div>
      <div class="product-card">
        <img src="images/2.jpg" alt="product 1" class="product-img" />
        <h2 class="product-title">Cat #2</h2>
        <p class="product-description">Lorem ipsum . . .</p>
      </div>
      <div class="product-card">
        <img src="images/3.jpg" alt="product 1" class="product-img" />
        <h2 class="product-title">Cat #3</h2>
        <p class="product-description">Lorem ipsum . . .</p>
      </div>
    </div>
  </body>
</html>

Here, we have a container with three different product-card. The container should be either a grid or a flexbox. I’ll use the grid as an example:

1
2
3
4
5
.container {
  display: grid;
  grid-template-columns: 250px 250px 250px;
  gap: 20px;
}

The container is a grid layout with three columns. Each column is 250px wide and with a 20px gap between each column.

Next, each product-card should have a border, and there should be padding between the border and the content.

1
2
3
4
5
.product-card {
  padding: 10px;
  border: black solid 2px;
  border-radius: 10px;
}

Lastly, you need to ensure the image fits inside the defined space by setting a with and height.

1
2
3
4
5
.product-img {
  width: 100%;
  height: 200px;
  object-fit: cover;
}

However, the images come in many different sizes, so they might not fit inside the defined space. The object-fit: cover; property makes sure the image will not be stretched or squished. We will discuss more about this property in the next chapter.

This will be the final result:

product compare result

Conclusion #

In this chapter, we covered some essential aspects of webpage layout and design, including display types, element positioning, transformation, and alignment techniques. We also explored the power of grids and flexbox layouts, providing the necessary skills for creating adaptable and visually appealing designs. As we move forward, the upcoming chapter will delve into responsive design techniques, allowing you to create webpages that seamlessly cater to various devices and screen sizes.

Continue to the next chapter…


If you think my articles are helpful, please consider making a donation to me. Your support is greatly appreciated.

Subscribe to my newsletter ➡️

✅ News and tutorials every other Monday

✅ Unsubscribe anytime

✅ No spam. Always free.