تاروپود — خودآموز HTML و CSS

فصل ۳ از ۱۱

پیشرفت ترم
۰٪

ترم ۳ · Layout: چیدمان

چیدن و وسط‌چین کردن

فصل ۳پیش‌نمایش رایگان
۱۰ دقیقه مطالعه فصل ۳

در این فصل چه می‌سازی#

فصل قبل کارت‌ها را در یک ردیف چیدی، ولی همه سرِ شروعِ محور به هم چسبیده بودند. این فصل کنترلِ جای آن‌ها را به‌دست می‌گیری: با یک دستور در امتدادِ main axis پخششان می‌کنی — وسط، دو سر، با فاصلهٔ برابر — و با یک دستورِ دیگر روی cross axis می‌چینی‌شان. و بالاخره به همان چیزی می‌رسی که وسط‌چینش برای هر تازه‌کاری یک معماست: یک چیز، دقیقاً وسطِ صفحه، هم افقی و هم عمودی، در دو خط. آخرِ فصل یک جعبه داری که کارت‌هایش دقیقاً وسط نشسته‌اند.

طرح‌وارهٔ تفاوتِ justify-content و align-items: یک پیکانِ افقی که نشان می‌دهد justify-content روی main axis کار می‌کند و یک پیکانِ عمودی که نشان می‌دهد align-items روی cross axis کار می‌کند

آخر این فصل می‌توانی:

  • با justify-content آیتم‌ها را در امتدادِ main axis پخش کنی (وسط، دو سر، فاصلهٔ برابر)
  • با align-items آیتم‌ها را روی cross axis بچینی و بفهمی چرا به‌طورِ پیش‌فرض کشیده می‌شوند
  • تشخیص بدهی هر دستور روی کدام محور کار می‌کند و دیگر آن دو را قاطی نکنی
  • یک عنصر را دقیقاً وسطِ یک جعبه بیاوری، هم افقی و هم عمودی
  • با align-self فقط یک آیتم را جدا از بقیه بچینی

قبل از شروع#

  • از فصل ۲: display: flex، main axis و cross axis، و gap — کلِ این فصل روی همان دو محور سوار است.
  • از فصل ۲: در صفحهٔ RTLِ ما، main axisِ row از راست به چپ می‌رود.
  • از ترم ۲ فصل ۲: کلاسِ چندتایی روی یک عنصر (class="card top") — برای align-self لازمش داریم.

مثل همیشه فقط یک مرورگر لازم داری، یا فقط همین آزمایشگاه.

۱. دو دستور، دو محور#

از فصل قبل یادت هست که هر flex container دو محور دارد: main axis (جهتِ چیدن) و cross axis (عمود بر آن). حالا دو دستورِ اصلیِ این فصل، دقیقاً هرکدام روی یکی از این محورها کار می‌کنند — و کلِ فصل روی همین یک جمله می‌چرخد:

  • justify-content → آیتم‌ها را روی main axis پخش می‌کند.
  • align-items → آیتم‌ها را روی cross axis می‌چیند.

اگر همین یک جمله را نگه داری، هیچ‌وقت گم نمی‌شوی. بیا یک جعبهٔ بلند بسازیم تا هر دو محور جا برای بازی داشته باشند:

<main class="cards">
  <div class="card">۱</div>
  <div class="card">۲</div>
  <div class="card">۳</div>
</main>
.cards {
  display: flex;
  gap: 16px;
  height: 240px;
  background-color: #ffffff;
  border: 2px solid #2a6b93;
}

.card {
  padding: 24px;
  background-color: #2a6b93;
  color: #ffffff;
  font-size: 24px;
}

چک کن: یک جعبهٔ سفیدِ قاب‌دار به بلندیِ ۲۴۰ پیکسل می‌بینی و سه کارتِ آبی داخلش که سمتِ راست جمع شده‌اند و از بالا تا پایینِ جعبه کشیده شده‌اند. آن «سمتِ راست» همان main-startِ RTL است. آن «کشیده‌شدن تا کف» را در بخش‌های بعد توضیح می‌دهیم — فعلاً بسپارش به خاطر.

