رشد، کوچک شدن و اندازه پایه: flex-grow، flex-shrink، flex-basis و شورت‌هند flex

در درس‌های قبل، رفتار Flex Container رو کامل دیدیم: جهت، شکستن خطوط، ترازبندی و فاصله‌گذاری. حالا وقتشه از زاویه دیگه‌ای نگاه کنیم: چطور می‌شه رفتار خود Flex Itemها رو، در برابر فضای موجود، کنترل کرد؛ یعنی این‌که هر آیتم، چقدر باید رشد کنه، چقدر باید کوچک بشه، و اندازه پایه‌اش دقیقاً چیه.

flex-basis: اندازه پایه یک آیتم

.item {
  flex-basis: 200px;
}

Property به اسم flex-basis اندازه اولیه یک Flex Item رو، پیش از اینکه هرگونه رشد یا کوچک‌شدنی اتفاق بیفته، مشخص می‌کنه. این مقدار، در طول Main Axis محاسبه می‌شه؛ یعنی اگه flex-direction: row باشه، flex-basis عملاً نقش عرض رو بازی می‌کنه؛ اگه flex-direction: column باشه، نقش ارتفاع رو.

تفاوت flex-basis با width

.item-a {
  width: 200px;
}

.item-b {
  flex-basis: 200px;
}

در نگاه اول، ممکنه flex-basis شبیه width به‌نظر برسه؛ ولی تفاوت مهمی دارن: flex-basis، به‌عنوان یک «پیشنهاد اندازه اولیه» عمل می‌کنه که، همون‌طور که در ادامه می‌بینیم، توسط flex-grow و flex-shrink می‌تونه تغییر کنه؛ در حالی که width در Flexbox، معمولاً (مگر با تنظیمات خاص) اولویت کمتری نسبت به flex-basis داره، وقتی هر دو هم‌زمان تعریف بشن.

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

.item {
  flex-basis: auto;
}

مقدار پیش‌فرض flex-basis، auto است؛ یعنی اندازه اولیه آیتم، بر اساس محتوای داخلیش (یا مقدار width/height‌ای که مستقیماً روش تعریف شده) محاسبه می‌شه.

flex-grow: میزان رشد در فضای اضافه

.container {
  display: flex;
}

.item {
  flex-grow: 1;
}

Property به اسم flex-grow مشخص می‌کنه، اگه فضای اضافه‌ای در Container باقی بمونه (یعنی مجموع اندازه پایه آیتم‌ها، کمتر از فضای کل Container باشه)، این فضای اضافه، چطور بین آیتم‌ها تقسیم بشه.

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

.item {
  flex-grow: 0; /* پیش‌فرض: هیچ رشدی نکن */
}

به‌طور پیش‌فرض، flex-grow برابر 0 است؛ یعنی آیتم‌ها، حتی اگه فضای خالی زیادی در Container باقی بمونه، هیچ رشدی نمی‌کنن و در همون اندازه flex-basis‌شون باقی می‌مونن.

یک مثال ساده: رشد برابر

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

.item {
  flex-grow: 1;
}
<div class="container">
  <div class="item">آیتم ۱</div>
  <div class="item">آیتم ۲</div>
  <div class="item">آیتم ۳</div>
</div>

وقتی هر سه آیتم flex-grow: 1 داشته باشن، هر فضای اضافه‌ای که در Container باقی بمونه، به‌طور کاملاً مساوی بین این سه آیتم تقسیم می‌شه؛ نتیجه نهایی این می‌شه که هر سه آیتم، عرض یکسان (دقیقاً یک‌سوم از عرض کل Container) پیدا می‌کنن.

نسبت‌های نامساوی با flex-grow

.item-a {
  flex-grow: 1;
}

.item-b {
  flex-grow: 2;
}

دقیقاً مشابه چیزی که در فصل ۶ با واحد fr در Grid دیدیم، مقادیر flex-grow به‌صورت نسبی محاسبه می‌شن. در این مثال، فضای اضافه به سه سهم تقسیم می‌شه (۱ + ۲)؛ .item-a یک سهم می‌گیره، و .item-b، دو برابر اون (یعنی دو سهم).

flex-shrink: میزان کوچک‌شدن در کمبود فضا

.item {
  flex-shrink: 1;
}

Property به اسم flex-shrink، دقیقاً برعکس flex-grow عمل می‌کنه: مشخص می‌کنه، اگه مجموع اندازه پایه آیتم‌ها، بیشتر از فضای موجود در Container باشه (یعنی کمبود فضا داشته باشیم)، هر آیتم چقدر باید از اندازه flex-basis‌ش کوچک‌تر بشه.

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

.item {
  flex-shrink: 1; /* پیش‌فرض: در صورت نیاز، کوچک شو */
}

برخلاف flex-grow، مقدار پیش‌فرض flex-shrink برابر 1 است؛ یعنی، به‌طور پیش‌فرض، آیتم‌ها اجازه دارن، در صورت کمبود فضا، کوچک بشن (به‌جای اینکه مجبور بشن از Container بیرون بزنن).

جلوگیری از کوچک شدن با flex-shrink: 0

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

.fixed-item {
  flex-basis: 150px;
  flex-shrink: 0;
}

.flexible-item {
  flex-basis: 300px;
}

