Flexbox Hand-on: یک زمین بازی بصری برای یادگیری چیدمان CSS

آیا از کشتی با چیدمان CSS خسته شده اید؟ Flexbox راه حل های قدرتمندی ارائه می دهد ، اما تفاوت زیادی بین خواندن مستندات و دیدن آن در عمل وجود دارد. به همین دلیل من یک اکسپلورر Flexbox Interactive ایجاد کردم که به شما کمک می کند تا از طریق آزمایش دستی ، این تکنیک اساسی را تسلط دهید. 🧪
چرا یک ابزار Flexbox دیگر؟
یادگیری مفاهیم توسعه وب وقتی می توانید بلافاصله نتایج تغییرات کد خود را مشاهده کنید ، به بهترین وجه کلیک می کند. تئوری و تمرین من Flexbox Explorer با اجازه دادن به شما:
- خصوصیات کانتینر را ترفند کنید و تغییرات فوری را ببینید
- سبک های فلکس فردی با رنگ ها و محتوای سفارشی
- به کد HTML/CSS دقیق دسترسی پیدا کنید تا آنچه می بینید
- از نظر جسمی موارد را با کشیدن و رها کردن دوباره تنظیم کنید
- برای پروژه های خود کد آماده استفاده را کپی کنید
خودتان آن را امتحان کنید: https://playground.learncomputer.in/css-flexbox-playground/
رابط اکسپلورر
این ابزار دارای یک رابط سه قسمتی است که برای یادگیری بهینه طراحی شده است:
- ایستگاه کنترل – تمام خصوصیات Flexbox شما در منوهای کشویی ساده
- پیش نمایش زنده – یک ماسهبازی بصری که طرح شما را در زمان واقعی نشان می دهد
- نمایش کد – HTML و CSS واقعی که طراحی شما را ایجاد می کند
این تنظیم یک حلقه بازخورد عالی ایجاد می کند: یک ویژگی را تنظیم کنید ، ببینید چه چیزی به صورت بصری تغییر می کند و کد اساسی را همزمان می فهمید.
ایجاد اکسپلورر: چگونه کار می کند
بیایید ببینیم که چگونه این ابزار ساخته شده است:
ساختار HTML
برنامه از یک ساختار HTML تمیز و معنایی استفاده می کند که رابط را به بخش های منطقی جدا می کند:
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">
class="container">
class="sidebar">
class="controls">
Container Properties
class="control-group">
class="control-group">
class="control-group">
class="control-group">
class="control-group">
Item Properties
class="control-group">
class="control-group">
type="color" id="itemBackground" value="#007bff">
class="control-group">
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">
"script.js">
یک ظاهر طراحی شده
CSS نه تنها رابط ما را سبک می کند بلکه رفتارهای Flexbox را که ما با آنها آزمایش می کنیم ، پیاده سازی می کند:
* {
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;
}
قابلیت تعاملی
JavaScript همه چیز را به زندگی می رساند ، به تغییرات خاصیت ، عملکرد کشیدن و رها کردن و تولید کد می پردازد:
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();
});
خصوصیات کانتینر Flexbox توضیح داده شده است
پانل سمت چپ کنترل هایی را برای کلیه خصوصیات اصلی کانتینر Flexbox فراهم می کند:
نوع نمایش
بین:
-
flex
– یک ظرف فلکس سطح بلوک ایجاد می کند -
inline-flex
– یک ظرف فلکس سطح درون خطی ایجاد می کند
جهت اصلی محور
جریان طرح خود را با:
-
row
– مواردی که به صورت افقی تنظیم شده اند (پیش فرض) -
row-reverse
– مواردی که به صورت افقی به ترتیب معکوس مرتب شده اند -
column
– مواردی که به صورت عمودی انباشته شده اند -
column-reverse
– مواردی که به صورت عمودی به ترتیب معکوس جمع شده اند
این انتخاب اساساً بر نحوه عملکرد سایر خصوصیات تأثیر می گذارد! 🧭
تراز اصلی محور (توجیه کننده-محتوای)
موارد موقعیت در امتداد محور اصلی:
-
flex-start
– موارد بسته بندی شده برای شروع -
flex-end
– موارد بسته بندی شده تا پایان -
center
– مواردی که در امتداد محور اصلی قرار دارند -
space-between
– مواردی که به طور مساوی با اولین بار در ابتدا توزیع می شوند ، آخرین بار در پایان -
space-around
– مواردی با فضای مساوی در اطراف آنها -
space-evenly
– مواردی با فضای مساوی بین آنها
تراز Axis Cross (Align-Atems)
موقعیت کنترل عمود بر محور اصلی:
-
stretch
– موارد برای پر کردن کانتینر (پیش فرض) گسترش می یابد -
flex-start
– مواردی که در محور متقابل شروع می شوند -
flex-end
– مواردی که در انتهای محور متقاطع تراز شده اند -
center
– موارد محور در محور متقاطع -
baseline
– مواردی که توسط خطوط متن تراز شده اند
رفتار سرریز (Flex-Wrap)
کنترل آنچه اتفاق می افتد وقتی موارد سرریز می شود:
-
nowrap
– همه مواردی که مجبور به تک خط هستند (پیش فرض) -
wrap
– موارد مورد نیاز به خطوط اضافی بسته می شوند -
wrap-reverse
– موارد را در جهت معکوس به خطوط اضافی بسته بندی می کنند
سفارشی سازی سطح مورد
فراتر از خواص کانتینر ، شما نیز می توانید:
- برای سفارشی سازی موارد خاص Flex را انتخاب کنید
- تغییر رنگ های پس زمینه با یک انتخاب کننده بصری
- محتوای متن هر مورد را اصلاح کنید
این ابزار حتی به طور خودکار رنگ متن را بر اساس روشنایی پس زمینه برای خوانایی بهینه تنظیم می کند! 🎨
فراتر از کنترل های اساسی
آنچه این Explorer را از هم جدا می کند ، ویژگی های تعاملی آن است:
کشیدن و رها کردن بصری
برای جابجایی آنها در داخل ظرف ، کلیک کنید و موارد را بکشید. این به شما کمک می کند:
- نحوه عملکرد Flexbox را تجربه کنید
- تنظیمات مختلف را بدون نوشتن کد آزمایش کنید
- روابط مکانی بین موارد را درک کنید
مدیریت آیتم پویا
- موارد جدید را با دکمه “اضافه کردن مورد” اضافه کنید
- موارد ناخواسته را با شناور و کلیک روی نماد “✕” حذف کنید
این ویژگی ها به شما امکان می دهد ببینید که چگونه Flexbox با تعداد مختلف موارد سازگار است.
حالت نور/تاریک
بین تم های رنگی با یک کلیک تغییر دهید – مناسب برای هر محیط کار یا زمان روز. 🌓
صادرات کد
پس از ایجاد طرح کامل:
- HTML را با یک کلیک کپی کنید
- CSS را با یک کلیک کپی کنید
آزمایشات خود را فوراً در پروژه های واقعی اجرا کنید!
طرح بندی برای امتحان کردن
در اینجا برخی از الگوهای مشترک برای آزمایش با:
مرکز عالی
مشکل بدنام مرکز ، فقط با دو خاصیت حل شده است:
justify-content: center
align-items: center
آن را امتحان کنید و تماشای مطالب خود را به مرکز ظرف تماشا کنید! 🎯
نوار ناوبری پاسخگو
یک منوی ناوبری انعطاف پذیر ایجاد کنید:
display: flex
-
justify-content: space-between
(یاspace-around
)
ببینید که چگونه موارد به طور مساوی توزیع می شوند و با تغییر اندازه پنجره ، فاصله را حفظ می کنند.
شبکه کارت با بسته بندی
یک شبکه پاسخگو ایجاد کنید:
- تنظیم کردن
flex-wrap: wrap
- چندین مورد را اضافه کنید
- متفاوت را امتحان کنید
justify-content
ارزش ها
تماشا کنید که چگونه موارد در صورت لزوم به ردیف های جدید ، فاصله های مداوم را حفظ می کنند.
برنامه های دنیای واقعی
از طریق اکتشاف ، Flexbox Excels را در:
- چیدمان هدر با آرم و ناوبری
- گالری های عکس با فاصله سازگار
- رسانه های اجتماعی با تصاویر و محتوای پروفایل تغذیه می کنند
- عناصر با برچسب ها و ورودی های تراز
- جداول مقایسه و پانل های قیمت گذاری
یادگیری از طریق انجام
این اکسپلورر Flexbox مفاهیم انتزاعی CSS را به تجربیات ملموس و قابل مشاهده تبدیل می کند. به جای به یاد آوردن خواص ، از طریق دستکاری مستقیم و بازخورد فوری یک شهود ایجاد خواهید کرد.
من شما را تشویق می کنم:
- مقادیر شدید را آزمایش کنید تا ببینید چگونه طرح ها پاسخ می دهند
- مؤلفه هایی را که اغلب در پروژه ها به آن نیاز دارید ایجاد کنید
- با تعداد مختلف موارد آزمایش کنید
- سعی کنید چیدمان ها را از وب سایت های مورد علاقه خود بازآفرینی کنید
با هر آزمایش ، Flexbox کمتر مرموز و بصری تر می شود – تبدیل آنچه که یک بار به نظر می رسید جادوگری CSS به یک ابزار دیگر در کیت شما تبدیل می شود. ✨
با چه چیدمان Flexbox دست و پنجه نرم کرده اید؟ سعی کنید آنها را در Explorer بسازید و نتایج خود را در نظرات به اشتراک بگذارید!