۲. justify-content: پخش‌کردن روی main axis#

justify-content جای آیتم‌ها را در امتدادِ main axis (اینجا افقی) تعیین می‌کند. چند مقدارِ پرکاربرد دارد. بیا center را امتحان کنیم:

.cards {
  display: flex;
  gap: 16px;
  height: 240px;
  justify-content: center;
  background-color: #ffffff;
  border: 2px solid #2a6b93;
}

چک کن: سه کارت به‌صورتِ یک گروه به وسطِ افقیِ جعبه رفتند. حالا مقدارها را یکی‌یکی عوض کن و هر بار نگاه کن:

  • flex-start → گروه می‌چسبد به شروعِ محور (در RTL سمتِ راست).
  • flex-end → می‌چسبد به انتها (سمتِ چپ).
  • space-between → اولی کاملاً یک سر، آخری کاملاً سرِ دیگر، فضای اضافه برابر بینشان پخش می‌شود.
  • space-around و space-evenly → فضا را جورِ دیگری پخش می‌کنند؛ امتحانشان کن و تفاوت را ببین.

space-between نانِ شبِ نوارهای ناوبری است: لوگو یک طرف، منو طرفِ دیگر، وسط خالی. همه‌اش با یک خط.

💡 نکته: چون justify-content روی main axis کار می‌کند، جهتِ RTL رویش اثر می‌گذارد: flex-start یعنی راست، نه چپ. اگر روزی «شروع» و «پایان» برعکسِ انتظارت بود، اول یادت بیاید صفحه RTL است.

۳. حالا وسطِ عمودی — و اینجا اشتباهِ کلاسیک را می‌کنیم#

کارت‌ها افقی وسط شدند، ولی هنوز از بالا تا پایینِ جعبه کشیده‌اند. می‌خواهی‌شان جمع‌وجور و در وسطِ عمودیِ جعبه بنشانی. اولین فکری که به ذهنِ تقریباً همه می‌رسد این است: «خب justify-content وسط‌چین می‌کند، پس لابد centerاش هم عمودی وسط می‌آورد.»

⚠️ مواظب باش: همین‌جا بزرگ‌ترین تلهٔ flexbox سرِ راهت است، و تقریباً هر تازه‌کاری یک‌بار تویش می‌افتد. وقتی می‌خواهی چیزی را عمودی وسط بیاوری، دستت خودبه‌خود می‌رود سراغِ justify-content — چون تنها دستورِ «وسط‌چین»ی است که تا حالا شناخته‌ای. از این به بعد، قبل از هر دستورِ چیدن یک ثانیه از خودت بپرس «این کار روی کدام محور است، main یا cross؟». همین یک سؤالِ کوچک، تو را از رایج‌ترین اشتباهِ کلِ ترم نجات می‌دهد.

بیا عمداً همان اشتباه را باور کنیم و ببینیم چه می‌شود — justify-content: center که از قبل هست را نگه دار و منتظرِ وسطِ عمودی بمان.

نگاه کن: کارت‌ها افقی وسط‌اند، ولی هنوز کاملاً کشیده‌اند از بالا تا پایین. هیچ چیزِ عمودی عوض نشد.

🔧 اگر کار نکرد: بله، عمدی است و این رایج‌ترین سردرگمیِ کلِ flexbox است. justify-content فقط روی main axis کار می‌کند، و main axisِ ما افقی است — پس هرچقدر هم centerاش کنی، فقط چپ‌وراست را وسط می‌آورد، نه بالاوپایین را. وسطِ عمودی روی cross axis است، و آن دستورِ دیگری دارد: align-items. و آن کشیده‌شدنِ کارت‌ها هم از همین‌جاست: مقدارِ پیش‌فرضِ align-items برابرِ stretch است، یعنی «آیتم‌ها را روی cross axis بکش تا کفِ جعبه». تا این را عوض نکنی، کارت‌ها کشیده می‌مانند.