در این مثال، حتی اگه مجموع اندازه پایه آیتم‌ها (۱۵۰ + ۳۰۰ = ۴۵۰ پیکسل) بیشتر از عرض Container (۴۰۰ پیکسل) باشه، .fixed-item، چون flex-shrink: 0 داره، هرگز کوچک‌تر از ۱۵۰ پیکسل نمی‌شه؛ در عوض، تمام فشار کمبود فضا، روی .flexible-item (که flex-shrink‌ش مقدار پیش‌فرض ۱ رو داره) وارد می‌شه، و اون آیتم، کوچک‌تر می‌شه تا فضا کافی بشه.

شورت‌هند flex: ترکیب هر سه Property

.item {
  flex: 1 1 200px;
}

Property به اسم flex، یک شورت‌هند برای هر سه Property‌ای‌ست که در این درس دیدیم.

flex: <flex-grow> <flex-shrink> <flex-basis>;

مقادیر کلیدواژه‌ای رایج

.flex-auto {
  flex: auto; /* معادل: flex-grow: 1; flex-shrink: 1; flex-basis: auto; */
}

.flex-1 {
  flex: 1; /* معادل: flex-grow: 1; flex-shrink: 1; flex-basis: 0; */
}

.flex-none {
  flex: none; /* معادل: flex-grow: 0; flex-shrink: 0; flex-basis: auto; */
}

.flex-initial {
  flex: initial; /* معادل: flex-grow: 0; flex-shrink: 1; flex-basis: auto (مقدار پیش‌فرض واقعی) */
}

این کلیدواژه‌ها، ترکیب‌های بسیار پرکاربردی رو، بدون نیاز به نوشتن هر سه مقدار جداگانه، فراهم می‌کنن.

کلیدواژه grow shrink basis کاربرد رایج
flex: 1 1 1 0 آیتمی که کل فضا را به‌طور مساوی با بقیه پر می‌کند
flex: auto 1 1 auto رشد و کوچک‌شدن، ولی با احترام به اندازه محتوا
flex: none 0 0 auto آیتمی با اندازه کاملاً ثابت

چرا شورت‌هند flex به نوشتن جداگانه سه Property ترجیح داده می‌شود؟

در عمل، توصیه رایج در پروژه‌های واقعی اینه که به‌جای نوشتن flex-grow، flex-shrink و flex-basis به‌طور جداگانه، از شورت‌هند flex استفاده بشه؛ چون این شورت‌هند، مقادیر پیش‌فرض منطقی‌تری برای Propertyهایی که ننویسیم در نظر می‌گیره، و احتمال فراموش کردن یکی از این سه مقدار (که می‌تونه رفتار غیرمنتظره‌ای ایجاد کنه) رو کاهش می‌ده.

یک مثال کامل و کاربردی: چیدمان با یک ستون ثابت و یک ستون انعطاف‌پذیر

.layout {
  display: flex;
}

.sidebar {
  flex: none;
  width: 250px;
}

.main-content {
  flex: 1;
}
<div class="layout">
  <div class="sidebar">نوار کناری</div>
  <div class="main-content">محتوای اصلی</div>
</div>

این الگو، دقیقاً همون چیزی‌ست که در فصل ۶، با واحد fr در Grid دیدیم؛ ولی این‌بار با Flexbox: .sidebar، با flex: none، همیشه دقیقاً ۲۵۰ پیکسل عرض ثابت داره، و .main-content، با flex: 1، تمام فضای باقی‌مانده رو، صرف‌نظر از عرض کل صفحه، به خودش اختصاص می‌ده.

نکات مهم

  • flex-basis اندازه پایه یک آیتم را، پیش از رشد یا کوچک‌شدن، مشخص می‌کند؛ مقدار پیش‌فرضش auto است.
  • flex-grow (پیش‌فرض 0) میزان سهم یک آیتم از فضای اضافه را، و flex-shrink (پیش‌فرض 1) میزان کوچک‌شدن آن در کمبود فضا را کنترل می‌کند.
  • شورت‌هند flex، ترکیب این سه Property را در یک خط فراهم می‌کند و در عمل، به نوشتن جداگانه هرکدام ترجیح داده می‌شود.

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

  • فراموش کردن این‌که flex-grow به‌طور پیش‌فرض صفر است؛ یعنی بدون تعریف صریح، آیتم‌ها هیچ فضای اضافه‌ای را پر نمی‌کنند.
  • قاطی کردن flex-basis با width، در حالی که در محاسبات Flexbox، معمولاً flex-basis اولویت دارد.
  • استفاده جداگانه و ناهماهنگ از flex-grow، flex-shrink و flex-basis، به‌جای استفاده از شورت‌هند flex که مقادیر پیش‌فرض منطقی‌تری دارد.

جمع‌بندی

flex-basis اندازه اولیه یک Flex Item را در طول Main Axis مشخص می‌کند، flex-grow سهم آن از فضای اضافه احتمالی را، و flex-shrink میزان کوچک‌شدنش در کمبود فضا را کنترل می‌کند. شورت‌هند flex، این سه مقدار را در یک Property واحد ترکیب می‌کند و با کلیدواژه‌های رایجی مثل flex: 1 یا flex: none، امکان ساخت چیدمان‌های ترکیبی (مثل یک ستون ثابت در کنار یک ستون کاملاً انعطاف‌پذیر) را به‌سادگی فراهم می‌کند.