کنترل جهت و شکستن آیتم‌ها: flex-direction، flex-wrap و flex-flow

در درس قبل، به‌طور مقدماتی با flex-direction و تأثیرش روی Main Axis آشنا شدیم. حالا وقتشه این Property رو کامل و با تمام مقادیرش ببینیم، و در کنارش، با flex-wrap هم آشنا بشیم که رفتار Flexbox رو در مواجهه با کمبود فضا کنترل می‌کنه.

مرور و تکمیل: flex-direction

Property به اسم flex-direction چهار مقدار می‌پذیره، نه فقط دوتایی که در درس قبل دیدیم.

row: مقدار پیش‌فرض

.container {
  display: flex;
  flex-direction: row;
}

همون‌طور که در درس قبل دیدیم، آیتم‌ها به‌صورت افقی، در طول Inline Axis سند، چیده می‌شن.

row-reverse: افقی، ولی معکوس

.container {
  display: flex;
  flex-direction: row-reverse;
}
<div class="container">
  <div>آیتم ۱</div>
  <div>آیتم ۲</div>
  <div>آیتم ۳</div>
</div>

در این حالت، آیتم‌ها همچنان در طول محور افقی چیده می‌شن، ولی جهت شروع و پایان Main Axis کاملاً برعکس می‌شه؛ یعنی «آیتم ۱» که در HTML اول اومده، حالا در انتهای Main Axis (نه ابتدای اون) قرار می‌گیره.

column: عمودی

.container {
  display: flex;
  flex-direction: column;
}

همون‌طور که در درس قبل دیدیم، آیتم‌ها زیر هم، از بالا به پایین، چیده می‌شن.

column-reverse: عمودی، ولی معکوس

.container {
  display: flex;
  flex-direction: column-reverse;
}

دقیقاً مثل row-reverse، ولی روی محور عمودی؛ آیتم اول در HTML، در پایین‌ترین نقطه Main Axis (نه بالاترین) قرار می‌گیره.

جدول جمع‌بندی چهار مقدار flex-direction

مقدار جهت Main Axis نقطه شروع آیتم‌ها
row افقی (پیرو جهت سند) ابتدای Inline Axis
row-reverse افقی (پیرو جهت سند، معکوس) انتهای Inline Axis
column عمودی بالا
column-reverse عمودی (معکوس) پایین

مشکل: چه اتفاقی می‌افتد وقتی آیتم‌ها جا نمی‌شوند؟

.container {
  display: flex;
  width: 300px;
}

.item {
  width: 150px;
}
<div class="container">
  <div class="item">آیتم ۱</div>
  <div class="item">آیتم ۲</div>
  <div class="item">آیتم ۳</div>
</div>

در این مثال، مجموع عرض سه آیتم (۴۵۰ پیکسل) بیشتر از عرض Container (۳۰۰ پیکسل)ه. به‌طور پیش‌فرض، Flexbox تلاش می‌کنه همه آیتم‌ها رو در یک خط واحد جا بده؛ که این کار، معمولاً باعث می‌شه آیتم‌ها فشرده بشن (این رفتار رو با جزئیات کامل، در درس‌های آینده با flex-shrink می‌بینیم) یا در موارد شدیدتر، از Container بیرون بزنن.

flex-wrap: اجازه شکستن به خط بعدی

.container {
  display: flex;
  flex-wrap: wrap;
}

Property به اسم flex-wrap مشخص می‌کنه آیا Flex Itemها، در صورت کمبود فضا، مجازند به خط (یا ستون) بعدی بشکنن یا نه.

مقدار رفتار
nowrap (پیش‌فرض) همه آیتم‌ها در یک خط واحد باقی می‌مانند، حتی اگر فشرده یا سرریز شوند
wrap آیتم‌ها، در صورت نیاز، به خط (یا ستون) بعدی می‌شکنند
wrap-reverse مشابه wrap، ولی ترتیب خطوط جدید از انتهای Cross Axis شروع می‌شود

یک مثال عملی از flex-wrap: wrap

.container {
  display: flex;
  flex-wrap: wrap;
  width: 300px;
}

.item {
  width: 150px;
}