پس قانون را دوباره بلند بگو: justify-content روی main axis (اینجا افقی)، align-items روی cross axis (اینجا عمودی). قاطی‌کردنِ این دو، همان تله‌ای است که همه یک‌بار تویش می‌افتند — تو دیگر نمی‌افتی.

۴. align-items: چیدن روی cross axis#

حالا دستورِ درست را اضافه کن. align-items: center هم کارت‌ها را از آن کشیدگی درمی‌آورد و به اندازهٔ محتوای خودشان جمعشان می‌کند، هم وسطِ عمودی می‌نشاندشان:

.cards {
  display: flex;
  gap: 16px;
  height: 240px;
  justify-content: center;
  align-items: center;
  background-color: #ffffff;
  border: 2px solid #2a6b93;
}

چک کن: کارت‌ها دیگر تا کف کشیده نیستند؛ به اندازهٔ خودشان جمع شده‌اند و دقیقاً وسطِ عمودیِ جعبه نشسته‌اند. حالا align-items را عوض کن و ببین:

  • flex-start → کارت‌ها می‌چسبند به بالای جعبه.
  • flex-end → می‌چسبند به پایین.
  • stretch → دوباره کشیده می‌شوند تا کف (همان پیش‌فرض).
  • center → وسطِ عمودی.

۵. وسط‌چینِ واقعی: هر دو محور با هم#

حالا معمای معروف حل می‌شود. آوردنِ یک چیز دقیقاً وسطِ یک جعبه — هم افقی هم عمودی — سال‌ها کابوسِ تازه‌کارها بود؛ شاید شنیده باشی بعضی‌ها با ترفندهایی مثلِ vertical-align تلاش می‌کردند و جواب نمی‌گرفتند. با flexbox جوابش فقط همین دو خطی است که همین الان نوشتی:

.cards {
  display: flex;
  justify-content: center;
  align-items: center;
}

justify-content: center وسطِ main axis، align-items: center وسطِ cross axis — و نتیجه، وسطِ کامل. این سه خط (display: flex و دو تا center) را حفظ کن؛ در کلِ عمرِ وب‌کاری‌ات بارها به‌کارش می‌بری.

قبل از ادامه، جواب بده: می‌خواهی کارت‌ها بروند پایینِ جعبه ولی افقی وسط بمانند. کدام دستور را چه‌کار می‌کنی؟ (جواب: align-items را flex-end کن — چون پایین‌رفتن روی cross axis است — و justify-content: center را دست‌نخورده بگذار.)

۶. align-self: یک آیتم، جدا از بقیه#

align-items روی همهٔ آیتم‌ها یک‌جا کار می‌کند. ولی گاهی می‌خواهی فقط یکی جای دیگری بنشیند. برای این، به خودِ آن آیتم align-self می‌دهی، که فقط او را روی cross axis می‌چیند و از قانونِ گروه بیرونش می‌کشد. به کارتِ سوم یک کلاسِ دوم بده:

<main class="cards">
  <div class="card">۱</div>
  <div class="card">۲</div>
  <div class="card top">۳</div>
</main>
.top {
  align-self: flex-start;
}

چک کن: کارتِ ۱ و ۲ هنوز وسطِ عمودی‌اند، ولی کارتِ ۳ رفت بالای جعبه. align-self روی همان cross axis کار می‌کند، فقط برای یک آیتم — انگار به آن یک کارت گفتی «تو به align-itemsِ گروه گوش نده، خودت بالا بنشین».

