Tips to Make a Web App That Is Truly Responsive With Flexbox
Nowadays, new devices are launched every day and users browse web apps on a multitude of screen sizes. To offer a great online experience to their users, it’s become essential for businesses to make their web apps responsive — i.e., be able to display nicely no matter the screen they appear on. Fortunately, new CSS tools were created in the past years to help create such flexible layouts. On the other hand, older browsers that do not support the most recent web technologies are still used widely. For instance, in the financial industries, lots of companies use Internet Explorer 11 daily.
Here comes flexbox to the rescue! Flexbox is a CSS3 layout model that solves usually tricky problems including how to position, center or dynamically resize elements on a page. It’s a tool modern enough to create responsive designs and old enough to be implemented in major browsers.
In this article, we’ll learn some of flexbox main properties by recreating two components from Airbnb’s website.
Notes:
- I’ll be taking a desktop-first (“large screen-first”) approach which means that I will write the code for large screens and use media queries to adapt to smaller ones.
- I’m using the React library instead of regular HTML, but the syntaxes are similar so don’t worry if you aren’t familiar with React!
Responsive navigation bar
The first element I recreated is Airbnb’s navigation bar. It applies the main use case of flexbox which is to layout elements inside a container in any direction.
Let’s take a look at the final result: on large screens, page links appear on the right. On smaller ones, they are hidden by default and the user clicks on an icon to toggle the menu.

The navigation bar has two states: links always displayed on large screens, a toggled menu on smaller ones.
Here is the Javascript code for the navigation bar:
function App() {
return (
<div className="App">
<Navbar />
</div>
);
}
class Navbar extends React.Component {
constructor() {
super();
this.state = {
opened: false
};
}
toggle() {
this.setState({
opened: !this.state.opened
});
}
render() {
return (
<nav className="navbar">
<div className="navbar-home">
<a href=".">
<img
className="logo"
src="http://www.freelogovectors.net/wp-content/uploads/2016/12/airbnb_logo.png"
alt="Airbnb logo"
/>
</a>
<button className="toggle" onClick={this.toggle.bind(this)}>
<i
className={
"fas " + (this.state.opened ? "fa-angle-up" : "fa-angle-down")
}
/>
</button>
</div>
<ul
className={
"navbar-links " + (this.state.opened ? "opened" : "closed")
}
>
<li className="navbar-link">
<a href=".">Becoming a host</a>
</li>
<li className="navbar-link">
<a href=".">Help</a>
</li>
<li className="navbar-link">
<a href=".">Sign up</a>
</li>
<li className="navbar-link">
<a href=".">Log in</a>
</li>
</ul>
</nav>
);
}
}
First, let’s create the large-screen version of the navigation bar.
Setting up flexbox
We start by setting the display: flex on the .navbar parent element. The parent element is now a flex container and its child elements flex items. To manage flex items alignments, we’ll apply the properties on the flex container.

Choosing a direction for the container
We then choose the direction of the main axis of the flex container with flex-direction. The main axis controls the direction the flex items are laid out in. Here, we want it to be row so that the flex items get placed horizontally and from left to right. Defining the main axis also determines the cross axis direction which is the axis perpendicular to it.

Aligning flex items on the main axis
To position the home menu on the left and the navigation links on the right, we use the justify-content property which aligns elements along the main axis or distributes space between them. By setting its value to space-between, flexbox tells the container to leave as much space as possible between items.

Aligning items on the cross axis
To align elements on the cross axis, we specify a value for the align-items property. With the value set to stretch, flex items take all the space available in height of the flex container.

Adapting to smaller screens
To obtain the layout for smaller screens, we only need to change the direction of the .navbar and .navbar-links flex containers with flex-direction: column! The main axis is now vertical and the items are aligned from top to bottom.
Notice that elements are still stretched on the cross-axis so they still take 100% of the device’s width. However, on the main-axis, there is no space between the flex items .navbar-home and .navbar-links. This is because we did not specify any minimum height to the container.

Here is the CSS short version which deals with structuring the component:
:root {
--height-lg-screens: 80px;
}
.navbar {
display: flex;
justify-content: space-between;
/* by default: align-items: strech -> child elements' heights = the container's height */
}
.navbar-links {
display: flex;
/* align-items: stretch; by default */
}
.navbar-home,
.navbar-link {
display: flex;
align-items: center; /* we want children to be centered vertically*/
}
/**
*
* Smaller screen + Mobile
*
*/
@media screen and (max-width: 1127px) {
.navbar {
flex-direction: column; /* change the direction of the container */
}
.navbar-links {
flex-direction: column;
}
}
Responsive gallery
The second element I found really cool and decided to remake is a single-dimension gallery which adapts the image sizes and count according to the user’s screen. It ensures that the images always have a minimum size by displaying fewer images as the screen size decreases.
It shows another common use case of flexbox, which is to let it dynamically resize items within a container.
Use the free JavaScript composer, browser programs to format your client-side scripts to optimize your code!
Here is the Javascript part:
function App() {
return (
<div className="App">
<Gallery />
</div>
);
}
function Gallery() {
const images = [
{
src: "/frank-zhang.jpg",
subtitle: "Private room - Los Angeles",
title: "Stahl House, aka Case Study House #22"
},
// etc...
];
return (
<div className="gallery">
{images.map((image, key) => (
<div className="card" key={key}>
<Place image={image} />
</div>
))}
</div>
);
}
function Place({ image }) {
return (
<div className="place">
<img className="place-photo" src={image.src} alt={image.title} />
<h5 className="place-subtitle">{image.subtitle}</h5>
<h4 className="place-title">{image.title}</h4>
</div>
);
}
Here, we’ll make use of the flex-basis property.
Flex-basis lets us set an element’s initial size on the main axis (its width if the flex-direction is “row”, its height otherwise) before it is placed inside a flex container. Once inside the container, its size can change depending on the values of flex-grow and flex-shrink and the space available.
On large screens, we’d like to see 4 images. We allow 1/4 of the screen width to each card element. To do so, we can use the CSS calc function which can perform calculations on CSS property values and use it to set flex-basis to 1/4 of the total width.
flex-basis: calc(100% / 4);

As the window size decreases, the width of each element decreases as well while still taking 1/4 of the width each.

At the first breakpoint, we set flex-basis to 1/3 of the device width. Each element should now take 33% of the device’s width. However, we can’t put 4 elements of width 33% the container’s in it…😐 The default behavior is that they all get squeezed in order to fit.

By telling them explicitly not to shrink, flex elements have to take the width stated by flex-basis: 1/3 of the width each. Since we can’t fit 4 elements of width 33% the container’s AND they’re not allowed to shrink, the elements which don’t fit will be ejected from the container!
flex-shrink: 0;

That’s it!
Here’s the final CSS:
.gallery {
display: flex;
}
.card {
flex-basis: calc(100% / 4);
flex-shrink: 0; /* don't shrink, and don't wrap -> leave the container*/
}
@media screen and (min-width: 967px) and (max-width: 1127px) {
.card {
flex-basis: calc(100% / 3);
}
}
@media screen and (max-width: 967px) {
.card {
flex-basis: calc(100% / 2);
}
});
Conclusion
I hope I showed you how great flexbox is at bringing up solutions to very common problems: centering, justifying, aligning, adjusting elements to the screen size, etc… It’s truly an all-in-one tool to build modern layouts!
Lastly, another great force of flexbox to me is its straightforwardness: it makes it easy to write code which conveys intent, and that’s great when you know how verbose CSS stylesheets can get. 😅
Check out the code sandboxes below to see the full code and have a better look at the items we’ve recreated: