The Flexible Box
In CSS April 7, 2023
Updated on May 13, 2023
In this tutorial, we will deal with the flexible box. The first version of the flexbox layout module was introduced as a Candidate Recommendation by the World Wide Web Consortium (W3C) in 2012. In 2016 the final version of the specification was published as a W3C Recommendation.
Let's start by creating a new project folder. In the terminal we type:
mkdir restaurant_menu
Let's change directories into its folder:
cd restaurant_menu
Next, we will create two files: index.html
and index.css
:
touch index.html index.css
We will start by editing the index.html
file. We will add a Doctype
declaration, an
html
element, and a head
and a body
elements inside the html
element. Inside the head
element, we will add a viewport
meta tag, import the EB
Garamond font from Google Fonts, link to the index.css
file, and finally add
a title :
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=EB+Garamond:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/index.css">
<title>Our Restaurant Menu</title>
</head>
<body></body>
</html>
Let's edit the index.css
file to make use of the font we imported and to add some basics styles to our
document:
body {
font-family: "EB Garamond", serif;
font-size: 16px;
font-weight: 400;
max-width: 1280px;
}
Inside the body element, we will add an h1 heading:
...
<body>
<h1>Our Menu</h1>
</body
Let's style this element in index.css
:
h1 {
text-align: center;
font-weight: 700;
font-size: 32px;
margin-bottom: 30px;
}
Our menu will have four sections: Appetizers, Soups, Main Courses, and Desserts.
We will wrap the four sections inside a div element, which is a flex container:
<div class="menu-container">
</div>
Let's style it. To turn this element into a flex container, we will utilize the display
property and
assign the value of flex
to it.
.menu-container {
display: flex;
}
The first section of our menu is the Appetizers section. Below is the HTML:
<section class="menu-section">
<h2>Appetizers</h2>
<ul>
<li>
<div class="menu-title">
<div>
<span class="menu-number">01.</span>
<span class="menu-text">Crispy Fried Calamari</span>
</div>
<span>$12</span>
</div>
<p>A classic appetizer with a crispy exterior and tender, flavorful calamari inside.
<p>
</li>
<li>
<div class="menu-title">
<div>
<span class="menu-number">02.</span>
<span class="menu-text">Baked Stuffed Mushrooms</span>
</div>
<span>$9</span>
</div>
<p>Plump and juicy mushrooms filled with savory stuffing and baked to perfection.</p>
</li>
<li>
<div class="menu-title">
<div><span class="menu-number">03.</span>
<span class="menu-text">Cheese and Charcuterie Board</span>
</div>
<span>$15</span>
</div>
<p>A delightful assortment of artisanal cheeses, cured meats, nuts, and fruit.</p>
</li>
</ul>
</section>
Let's add some basics styles to the h2 and ul elements:
h2 {
font-size: 24px;
font-weight: 700;
}
ul {
list-style-type: none;
padding: 0;
}
Please notice the structure of our menu. The menu is numbered, and each item has a title with the name and the price. Below this title is a short description of the dish.
The paragraph with the class of menu-title is a flex container:
.menu-title {
display: flex;
}
The content in a flex container can be laid out in any direction. To determine the arrangement of items within a flex
container, we use the flex-direction
property, which sets the direction of the main axis of the flex
container. Its default value is row
. That means that the direction of the main axis is the same as the
inline direction of the current writing mode. The initial value of our writing mode is left-to-right since we use
English as our document language. We want the content of this paragraph to be laid out leftwards, so we don't
need to specify any value for the flex-direction
property.
If we would change the direction of the flow, from right to left, we would set the value of this property to
row-reverse
.
If we would like to change our items' direction from top to bottom, we will use the column
value for this
property. If we would like to reverse the flow, from bottom to top, we would use the column-reverse
value.
We want the name of the dish on the left, and the price to be pushed to the right. How can we achieve that? We will
use the justify-content
property, which aligns items along the main axis of the current line of the flex
container. Its initial value is flex-start
, which means the items are packed at the start of the
line. We will change this value to space-between
, which will distribute the items evenly along the line:
justify-content: space-between;
Other possible values of this property are flex-end
, center
, space-around
, and
space-evenly
.
The flex-end
value aligns items to the end of the line.
-
The
center
value centers the items along the line.
The space-around
value distributes the items evenly along the line with equal space around them.
The space-evenly
value distributes the items evenly along the line with equal space around them and at
the beginning and end of the line.
Let's add a right margin to the span with the menu-number class:
.menu-number {
margin-right: 10px;
}
We'll also change the color of the span with the menu-text class and make it bold:
.menu-text {
color: #7b5f2a;
font-weight: 700;
}
Between the name of the dish and its price, we'll add a decorative border. Let's change our html to include another span element between the number and the name:
<section class="menu-section">
<h2>Appetizers</h2>
<ul>
<li>
<div class="menu-title">
<div>
<span class="menu-number">01.</span>
<span class="menu-text">Crispy Fried Calamari</span>
</div>
<span class="decorative-border"></span>
<span>$12</span>
</div>
<p>A classic appetizer with a crispy exterior and tender, flavorful calamari inside.
<p>
</li>
<li>
<div class="menu-title">
<div>
<span class="menu-number">02.</span>
<span class="menu-text">Baked Stuffed Mushrooms</span>
</div>
<span class="decorative-border"></span>
<span>$9</span>
</div>
<p>Plump and juicy mushrooms filled with savory stuffing and baked to perfection.</p>
</li>
<li>
<div class="menu-title">
<div><span class="menu-number">03.</span>
<span class="menu-text">Cheese and Charcuterie Board</span>
</div>
<span class="decorative-border"></span>
<span>$15</span>
</div>
<p>A delightful assortment of artisanal cheeses, cured meats, nuts, and fruit.</p>
</li>
</ul>
</section>
And add a styling rule in index.css
:
.decorative-border {
border-bottom: 1px dotted black;
}
We don't see this span because it has no width. But we can make this item grow using the flex-grow
property, which sets how much an item will grow relative to the items in the same flex container. Its initial value is
0. But, if we set its value to 1, this item will take up all the available space. Let's do it:
flex-grow: 1
The opposite of the flex-grow
property is the flex-shrink
property. This property sets how
much a flex item will shrink relative to the flex items in the container when negative space is distributed. Its
initial value is 1.
The flex
shorthand property sets the flex-grow
property, and the flex-shrink
property, along with another property called flex-basis
, which sets the main size of a flex item. It is
advised to use the flex
shorthand property when possible. We will use here the auto
value,
which makes the item fully flexible, meaning it will occupy all the available space. This auto
value is
equivalent to flex: 1 1 auto
.
So let's use the flex
property instead of the flex-grow
property:
flex: auto;
Let's add some margins to the left and right of this border:
margin: 0 10px;
Now let's add another section to our menu. Let's open the index.html
file and add this below the
Appetizer section:
<section class="menu-section">
<h2>Soups</h2>
<ul>
<li>
<div class="menu-title">
<div>
<span class="menu-number">01.</span>
<span class="menu-text">Lobster Bisque</span>
</div>
<span class="decorative-border"></span>
<span>$12</span>
</div>
<p>A creamy and decadent soup made with tender chunks of lobster and savory broth.</p>
</li>
<li>
<div class="menu-title">
<div>
<span class="menu-number">02.</span>
<span class="menu-text">Tomato and Basil Soup</span>
</div>
<span class="decorative-border"></span>
<span>$8</span>
</div>
<p>A comforting and classic soup made with fresh tomatoes and fragrant basil.</p>
</li>
<li>
<div class="menu-title">
<div>
<span class="menu-number">03.</span>
<span class="menu-text">Butternut Squash Soup</span>
</div>
<span class="decorative-border"></span>
<span>$10</span>
</div>
<p>A rich and creamy soup with sweet roasted butternut squash and warm spices.</p>
</li>
</ul>
</section>
The two sections are side by side now because the initial value of the flex-direction
property is
row
. That's why we will change it to column
. Let's add this inside the styling rule for our
container:
.menu-container {
display: flex;
flex-direction: column;
}
Now it looks better on small devices, but on large devices, we want two columns, because it is a lot of space. So let's add a rule for devices larger than 1024px:
@media only screen and (min-width: 1024px) {
.menu-container {
flex-flow: row wrap;
}
}
On large devices, we will add some margins to the sections too. Add this inside the @media
rule :
.menu-section {
margin: 0 auto 40px;
}
To achieve a two-column layout for large devices, we'll use the flex
property to set its size and add
some white space between them:
flex: 0 1 calc(50% - 60px);
It is equivalent to:
flex-grow: 0;
flex-stretch: 1;
flex-basis: calc(50% - 60px);
Now, let's add another two sections to our menu:
<section class="menu-section">
<h2>Main Courses</h2>
<ul>
<li>
<div class="menu-title">
<div>
<span class="menu-number">01.</span>
<span class="menu-text">Pan-Seared Salmon</span>
</div>
<span class="decorative-border"></span>
<span>$22</span>
</div>
<p>A succulent and flavorful fillet of salmon, seared to perfection and served with a fresh herb
salad.</p>
</li>
<li>
<div class="menu-title">
<div>
<span class="menu-number">02.</span>
<span class="menu-text">Grilled Ribeye Steak</span>
</div>
<span class="decorative-border"></span>
<span>$28</span>
</div>
<p>A juicy and tender ribeye steak, grilled to your liking and served with garlic mashed potatoes
and
grilled
vegetables.</p>
</li>
<li>
<div class="menu-title">
<div>
<span class="menu-number">03.</span>
<span class="menu-text">Roasted Vegetable Lasagna</span>
</div>
<span class="decorative-border"></span>
<span>$30</span>
</div>
<p>Layered pasta, creamy ricotta, and roasted vegetables topped with marinara sauce.</p>
</li>
</ul>
</section>
<section class="menu-section">
<h2>Desserts</h2>
<ul>
<li>
<div class="menu-title">
<div>
<span class="menu-number">01.</span>
<span class="menu-text">Tiramisu</span>
</div>
<span class="decorative-border"></span>
<span>$6</span>
</div>
<p>Classic Italian dessert made with layers of espresso-soaked ladyfingers and creamy mascarpone
cheese.</p>
</li>
<li>
<div class="menu-title">
<div>
<span class="menu-number">02.</span>
<span class="menu-text">Key Lime Pie</span>
</div>
<span class="decorative-border"></span>
<span>$6</span>
</div>
<p>Tart and sweet pie made with fresh key lime juice and a graham cracker crust.</p>
</li>
<li class="list-item">
<div class="menu-title">
<div>
<span class="menu-text">03.</span>
<span class="menu-text">Raspberry Cheesecake</span>
</div>
<span class="decorative-border"></span>
<span>$6</span>
</div>
<p>Cheesecake with graham cracker crust and raspberry sauce.</p>
</li>
</ul>
</section>
Notice how they occupy a new line on large devices.
Conclusion
We have built a simple restaurant menu web page using the Flexbox layout. The layout adjusts to different screen sizes in a flexible manner. In today's digital landscape, where users access websites on a wide range of devices with varying screen sizes and capabilities, flexible and adaptable web design is more important than ever. Furthermore, using Flexbox allows us to create complex layouts with less code, making our web pages more efficient and easier to maintain. In conclusion, mastering the use of CSS Flexbox is a valuable skill for any web developer. Due to its flexibility and ease of use, it allows us to create beautiful and responsive layouts that improve the user experience on a wide range of devices.