align-self دقیقاً همان مقدارهایی را می‌گیرد که align-items می‌گرفت: center، flex-start، flex-end و stretch — ولی فقط روی همان یک آیتم. مقدارِ کارتِ سوم را یک‌بار flex-end و یک‌بار center هم بده و ببین تنهایی جابه‌جا می‌شود، بی‌آنکه به دو کارتِ دیگر دست بزنی. این خیلی به‌کار می‌آید: کلِ گروه را با align-items یک‌جور می‌چینی و بعد یکی‌دو استثنا را با align-self جدا می‌کنی، بی‌آنکه ساختارِ HTML را عوض کنی.

🤖 با AI: یک عکس یا توضیح از چیدمانی که می‌خواهی به دستیارِ AI ات بده و بپرس «برای وسط‌چینِ عمودیِ این، justify-content را عوض کنم یا align-items را؟». این بهترین آزمونِ «AI هم اشتباه می‌کند» است: AI دربارهٔ محورها گاهی با اعتمادبه‌نفس جواب را جابه‌جا می‌گوید. جوابش را همان لحظه در آزمایشگاه امتحان کن — اگر چیزی که گفت عمودی وسط نیاورد، خودت می‌دانی مقصر کدام محور است.

کد کاملِ این فصل#

این هم دو فایلِ کاملِ این فصل، یک‌جا. اول index.html:

<!-- index.html -->
<!DOCTYPE html>
<html lang="fa" dir="rtl">
  <head>
    <meta charset="UTF-8">
    <title>چیدن و وسط‌چین کردن</title>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <main class="cards">
      <div class="card">۱</div>
      <div class="card">۲</div>
      <div class="card top">۳</div>
    </main>
  </body>
</html>

و styles.css:

/* styles.css */
.cards {
  display: flex;
  gap: 16px;
  height: 240px;
  justify-content: center;
  align-items: center;
  background-color: #ffffff;
  border: 2px solid #2a6b93;
}

.card {
  padding: 24px;
  background-color: #2a6b93;
  color: #ffffff;
  font-size: 24px;
}

.top {
  align-self: flex-start;
}

چک کن: روی صفحه یک جعبهٔ قاب‌دار می‌بینی که کارتِ ۱ و ۲ دقیقاً وسطش نشسته‌اند و کارتِ ۳ با align-self رفته بالا. justify-content روی main axis، align-items روی cross axis، و align-self یک استثنا برای یک آیتم — این سه، کلِ چیدنِ flex است.

واژه‌های تازهٔ این فصل#

کلمه تلفظ به حروف فارسی یعنی چه
justify-content جاستیفای کانتنت پخشِ آیتم‌ها روی main axis
align-items اَلاین آیتمز چیدنِ همهٔ آیتم‌ها روی cross axis
align-self اَلاین سِلف چیدنِ فقط یک آیتم روی cross axis، جدا از گروه
center سِنتر مقداری که آیتم‌ها را وسطِ محور می‌آورد
space-between اسپیس بیتوین اولی یک سر، آخری سرِ دیگر، فضا بینشان پخش
stretch استرچ پیش‌فرضِ align-items: کشیدنِ آیتم تا کفِ cross axis

تمرین‌ها

اول خودت فکر کن یا امتحان کن — بعد اینجا را باز کن.

در فصل بعد#

الان می‌توانی آیتم‌ها را روی هر دو محور هر جا که خواستی بنشانی. ولی تا اینجا هر آیتم اندازهٔ خودش را داشت و فضای اضافه خالی می‌ماند. فصل بعد آخرین قطعهٔ flexbox است و همان که اسمش را واقعی می‌کند — انعطاف: با flex-grow آیتم‌ها فضای خالی را پُر می‌کنند، با flex-shrink وقتی جا کم می‌آید جمع می‌شوند، و با flex-wrap وقتی دیگر جا نبود، به خطِ بعد می‌روند به‌جای اینکه از جعبه بیرون بزنند.

به آخر این فصل رسیدی!

اگر ساختی و جواب داد، این دکمه مال توست.