Main Content
This area flexes to fill the available space. The layout adjusts responsively on smaller screens.
Module 6: Modern CSS & Layouts - Monday (Lecture 2)
In our previous lecture, we introduced the fundamental concepts of Flexbox and briefly touched on its properties. In this lecture, we'll do a deep dive into flex container properties, exploring each in detail with examples and real-world applications.
Remember, the flex container is the parent element that has display: flex or display: inline-flex applied to it. The properties we'll explore in this lecture control how the flex container behaves and how it lays out its children (the flex items).
These properties work together to give you precise control over how your layout behaves. Let's explore each in detail.
The display property with values flex or inline-flex is what creates a flex container in the first place. This is the foundation of Flexbox.
This creates a block-level flex container, similar to display: block. The container takes up the full width available and starts on a new line.
This creates an inline-level flex container, similar to display: inline-block. The container only takes up as much width as necessary and doesn't force a new line.
/* Block-level flex container */
.container {
display: flex;
}
/* Inline-level flex container */
.container {
display: inline-flex;
}
The key difference is in how the container itself behaves in the document flow, not in how the flex items inside it are laid out. Choose flex when you want the container to take up the full width of its parent, and inline-flex when you want multiple flex containers to sit side by side.
display: flex is typically used for main navigation menus that span the full width of a header, while inline-flex might be used for a group of related buttons that should appear inline with other content.
The flex-direction property establishes the main axis, determining the direction in which flex items are placed in the flex container. This property fundamentally affects how your layout works, as it defines what "start" and "end" mean in your flex container.
/* Main axis from left to right (default) */
.container {
flex-direction: row;
}
/* Main axis from right to left */
.container {
flex-direction: row-reverse;
}
/* Main axis from top to bottom */
.container {
flex-direction: column;
}
/* Main axis from bottom to top */
.container {
flex-direction: column-reverse;
}
flex-direction also changes what "justify-content" and "align-items" do, as they always work relative to the main and cross axes.
A common pattern is to use flex-direction: row for a horizontal navigation on desktop, but switch to flex-direction: column for a stacked navigation on mobile:
/* Mobile-first approach */
.nav {
display: flex;
flex-direction: column;
}
/* Switch to row on larger screens */
@media (min-width: 768px) {
.nav {
flex-direction: row;
}
}
The flex-wrap property determines whether flex items are forced into a single line or can be wrapped onto multiple lines. This is crucial for creating responsive layouts that adapt to different screen sizes.
/* Items will all try to fit on one line (default) */
.container {
flex-wrap: nowrap;
}
/* Items will wrap onto multiple lines if needed */
.container {
flex-wrap: wrap;
}
/* Items will wrap onto multiple lines in reverse order */
.container {
flex-wrap: wrap-reverse;
}
Using flex-wrap: wrap is perfect for card layouts that need to adapt to different screen sizes:
.card-container {
display: flex;
flex-wrap: wrap;
}
.card {
flex: 1 0 300px; /* Grow, don't shrink, base width 300px */
margin: 10px;
/* Additional card styling */
}
This creates a layout where cards take up at least 300px of width, grow to fill available space, and wrap to new lines when they don't fit. It's responsive without requiring media queries.
The flex-flow property is a shorthand that combines flex-direction and flex-wrap. It lets you set both properties in a single declaration, making your CSS more concise.
/* Equivalent to flex-direction: row; flex-wrap: nowrap; */
.container {
flex-flow: row nowrap;
}
/* Equivalent to flex-direction: column; flex-wrap: wrap; */
.container {
flex-flow: column wrap;
}
/* Equivalent to flex-direction: row-reverse; flex-wrap: wrap-reverse; */
.container {
flex-flow: row-reverse wrap-reverse;
}
The first value represents flex-direction, and the second value represents flex-wrap. Both values are optional, but you need at least one:
/* Only specifying flex-direction, flex-wrap defaults to nowrap */
.container {
flex-flow: column;
}
/* Only specifying flex-wrap, flex-direction defaults to row */
.container {
flex-flow: wrap;
}
Using flex-flow is recommended when you need to set both properties, as it's more concise and easier to read.
The justify-content property defines how flex items are distributed along the main axis. It controls both the alignment and the distribution of free space.
/* Items are packed toward the start of the main axis (default) */
.container {
justify-content: flex-start;
}
/* Items are centered along the main axis */
.container {
justify-content: center;
}
/* Items are packed toward the end of the main axis */
.container {
justify-content: flex-end;
}
/* Items are evenly distributed with the first at the start and the last at the end */
.container {
justify-content: space-between;
}
/* Items are evenly distributed with equal space around them */
.container {
justify-content: space-around;
}
/* Items are evenly distributed with equal space between them */
.container {
justify-content: space-evenly;
}
A common pattern is to have a logo on the left, primary navigation in the center, and user actions on the right:
.site-header {
display: flex;
align-items: center;
}
.logo {
/* Logo styles */
}
.main-nav {
display: flex;
margin-left: 20px;
}
.user-actions {
display: flex;
margin-left: auto; /* Pushes user actions to the right */
}
Here, instead of using justify-content, we use margin-left: auto; on the user actions to push it to the right edge. This is a common technique when you want some elements aligned to the start and others to the end.
The align-items property defines how flex items are aligned along the cross axis (perpendicular to the main axis). It's especially useful for controlling vertical alignment in a row-based layout or horizontal alignment in a column-based layout.
/* Items stretch to fill the container along the cross axis (default) */
.container {
align-items: stretch;
}
/* Items are placed at the start of the cross axis */
.container {
align-items: flex-start;
}
/* Items are centered along the cross axis */
.container {
align-items: center;
}
/* Items are placed at the end of the cross axis */
.container {
align-items: flex-end;
}
/* Items are aligned such that their baselines align */
.container {
align-items: baseline;
}
The baseline value is particularly useful when you have text of different sizes or with different paddings, as it aligns items based on the baseline of text rather than the edges of the item's box.
One of the most celebrated features of Flexbox is how it simplifies vertical centering, a task that was notoriously difficult before:
/* Perfectly center an element vertically and horizontally */
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* Or any specific height */
}
This pattern is commonly used for centering modal windows, login forms, or hero section content.
The align-content property determines how rows of flex items are distributed along the cross axis when there are multiple rows (due to flex-wrap: wrap). It's similar to justify-content, but for the cross axis and only when there are multiple rows or columns.
/* Lines stretch to fill the remaining space (default) */
.container {
align-content: stretch;
}
/* Lines are packed toward the start of the container */
.container {
align-content: flex-start;
}
/* Lines are centered in the container */
.container {
align-content: center;
}
/* Lines are packed toward the end of the container */
.container {
align-content: flex-end;
}
/* Lines are evenly distributed with the first at the start and the last at the end */
.container {
align-content: space-between;
}
/* Lines are evenly distributed with equal space around them */
.container {
align-content: space-around;
}
It's important to note that align-content has no effect when:
flex-wrap: nowrap)
For a photo gallery with images of fixed width and height, align-content can control how rows of images are distributed vertically:
.gallery {
display: flex;
flex-wrap: wrap;
align-content: space-evenly;
height: 600px; /* Fixed height container */
}
.gallery-item {
width: 150px;
height: 150px;
margin: 5px;
}
This creates a gallery where rows of images are evenly distributed throughout the available vertical space, rather than being packed at the top or stretched.
The gap property (and its components row-gap and column-gap) creates spaces between flex items without affecting the outer margins of the container. This is a relatively newer addition to Flexbox but is now well-supported in modern browsers.
/* Sets both row and column gap to the same value */
.container {
gap: 10px;
}
/* Sets row gap to 10px and column gap to 20px */
.container {
gap: 10px 20px;
}
/* Sets only the row gap */
.container {
row-gap: 10px;
}
/* Sets only the column gap */
.container {
column-gap: 20px;
}
Using gap instead of margins on individual items has several advantages:
The gap property is perfect for creating dashboard layouts with consistently spaced widgets:
.dashboard-grid {
display: flex;
flex-wrap: wrap;
gap: 15px;
}
.dashboard-card {
flex: 1 0 calc(33.33% - 15px * 2/3);
min-width: 250px;
/* Additional styling */
}
This creates a responsive grid of dashboard widgets with equal spacing. The flex-basis calculation accounts for the gap to ensure widgets are properly sized.
The real power of Flexbox comes from combining these properties to create complex layouts that are both flexible and responsive. Let's look at a few examples of how these properties work together.
A common website layout includes a fixed-width sidebar and a flexible main content area:
This area flexes to fill the available space. The layout adjusts responsively on smaller screens.
.app-layout {
display: flex;
}
.sidebar {
flex: 0 0 200px; /* Don't grow, don't shrink, stay at 200px */
}
.main-content {
flex: 1; /* Grow to fill remaining space */
}
/* Responsive adjustment */
@media (max-width: 768px) {
.app-layout {
flex-direction: column;
}
.sidebar {
flex: 0 0 auto; /* Allow height to be determined by content */
}
}
A search bar with a flexible input and a fixed-width button:
.search-container {
display: flex;
}
.search-input {
flex: 1; /* Grow to fill available space */
}
.search-button {
/* Fixed width if desired */
}
A responsive image gallery that changes the number of columns based on available space:
.image-gallery {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.gallery-item {
/* Will create 4 columns on larger screens, fewer on smaller screens */
flex: 1 0 calc(25% - 10px);
min-width: 150px;
}
To make the most of Flexbox containers, here are some best practices to follow:
Remember that justify-content always works along the main axis, and align-items always works along the cross axis. If you change flex-direction, these properties' effects will change accordingly.
Use flex-flow instead of separate flex-direction and flex-wrap properties when setting both. This makes your CSS more concise and easier to maintain.
When possible, use the gap property instead of margins on individual items. This creates more consistent spacing and is easier to maintain.
Always test your Flexbox layouts at different screen sizes to ensure they respond appropriately. Consider using flex-wrap: wrap for layouts that need to adapt to smaller screens.
While Flexbox can create naturally responsive layouts, media queries can enhance the responsiveness by changing flex container properties at different breakpoints (e.g., switching from row to column direction on mobile).
Complex layouts often benefit from nested flex containers, with different flex-direction values. For example, a column-based layout might contain row-based components.
When using properties like flex-direction: row-reverse or order, remember that the visual order might not match the DOM order, which can affect keyboard navigation and screen readers.
If items are overflowing the container, check:
flex-wrap: wrap set if you want items to wrap?flex-shrink: 1 or higher)?If there's empty space in the container, check:
justify-content set to distribute space as desired?flex-grow: 1 or higher)?
If align-content isn't having any effect, remember:
flex-wrap: wrap)If items aren't aligning as expected, check:
align-self?If nested flex containers aren't behaving as expected, remember:
Create a responsive navigation bar with these requirements:
Challenge: Make sure the items stack in a logical order on mobile (logo first, then navigation, then user actions).
Create a responsive dashboard layout with these requirements:
Create a product card with these requirements:
Create a flex container with at least 6 items and experiment with different combinations of these properties:
Try to create at least 5 different layouts using the same HTML but different CSS properties.
In this lecture, we've explored the properties of flex containers in depth:
display: flex and display: inline-flex - Create a flex containerflex-direction - Control the direction of the main axisflex-wrap - Determine whether items wrap to new linesflex-flow - Shorthand for flex-direction and flex-wrapjustify-content - Align items along the main axisalign-items - Align items along the cross axisalign-content - Distribute wrapped lines along the cross axisgap, row-gap, column-gap - Create space between flex itemsThese properties give you precise control over how flex containers behave and how they lay out their children. By combining them in different ways, you can create a wide variety of layouts that are both flexible and responsive.
In the next lecture, we'll dive into flex item properties, exploring how individual items behave within a flex container.