با اضافه شدن flex-wrap: wrap، حالا اون سه آیتم که در مثال قبل، مجبور به فشرده شدن در یک خط بودن، به‌طور طبیعی به دو خط تقسیم می‌شن: دو آیتم اول در خط اول (که مجموعشون دقیقاً ۳۰۰ پیکسل، برابر عرض Container، است)، و آیتم سوم، در خط دوم.

نکته مهم: flex-wrap روی Cross Axis اثر می‌گذارد، نه Main Axis

وقتی آیتم‌ها به خط بعدی می‌شکنن، این «خطوط جدید»، همیشه در طول Cross Axis از هم فاصله می‌گیرن؛ نه Main Axis. یعنی اگه flex-direction: row باشه (Main Axis افقی)، خطوط جدید، عمودی (در طول Cross Axis) زیر هم قرار می‌گیرن؛ اگه flex-direction: column باشه (Main Axis عمودی)، «ستون‌های» جدید، افقی (در طول Cross Axis) کنار هم قرار می‌گیرن.

flex-flow: شورت‌هند ترکیبی

.container {
  display: flex;
  flex-flow: row wrap;
}

Property به اسم flex-flow یک شورت‌هند برای تعریف هم‌زمان flex-direction و flex-wrap، در یک خط، است.

flex-flow: <flex-direction> <flex-wrap>;
.example-a {
  flex-flow: row nowrap; /* معادل flex-direction: row + flex-wrap: nowrap */
}

.example-b {
  flex-flow: column wrap; /* معادل flex-direction: column + flex-wrap: wrap */
}

هر دو مقدار داخل flex-flow اختیاریه؛ اگه فقط یکی از این دو رو بنویسیم، دیگری به مقدار پیش‌فرض خودش (row برای Direction و nowrap برای Wrap) برمی‌گرده.

یک مثال کاربردی کامل: گالری تصاویر واکنش‌گرا

.gallery {
  display: flex;
  flex-flow: row wrap;
  gap: 10px;
}

.gallery-item {
  width: 200px;
  height: 150px;
}
<div class="gallery">
  <div class="gallery-item">تصویر ۱</div>
  <div class="gallery-item">تصویر ۲</div>
  <div class="gallery-item">تصویر ۳</div>
  <div class="gallery-item">تصویر ۴</div>
  <div class="gallery-item">تصویر ۵</div>
</div>

در این مثال (که Property به اسم gap رو در درس‌های بعدی همین فصل کامل بررسی می‌کنیم)، تصاویر به‌طور خودکار، بسته به عرض موجود صفحه، به تعداد مناسبی در هر خط چیده می‌شن و در صورت کمبود فضا، به خط بعدی می‌شکنن؛ بدون نیاز به هیچ Media Query یا محاسبه دستی.

نکات مهم

  • flex-direction چهار مقدار دارد: row، row-reverse، column و column-reverse؛ دو مقدار reverse فقط ترتیب شروع و پایان آیتم‌ها را در همان محور برعکس می‌کنند.
  • مقدار پیش‌فرض flex-wrap، یعنی nowrap، باعث می‌شود همه آیتم‌ها در یک خط واحد بمانند، حتی با سرریز احتمالی.
  • flex-flow شورت‌هندی برای تعریف هم‌زمان flex-direction و flex-wrap است.

اشتباهات رایج

  • فراموش کردن flex-wrap: wrap در چیدمان‌هایی با تعداد نامشخص آیتم، که می‌تواند باعث فشرده‌شدن یا سرریز آیتم‌ها شود.
  • تصور اینکه row-reverse یا column-reverse، جهت Cross Axis را هم تغییر می‌دهند؛ در حالی که فقط ترتیب آیتم‌ها در همان Main Axis را برعکس می‌کنند.
  • قاطی کردن ترتیب مقادیر در flex-flow؛ همیشه ابتدا flex-direction و سپس flex-wrap نوشته می‌شود.

جمع‌بندی

flex-direction با چهار مقدار (row، row-reverse، column، column-reverse)، جهت و ترتیب Main Axis را کنترل می‌کند. flex-wrap مشخص می‌کند آیتم‌ها در صورت کمبود فضا، مجاز به شکستن به خط یا ستون بعدی (در طول Cross Axis) هستند یا خیر. flex-flow این دو Property را در یک شورت‌هند واحد ترکیب می‌کند و برای چیدمان‌های واکنش‌گرا، مثل گالری‌های تصویر، ابزاری بسیار کاربردی محسوب می‌شود.