Are you tired of wrestling with CSS layouts? Flexbox offers powerful solutions, but there's a big difference between reading documentation and seeing it in action. That's why I created an interactive Flexbox Explorer that helps you master this essential layout technique through hands-on experimentation. 🧪
Why Another Flexbox Tool?
Learning web development concepts clicks best when you can immediately see the results of your code changes. My Flexbox Explorer bridges theory and practice by letting you:
- Tweak container properties and see instant layout changes
- Style individual flex items with custom colors and content
- Access the exact HTML/CSS code powering what you see
- Physically rearrange items with drag-and-drop
- Copy ready-to-use code for your projects
Try it yourself: https://playground.learncomputer.in/css-flexbox-playground/
The Explorer Interface
The tool features a three-part interface designed for optimal learning:
- Control Station - All your Flexbox properties in simple dropdown menus
- Live Preview - A visual sandbox showing your layout in real-time
- Code Display - The actual HTML and CSS that creates your design
This setup creates a perfect feedback loop: adjust a property, see what changes visually, and understand the underlying code simultaneously.
Creating the Explorer: How it Works
Let's look at how this tool is constructed:
HTML Structure
The application uses a clean, semantic HTML structure that separates the interface into logical sections:
</span>
lang="en">
charset="UTF-8">
name="viewport" content="width=device-width, initial-scale=1.0">
CSS Flexbox Playground
rel="stylesheet" href="styles.css">
class="header">
CSS Flexbox Playground
class="header-buttons">
id="darkModeBtn">Dark Mode
id="copyHtmlBtn">Copy HTML
id="copyCssBtn">Copy CSS
id="addItemBtn">Add Item
class="container">
class="sidebar">
class="controls">
Container Properties
class="control-group">
for="display">Display
id="display">
value="flex">flex
value="inline-flex">inline-flex
class="control-group">
for="flexDirection">Flex Direction
id="flexDirection">
value="row">row
value="row-reverse">row-reverse
value="column">column
value="column-reverse">column-reverse
class="control-group">
for="justifyContent">Justify Content
id="justifyContent">
value="flex-start">flex-start
value="flex-end">flex-end
value="center">center
value="space-between">space-between
value="space-around">space-around
value="space-evenly">space-evenly
class="control-group">
for="alignItems">Align Items
id="alignItems">
value="stretch">stretch
value="flex-start">flex-start
value="flex-end">flex-end
value="center">center
value="baseline">baseline
class="control-group">
for="flexWrap">Flex Wrap
id="flexWrap">
value="nowrap">nowrap
value="wrap">wrap
value="wrap-reverse">wrap-reverse
Item Properties
class="control-group">
for="itemSelector">Select Item
id="itemSelector">
class="control-group">
for="itemBackground">Background Color
type="color" id="itemBackground" value="#007bff">
class="control-group">
for="itemText">Text Content
type="text" id="itemText" value="Item">
class="playground">
class="flex-container" id="flexContainer">
class="flex-item" draggable="true">
1
class="remove-icon">✕
class="flex-item" draggable="true">
2
class="remove-icon">✕
class="flex-item" draggable="true">
3
class="remove-icon">✕
class="code-panel">
class="code-section">
HTML
id="htmlCode">
class="code-section">
CSS
id="cssCode">
<span class="na">src="script.js">
Enter fullscreen mode
Exit fullscreen mode
Core Styling
The CSS not only styles our interface but also implements the Flexbox behaviors we're experimenting with:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', sans-serif;
}
body {
background: #f0f2f5;
color: #333;
line-height: 1.6;
height: 100vh;
display: flex;
flex-direction: column;
transition: all 0.3s ease;
}
body.dark-mode {
background: #1a1a1a;
color: #fff;
}
.container {
display: flex;
flex: 1;
overflow: hidden;
}
.header {
padding: 15px 20px;
background: #007bff;
color: white;
display: flex;
justify-content: space-between;
align-items: center;
}
.header-buttons button {
padding: 8px 15px;
margin-left: 10px;
border: none;
border-radius: 5px;
background: #fff;
color: #007bff;
cursor: pointer;
transition: all 0.3s;
}
.header-buttons button:hover {
background: #e9ecef;
}
.sidebar {
width: 300px;
background: #fff;
padding: 20px;
box-shadow: 2px 0 5px rgba(0,0,0,0.1);
overflow-y: auto;
}
body.dark-mode .sidebar {
background: #2d2d2d;
}
.playground {
flex: 1;
padding: 20px;
background: #fff;
margin: 20px;
border-radius: 10px;
box-shadow: 0 0 15px rgba(0,0,0,0.1);
}
body.dark-mode .playground {
background: #2d2d2d;
}
.controls h3 {
margin-bottom: 15px;
color: #007bff;
}
.control-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: 500;
color: #555;
}
body.dark-mode label {
color: #ddd;
}
select, input[type="text"], input[type="color"] {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 5px;
background: #f9f9f9;
cursor: pointer;
}
input[type="color"] {
height: 40px;
padding: 0;
}
body.dark-mode select,
body.dark-mode input[type="text"],
body.dark-mode input[type="color"] {
background: #3a3a3a;
color: #fff;
border-color: #555;
}
.flex-container {
min-height: 200px;
border: 2px dashed #666;
border-radius: 5px;
padding: 10px;
background: #f8f9fa;
transition: all 0.3s ease;
}
body.dark-mode .flex-container {
background: #333;
border-color: #888;
}
.flex-item {
padding: 20px;
margin: 5px;
border-radius: 5px;
text-align: center;
cursor: move;
transition: all 0.2s ease;
user-select: none;
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.flex-item:hover {
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}
.flex-item .remove-icon {
display: none;
position: absolute;
top: 5px;
right: 5px;
width: 16px;
height: 16px;
background: rgba(255, 255, 255, 0.8);
color: #333;
border-radius: 50%;
text-align: center;
line-height: 16px;
font-size: 12px;
cursor: pointer;
transition: all 0.2s ease;
}
.flex-item:hover .remove-icon {
display: block;
}
.flex-item .remove-icon:hover {
background: #ff4444;
color: white;
}
.flex-item.dragging .remove-icon {
display: none;
}
.flex-item.dragging {
opacity: 0.5;
}
.code-panel {
width: 300px;
background: #1a1a1a;
color: #fff;
padding: 20px;
overflow-y: auto;
font-family: 'Courier New', monospace;
font-size: 14px;
display: flex;
flex-direction: column;
gap: 20px;
}
.code-section h3 {
margin-bottom: 10px;
color: #007bff;
}
Enter fullscreen mode
Exit fullscreen mode
Interactive Functionality
JavaScript brings everything to life, handling property changes, drag-and-drop functionality, and code generation:
document.addEventListener('DOMContentLoaded', () => {
const flexContainer = document.getElementById('flexContainer');
const htmlCode = document.getElementById('htmlCode');
const cssCode = document.getElementById('cssCode');
const controls = document.querySelectorAll('.controls select');
const darkModeBtn = document.getElementById('darkModeBtn');
const copyHtmlBtn = document.getElementById('copyHtmlBtn');
const copyCssBtn = document.getElementById('copyCssBtn');
const addItemBtn = document.getElementById('addItemBtn');
const itemSelector = document.getElementById('itemSelector');
const itemBackground = document.getElementById('itemBackground');
const itemText = document.getElementById('itemText');
let itemCount = 3;
// Populate item selector
function updateItemSelector() {
itemSelector.innerHTML = '';
const items = flexContainer.querySelectorAll('.flex-item');
items.forEach((item, index) => {
const option = document.createElement('option');
option.value = index;
option.textContent = `Item ${index + 1}`;
itemSelector.appendChild(option);
});
// Ensure controls reflect the currently selected item
updateItemControls();
}
// Update item controls based on selected item
function updateItemControls() {
const selectedIndex = parseInt(itemSelector.value, 10); // Ensure it's an integer
const selectedItem = flexContainer.children[selectedIndex];
if (selectedItem) {
itemBackground.value = rgbToHex(selectedItem.style.backgroundColor) || '#007bff';
itemText.value = selectedItem.firstChild.textContent || 'Item';
updateTextColor(selectedItem);
}
}
// Convert RGB to Hex
function rgbToHex(rgb) {
if (!rgb || rgb === '') return '#007bff';
const match = rgb.match(/\d+/g);
if (!match) return '#007bff';
const [r, g, b] = match.map(Number);
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase()}`;
}
// Calculate luminance and set text color
function updateTextColor(item) {
const bgColor = item.style.backgroundColor || '#007bff';
const match = bgColor.match(/\d+/g);
if (!match) return; // If no valid color, skip
const [r, g, b] = match.map(Number);
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
item.style.color = luminance > 0.5 ? '#000000' : '#FFFFFF';
}
// Update Flexbox properties and both code displays
function updateFlexbox() {
const styles = {
display: document.getElementById('display').value,
flexDirection: document.getElementById('flexDirection').value,
justifyContent: document.getElementById('justifyContent').value,
alignItems: document.getElementById('alignItems').value,
flexWrap: document.getElementById('flexWrap').value
};
Object.assign(flexContainer.style, styles);
updateHTMLCode();
updateCSSCode(styles);
}
// Update HTML code display
function updateHTMLCode() {
const itemsHTML = Array.from(flexContainer.children)
.map(item => ` ${item.style.backgroundColor || '#007bff'}; color: ${item.style.color}">${item.firstChild.textContent}`)
.join('\n');
htmlCode.textContent = `\n${itemsHTML}\n`;
}
// Update CSS code display
function updateCSSCode(styles) {
cssCode.textContent = `.flex-container {
display: ${styles.display};
flex-direction: ${styles.flexDirection};
justify-content: ${styles.justifyContent};
align-items: ${styles.alignItems};
flex-wrap: ${styles.flexWrap};
}
.flex-item {
padding: 20px;
margin: 5px;
border-radius: 5px;
text-align: center;
}`;
}
// Update selected item's properties
function updateItemProperties() {
const selectedIndex = parseInt(itemSelector.value, 10); // Ensure integer
const selectedItem = flexContainer.children[selectedIndex];
if (selectedItem) {
selectedItem.style.backgroundColor = itemBackground.value;
selectedItem.firstChild.textContent = itemText.value;
updateTextColor(selectedItem);
updateHTMLCode();
}
}
// Drag and Drop functionality
flexContainer.addEventListener('dragstart', (e) => {
if (e.target.classList.contains('flex-item')) {
e.target.classList.add('dragging');
}
});
flexContainer.addEventListener('dragend', (e) => {
if (e.target.classList.contains('flex-item')) {
e.target.classList.remove('dragging');
}
});
flexContainer.addEventListener('dragover', (e) => {
e.preventDefault();
});
flexContainer.addEventListener('drop', (e) => {
e.preventDefault();
const dragging = document.querySelector('.dragging');
const afterElement = getDragAfterElement(flexContainer, e.clientX, e.clientY);
if (afterElement == null) {
flexContainer.appendChild(dragging);
} else {
flexContainer.insertBefore(dragging, afterElement);
}
updateHTMLCode();
updateItemSelector();
});
function getDragAfterElement(container, x, y) {
const draggableElements = [...container.querySelectorAll('.flex-item:not(.dragging)')];
return draggableElements.reduce((closest, child) => {
const box = child.getBoundingClientRect();
const offsetX = x - (box.left + box.width / 2);
const offsetY = y - (box.top + box.height / 2);
if (offsetX < 0 && offsetX > closest.offset) {
return { offset: offsetX, element: child };
}
return closest;
}, { offset: Number.NEGATIVE_INFINITY }).element;
}
// Remove Item functionality
flexContainer.addEventListener('click', (e) => {
if (e.target.classList.contains('remove-icon')) {
const item = e.target.parentElement;
if (flexContainer.children.length > 1) {
item.remove();
updateItemNumbers();
updateHTMLCode();
updateItemSelector();
} else {
alert('Cannot remove the last item!');
}
}
});
// Update item numbers after removal
function updateItemNumbers() {
const items = flexContainer.querySelectorAll('.flex-item');
items.forEach((item, index) => {
item.firstChild.textContent = item.firstChild.textContent.match(/\d+/) ? index + 1 : item.firstChild.textContent;
});
itemCount = items.length;
}
// Dark Mode Toggle
darkModeBtn.addEventListener('click', () => {
document.body.classList.toggle('dark-mode');
darkModeBtn.textContent = document.body.classList.contains('dark-mode')
? 'Light Mode'
: 'Dark Mode';
});
// Copy HTML
copyHtmlBtn.addEventListener('click', () => {
const code = htmlCode.textContent;
navigator.clipboard.writeText(code).then(() => {
alert('HTML code copied to clipboard!');
});
});
// Copy CSS
copyCssBtn.addEventListener('click', () => {
const code = cssCode.textContent;
navigator.clipboard.writeText(code).then(() => {
alert('CSS code copied to clipboard!');
});
});
// Add New Item
addItemBtn.addEventListener('click', () => {
itemCount++;
const newItem = document.createElement('div');
newItem.className = 'flex-item';
newItem.draggable = true;
newItem.style.backgroundColor = itemBackground.value;
newItem.innerHTML = `${itemText.value}✕`;
flexContainer.appendChild(newItem);
updateTextColor(newItem);
updateHTMLCode();
updateItemSelector();
});
// Event Listeners for controls
controls.forEach(control => {
control.addEventListener('change', updateFlexbox);
});
itemSelector.addEventListener('change', updateItemControls);
itemBackground.addEventListener('input', updateItemProperties);
itemText.addEventListener('input', updateItemProperties);
// Initial setup
updateFlexbox();
flexContainer.querySelectorAll('.flex-item').forEach(item => {
item.style.backgroundColor = '#007bff'; // Set initial background
updateTextColor(item);
});
updateItemSelector();
});
Enter fullscreen mode
Exit fullscreen mode
Flexbox Container Properties Explained
The left panel provides controls for all major Flexbox container properties:
Display Type
Choose between:
flex - Creates a block-level flex container
inline-flex - Creates an inline-level flex container
Main Axis Direction
Set your layout flow with:
row - Items arranged horizontally (default)
row-reverse - Items arranged horizontally in reverse order
column - Items stacked vertically
column-reverse - Items stacked vertically in reverse order
This choice fundamentally affects how other properties work! 🧭
Main Axis Alignment (justify-content)
Position items along the main axis:
flex-start - Items packed toward start
flex-end - Items packed toward end
center - Items centered along main axis
space-between - Items evenly distributed with first at start, last at end
space-around - Items with equal space around them
space-evenly - Items with equal space between them
Cross Axis Alignment (align-items)
Control positioning perpendicular to the main axis:
stretch - Items expand to fill container (default)
flex-start - Items aligned at cross-axis start
flex-end - Items aligned at cross-axis end
center - Items centered on cross axis
baseline - Items aligned by text baselines
Overflow Behavior (flex-wrap)
Control what happens when items would overflow:
nowrap - All items forced to single line (default)
wrap - Items wrap to additional lines as needed
wrap-reverse - Items wrap to additional lines in reverse direction
Item-Level Customization
Beyond container properties, you can also:
Select specific flex items to customize
Change background colors with a visual picker
Modify the text content of any item
The tool even automatically adjusts text color based on background brightness for optimal readability! 🎨
Beyond Basic Controls
What sets this explorer apart are its interactive features:
Intuitive Drag and Drop
Click and drag items to reposition them within the container. This helps you:
Experience how Flexbox ordering works
Test different arrangements without writing code
Understand spatial relationships between items
Dynamic Item Management
Add new items with the "Add Item" button
Remove unwanted items by hovering and clicking the "✕" icon
These features let you see how Flexbox adapts to different numbers of items.
Light/Dark Mode
Switch between color themes with a single click - perfect for any working environment or time of day. 🌓
Code Export
Once you've created the perfect layout:
Copy HTML with one click
Copy CSS with one click
Instantly implement your experiments in real projects!
Layouts to Try
Here are some common patterns to experiment with:
Perfect Centering
The infamous centering problem, solved with just two properties:
justify-content: center
align-items: center
Try it and watch your content snap to the center of the container! 🎯
Responsive Navigation Bar
Create a flexible navigation menu:
display: flex
justify-content: space-between (or space-around)
See how items distribute evenly, maintaining spacing as the window resizes.
Card Grid with Wrapping
Build a responsive grid of cards:
Set flex-wrap: wrap
Add several items
Try different justify-content values
Watch how items maintain consistent spacing while wrapping to new rows as needed.
Real-World Applications
Through exploration, you'll discover Flexbox excels at:
Header layouts with logos and navigation
Photo galleries with consistent spacing
Social media feeds with profile images and content
Form elements with aligned labels and inputs
Feature comparison tables and pricing panels
Learning Through Doing
This Flexbox Explorer transforms abstract CSS concepts into tangible, visible experiences. Instead of memorizing properties, you'll develop an intuition through direct manipulation and instant feedback.I encourage you to:
Test extreme values to see how layouts respond
Create components you frequently need in projects
Experiment with different numbers of items
Try recreating layouts from your favorite websites
With each experiment, Flexbox becomes less mysterious and more intuitive — turning what once seemed like CSS sorcery into just another tool in your kit. ✨What Flexbox layouts have you struggled with? Try building them in the explorer and share your results in the comments!