HTML and CSS course · Module 4: Flexbox
Order and Align-self - Individual Element Control
In this lesson5
Welcome back to the Library of Alexandria! On a phone, the content should come before the sidebar, even though the HTML must stay untouched. The librarians knew this problem well: when the pharaoh visited, the most precious papyrus went to the front of the shelf, while the catalogue stayed exactly the same. In Flexbox, exceptions like this are handled by order and align-self.
Order - Changing Visual Order
The order property changes the display order without changing the HTML. It takes an integer, and at the start every element has the same value:
.item {
order: 0; /* Default value for all elements */
}
/* Lower value = earlier */
/* Higher value = later */Elements are sorted in ascending order, ties are settled by the order in the HTML, and negative values such as order: -1 are allowed.
Basic Example
Here are four boxes that the HTML lists one after another:
<div class="container">
<div class="item-1">1</div>
<div class="item-2">2</div>
<div class="item-3">3</div>
<div class="item-4">4</div>
</div>Now, in CSS, box three gets a negative value, box one a positive value, and the rest stay at the default zero:
.container {
display: flex;
}
/* Default: 1, 2, 3, 4 */
.item-3 {
order: -1; /* Will be first: 3, 1, 2, 4 */
}
.item-1 {
order: 1; /* Will be last: 3, 2, 4, 1 */
}
/* Result: 3, 2, 4, 1 */Box three jumps to the front, box one moves to the end, and boxes two and four keep their HTML order, while the HTML itself has not changed at all.
Practical Example - Responsive Layout
The real power of order shows in layouts that change together with the screen:
<div class="layout">
<header class="header">Header</header>
<nav class="sidebar">Sidebar</nav>
<main class="content">Content</main>
<aside class="ads">Ads</aside>
<footer class="footer">Footer</footer>
</div>The CSS uses tools from the upcoming lessons: flex-wrap: wrap moves sections to a new row, flex: 0 0 100% takes the full width, flex: 1 takes the remaining space, and the @media (max-width: 768px) block applies only to screens up to 768 pixels wide:
.layout {
display: flex;
flex-wrap: wrap;
}
/* Desktop - default order */
.header { order: 1; flex: 0 0 100%; }
.sidebar { order: 2; flex: 0 0 25%; }
.content { order: 3; flex: 1; }
.ads { order: 4; flex: 0 0 20%; }
.footer { order: 5; flex: 0 0 100%; }
/* Mobile - change order */
@media (max-width: 768px) {
.header { order: 1; }
.content { order: 2; } /* Content before sidebar! */
.sidebar { order: 3; }
.ads { order: 4; }
.footer { order: 5; }
/* All full width */
.header, .sidebar, .content, .ads, .footer {
flex: 0 0 100%;
}
}On a phone, the content with order: 2 jumps ahead of the sidebar while the HTML stays put, like a pyramid in which the pharaoh changed only the visitors' route. My advice: give order only to the sections that really need to move, and leave the rest at zero.
Practical Example - Product Sorting
In a shop, featured products should stand at the front:
<div class="products">
<div class="product" data-priority="normal">Product A</div>
<div class="product featured" data-priority="high">Product B</div>
<div class="product" data-priority="normal">Product C</div>
<div class="product sale" data-priority="medium">Product D</div>
</div>The CSS reacts to the featured and sale classes here, while data-priority is only a description. gap: 20px adds the spacing, and calc(33.333% - 14px) means one third of the width minus a share of that spacing:
.products {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.product {
flex: 0 0 calc(33.333% - 14px);
order: 3; /* Normal products at the end */
}
.product.featured {
order: 1; /* Featured at the beginning */
border: 3px solid goldenrod;
}
.product.sale {
order: 2; /* Sale in the middle */
background: #e74c3c;
color: white;
}
/* Result: Featured -> Sale -> Normal -> Normal */The featured product B comes first, the discounted D second, and A and C close the row in their HTML order.
Accessibility Notes
There is a catch: order changes only the visual order, not the DOM that the keyboard and screen readers move through. Take three tabs:
<div class="tabs">
<button>Tab 1</button>
<button>Tab 2</button>
<button>Tab 3</button>
</div>In the HTML, the Tab 1 button comes first. Let's move it visually to the very end of the bar:
.tabs button:first-child {
order: 3; /* Visually last */
}
/* Problem: Keyboard navigation (Tab) will keep the original order! */On screen, Tab 1 is last, but the keyboard and a screen reader still reach it first. The Flexbox specification says it plainly: order is for visual, not logical, reordering, so when the order changes the meaning of the content, rearrange the HTML and check the layout using only the keyboard.
Align-self - Individual Alignment
align-self works across the main axis: it overrides the container's align-items for a single element.
Align-self Values
It accepts the values you know from align-items, plus auto:
.item {
align-self: auto; /* Inherits from align-items (default) */
align-self: flex-start; /* At the start of the cross axis */
align-self: flex-end; /* At the end of the cross axis */
align-self: center; /* Centered */
align-self: baseline; /* Aligned to text baseline */
align-self: stretch; /* Stretched (if no height) */
}The default auto takes the parent's align-items, and stretch stretches the element only when it has no fixed height.
Basic Example
The middle one of three elements has an extra special class:
<div class="container">
<div class="item">Item 1</div>
<div class="item special">Item 2 (Special)</div>
<div class="item">Item 3</div>
</div>The container centers everyone with align-items: center, and then we make a single exception for the highlighted element:
.container {
display: flex;
align-items: center; /* All centered */
height: 300px;
border: 2px solid #ddd;
}
.item {
padding: 20px;
background: #3498db;
color: white;
}
/* One element aligned differently */
.item.special {
align-self: flex-start; /* This one will be at the top */
background: goldenrod;
}Item 2 sticks to the top edge while the others stay in the middle, because the container's rule still applies.
Practical Examples
1. Card with button at the bottom
The buttons in cards with different amounts of content should line up at the bottom:
<div class="cards">
<div class="card">
<h3>Product 1</h3>
<p>Short description</p>
<button class="btn">Buy Now</button>
</div>
<div class="card">
<h3>Product 2</h3>
<p>A very long description that takes up much more space...</p>
<button class="btn">Buy Now</button>
</div>
</div>Each card becomes a flex container laid out as a column, and the button gets align-self: stretch and margin-top: auto, a margin that eats up all the free space above it:
.cards {
display: flex;
gap: 20px;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
padding: 20px;
border: 1px solid #ddd;
}
.card h3,
.card p {
flex: 0;
}
.card .btn {
align-self: stretch; /* Button at full width */
margin-top: auto; /* Push to bottom */
}In a column the cross axis runs horizontally, so the button stretches to the width of the card, and the margin pushes it to the bottom.
2. Avatar in chat message
In a chat bubble, the author's photo sits next to the message and the time it was sent:
<div class="message">
<img src="avatar.jpg" alt="User" class="avatar">
<div class="message-content">
<h4>User Name</h4>
<p>This is a message that can be long...</p>
<span class="timestamp">10:30</span>
</div>
</div>The container puts everything at the top, the avatar gets the align-self: center exception, and flex-shrink: 0 protects it from being squashed:
.message {
display: flex;
gap: 15px;
align-items: flex-start; /* Everything at the top */
padding: 15px;
}
.avatar {
width: 50px;
height: 50px;
border-radius: 50%;
flex-shrink: 0;
align-self: center; /* Avatar centered vertically */
}
.message-content {
flex: 1;
}
.timestamp {
align-self: flex-end; /* Timestamp at bottom */
font-size: 0.8em;
color: #777;
}The avatar sits in the middle, but watch out for a trap: align-self works only on children of a flex container, and .timestamp lives inside .message-content, which has no display: flex, so the time will not move. Add display: flex and flex-direction: column there, and flex-end will move the time to the right edge.
3. Icon toolbar
In a toolbar, one icon is bigger than the others:
<div class="toolbar">
<button class="tool">Icon 1</button>
<button class="tool">Icon 2</button>
<button class="tool large">Big Icon</button>
<button class="tool">Icon 3</button>
</div>The toolbar centers the icons, and the big one gets the align-self: flex-start exception plus a golden background:
.toolbar {
display: flex;
gap: 10px;
padding: 10px;
background: #34495e;
align-items: center; /* All centered */
}
.tool {
width: 40px;
height: 40px;
background: #3498db;
border: none;
color: white;
cursor: pointer;
}
.tool.large {
width: 60px;
height: 60px;
align-self: flex-start; /* Aligned to top */
background: goldenrod;
}The big icon is the tallest, so flex-start looks exactly like center here until the toolbar gets height: 80px.
Order + Align-self - Combination
In a hero section, both properties work together:
<div class="hero">
<div class="hero-image">Image</div>
<div class="hero-content">Content</div>
</div>The image with order: 2 goes to the right, the content with order: 1 and align-self: flex-start to the left, and on a phone the order flips:
.hero {
display: flex;
align-items: center;
min-height: 500px;
gap: 40px;
}
.hero-image {
flex: 0 0 50%;
order: 2; /* Image on the right */
}
.hero-content {
flex: 1;
order: 1; /* Content on the left */
align-self: flex-start; /* Content at the top */
}
/* On mobile */
@media (max-width: 768px) {
.hero {
flex-direction: column;
}
.hero-image {
order: 1; /* Image on top */
flex: 0 0 auto;
}
.hero-content {
order: 2; /* Content below */
align-self: stretch; /* Full width */
}
}On a phone, the image jumps to the top, and the content below it stretches to the full width, because in a column stretch works horizontally.
Practical Patterns
1. Featured item first
The featured element always opens the gallery and takes a whole row:
.grid {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.grid-item {
flex: 0 0 calc(33.333% - 14px);
order: 2;
}
.grid-item.featured {
flex: 0 0 100%;
order: 1; /* Always first */
align-self: stretch;
background: goldenrod;
}It has order: 1 and the rest have order: 2, so its position in the HTML does not matter.
2. Sticky footer in card
The footer of a card should stick to the bottom:
.card {
display: flex;
flex-direction: column;
height: 100%;
}
.card-header {
flex: 0 0 auto;
}
.card-body {
flex: 1;
}
.card-footer {
flex: 0 0 auto;
align-self: stretch;
margin-top: auto; /* Always at the bottom */
}The middle part with flex: 1 takes the free space, and margin-top: auto pins the footer to the bottom.
3. Responsive form
The submit button always closes the form:
.form {
display: flex;
flex-wrap: wrap;
gap: 15px;
}
.form-field {
flex: 0 0 calc(50% - 7.5px);
}
.form-field.full {
flex: 0 0 100%;
}
.form-submit {
flex: 0 0 auto;
order: 999; /* Always at the end */
align-self: flex-end;
margin-top: 10px;
}
@media (max-width: 768px) {
.form-field {
flex: 0 0 100%;
}
.form-submit {
flex: 0 0 100%; /* Full width on mobile */
align-self: stretch;
}
}The button with order: 999 lands at the end. On a phone it gets flex: 0 0 100%, because align-self: stretch alone stretches it only vertically in a row.
Summary
order changes only the visual order and leaves the DOM alone, while align-self overrides align-items for one element on the cross axis. In the next lesson you will see what happens when elements no longer fit in one row.
In the editor below, change the order values and arrange the dynasty of pharaohs without touching the HTML.
Code for this lesson: index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flexbox - Order</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>Order - Element Order</h1>
<p class="subtitle">Change display order without changing HTML</p>
<section class="demo-section">
<h2>Default order (order: 0)</h2>
<div class="flex-container">
<div class="flex-item order-0">Element 1</div>
<div class="flex-item order-0">Element 2</div>
<div class="flex-item order-0">Element 3</div>
<div class="flex-item order-0">Element 4</div>
</div>
<p class="description">Elements in HTML order</p>
</section>
<section class="demo-section">
<h2>Changed order</h2>
<div class="flex-container">
<div class="flex-item order-4">Element 1 (order: 4)</div>
<div class="flex-item order-2">Element 2 (order: 2)</div>
<div class="flex-item order-1">Element 3 (order: 1)</div>
<div class="flex-item order-3">Element 4 (order: 3)</div>
</div>
<p class="description">Display: 3 → 2 → 4 → 1</p>
</section>
<section class="demo-section">
<h2>Order with negative values</h2>
<div class="flex-container">
<div class="flex-item order-0">Normal (0)</div>
<div class="flex-item order-minus">First (-1)</div>
<div class="flex-item order-0">Normal (0)</div>
<div class="flex-item order-plus">Last (2)</div>
</div>
<p class="description">Order can be negative - it will appear before elements with order: 0</p>
</section>
<section class="demo-section practice">
<h2>Practice: Pharaoh Dynasty</h2>
<p class="practice-description">Arrange pharaohs by reign chronology</p>
<div class="timeline-container">
<h3>Chronological list of pharaohs:</h3>
<div class="timeline">
<div class="pharaoh narmer">
<div class="crown">▲</div>
<div class="name">Narmer</div>
<div class="years">~3100 BCE</div>
<div class="dynasty">Dynasty I</div>
</div>
<div class="pharaoh khufu">
<div class="crown">▲</div>
<div class="name">Cheops (Khufu)</div>
<div class="years">~2580 BCE</div>
<div class="dynasty">Dynasty IV</div>
</div>
<div class="pharaoh tutankhamun">
<div class="crown">▲</div>
<div class="name">Tutankhamun</div>
<div class="years">~1332 BCE</div>
<div class="dynasty">Dynasty XVIII</div>
</div>
<div class="pharaoh ramesses">
<div class="crown">▲</div>
<div class="name">Ramesses II</div>
<div class="years">~1279 BCE</div>
<div class="dynasty">Dynasty XIX</div>
</div>
<div class="pharaoh cleopatra">
<div class="crown">▲</div>
<div class="name">Cleopatra VII</div>
<div class="years">~51 BCE</div>
<div class="dynasty">Ptolemaic</div>
</div>
</div>
</div>
<div class="controls">
<button onclick="resetOrder()">HTML Order</button>
<button onclick="chronologicalOrder()">Chronological</button>
<button onclick="reverseOrder()">Reversed</button>
<button onclick="randomOrder()">Random</button>
</div>
<div class="info-box">
<h4>How order works:</h4>
<ul>
<li>By default all elements have <code>order: 0</code></li>
<li>Elements are sorted in ascending order by order value</li>
<li>With the same order value, the HTML order matters</li>
<li>Negative values can be used</li>
</ul>
</div>
</section>
</div>
<script>
function resetOrder() {
const pharaohs = document.querySelectorAll('.pharaoh');
pharaohs.forEach((pharaoh, index) => {
pharaoh.style.order = '0';
});
}
function chronologicalOrder() {
document.querySelector('.narmer').style.order = '1';
document.querySelector('.khufu').style.order = '2';
document.querySelector('.tutankhamun').style.order = '3';
document.querySelector('.ramesses').style.order = '4';
document.querySelector('.cleopatra').style.order = '5';
}
function reverseOrder() {
document.querySelector('.narmer').style.order = '5';
document.querySelector('.khufu').style.order = '4';
document.querySelector('.tutankhamun').style.order = '3';
document.querySelector('.ramesses').style.order = '2';
document.querySelector('.cleopatra').style.order = '1';
}
function randomOrder() {
const pharaohs = document.querySelectorAll('.pharaoh');
pharaohs.forEach(pharaoh => {
pharaoh.style.order = Math.floor(Math.random() * 10);
});
}
</script>
</body>
</html>Remember: order and align-self are the pharaoh's special commands for individual blocks of the pyramid, exceptions to the general rules that never rearrange the catalogue, which is the HTML.
Docs entries used in this lesson
Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. What is the default value of the order property for all flex items?
2. What is the align-self property used for?
Hands-on tasks in the game
- Horizontal ordering
Arrange the CSS declaration that changes an item's order to the second position:
- Click in order
Arrange the declaration that centers a single item on the cross axis: