در یک پروژه‌ی داشبورد مدیریتی، به نقطه‌ای رسیدم که چیدمان با Flexbox دیگر جواب نمی‌داد. باید ستون کناری، هدر، محتوای اصلی و فوتر را طوری می‌چیدم که در دسکتاپ سه‌ستونه، در تبلت دوسطونه و در موبایل تک‌ستونه باشد؛ و در کنار این، تعدادی کارت آماری هم داشته باشم که در عرض‌های مختلف خودشان بازچینش شوند. تلاش کردم با ترکیب چند لایه Flexbox این کار را انجام بدهم اما کد به یک هیولای پیچیده و شکننده تبدیل شد. آن روز اولین باری بود که واقعاً سراغ گرید در CSS رفتم و فهمیدم که این ابزار، دقیقاً برای همان دسته از مسائلی ساخته شده که Flexbox ذاتاً نمی‌تواند تمیز حل کند.

Grid (گرید) در سال ۲۰۱۷ به مرورگرها آمد و یکی از بزرگ‌ترین تغییرات در نحوه‌ی تفکر ما درباره‌ی چیدمان بود. اگر از مسیر آموزش CSS از صفر عبور کرده‌اید و یا فلکس باکس در CSS را خوانده‌اید، این نوشته مرحله‌ی بعدی و طبیعی مسیر شماست؛ چون Grid به‌جای رقابت با Flexbox، آن را کامل می‌کند.

چرا Grid معادله‌ی چیدمان را عوض کرد؟

Flexbox برای چیدمان یک‌بعدی طراحی شده بود: یا سطر یا ستون. وقتی نیاز به چیدمان دوبعدی دارید — یعنی هم‌زمان سطر و ستون را کنترل می‌کنید — Flexbox ذاتاً ابزار مناسب نیست، چون هر بار مجبور می‌شوید با لایه‌های تودرتو و کلاس‌های کمکی، آن یک بُعد گم‌شده را به‌زور بازسازی کنید.

Grid این محدودیت را از ریشه حل کرد. سه تفاوت بنیادی که در تجربه‌ی پروژه‌هایم بیشترین اثر را داشته‌اند:

  • تعریف صریح ساختار: می‌توانید بگویید «این ناحیه چهار ستون و سه سطر دارد» بدون اینکه به محتوا نگاه کنید. بعد محتوا را در آن ساختار جای می‌دهید.
  • نام‌گذاری نواحی: چیدمان را با grid-template-areas به شکل یک نقشه‌ی بصری در کد می‌نویسید. این تک‌قابلیت به‌تنهایی، نیمی از سردرگمی‌های چیدمان پیچیده را حذف می‌کند.
  • کنترل مستقل سطر و ستون: می‌توانید ردیف‌ها را با یک قاعده و ستون‌ها را با قاعده‌ای دیگر کنترل کنید؛ چیزی که در Flexbox با ترفندهای تودرتو شبیه‌سازی می‌شد.

یک نکته‌ی مهم که تجربه‌ی سال‌های اخیر به من ثابت کرد: Grid به Flexbox پایان نداد، بلکه آن را کامل کرد. امروز در پروژه‌های خودم، ساختار کلی صفحه با Grid و اجزای داخلی آن با Flexbox چیده می‌شوند. اگر می‌خواهید این همکاری را به‌طور کامل ببینید، CSS مدرن: از Flexbox تا Grid را در کنار این مقاله بخوانید.

Flexbox به شما می‌گوید محتوا چطور در یک خط بچیند؛ Grid به شما می‌گوید صفحه چطور در چند بعد ساخته شود. اولی جریان را می‌سازد، دومی بستر را.

مدل ذهنی: سطر، ستون و خطوط نامرئی

در Grid، همه چیز حول سه مفهوم می‌چرخد:

۱. مسیرها (Tracks)

Grid از مسیرهای افقی (ردیف) و عمودی (ستون) تشکیل شده. هر مسیر، یک واحد مستقل است که می‌توانید اندازه‌اش را تعریف کنید.

۲. خطوط (Lines)

مرزهای بین مسیرها را خط می‌گویند. شماره‌گذاری خطوط از یک شروع می‌شود و می‌توانید آیتم‌ها را با شماره‌ی خطوط جای دهید: grid-column: 2 / 4 یعنی «از خط دوم تا خط چهارم ستون». این شماره‌گذاری، رایج‌ترین منبع سردرگمی تازه‌کارهاست چون خطوط با ستون‌ها اشتباه گرفته می‌شوند.

۳. ناحیه‌ها (Areas)

هر مجموعه‌ی مستطیلی از سلول‌های Grid را می‌توان نام‌گذاری کرد و بعد آیتم‌ها را به آن ناحیه وصل کرد. این سطح انتزاع، چیدمان را از «مختصات عددی» به «نقشه‌ی بصری» ارتقا می‌دهد.

یک تصویر ذهنی که در آموزش تیم‌ها استفاده می‌کنم: Grid را مثل یک صفحه‌ی شطرنج ببینید که می‌توانید خودتان شبکه‌ی آن را تعریف کنید. بعد مهره‌ها را روی هر خانه یا خانه‌های دلخواه قرار می‌دهید.

اولین خط Grid: تعریف و فعال‌سازی

فعال‌سازی Grid با یک خط شروع می‌شود:

.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 1rem;
}

همین سه خط، یک شبکه‌ی سه‌ستونه با فاصله‌ی یک رم بین ستون‌ها می‌سازد. چیزی که در Flexbox نیاز به محاسبه‌ی دقیق عرض، flex-basis و gap داشت، اینجا با یک توصیف ساده اتفاق می‌افتد.

نکته‌ی ظریف که سال اول کارم را به خودش مشغول کرد: Grid روی فرزندان مستقیم اثر می‌گذارد، نه نوه‌ها. اگر نوه‌ها نیاز به چیدمان Grid دارند، باید روی والد خودشان display: grid بگذارید. این مشابه رفتار Flexbox است و اگر این را درونی کنید، در پروژه‌های بزرگ سردرگم نمی‌شوید.

واحد fr و منطق تقسیم فضا

واحد fr قلب انعطاف‌پذیری Grid است. این واحد به معنای «سهمی از فضای آزاد» است. سه کاربرد که در پروژه‌ها به‌کارم آمده:

  • grid-template-columns: 1fr 1fr — دو ستون هم‌عرض که فضای آزاد را نصف می‌کنند.
  • grid-template-columns: 250px 1fr — ستون کنار ثابت و ستون محتوا پرکننده.
  • grid-template-columns: 2fr 1fr — محتوای اصلی دو برابر سایدبار جا می‌گیرد.

تفاوت مهم fr با درصد: در 50% فضای در دسترس دقیقاً نصف می‌شود، در حالی که 1fr ابتدا فضای آزاد باقیمانده را حساب می‌کند و بعد بین بخش‌ها تقسیم می‌کند. این تفاوت، در پروژه‌هایی که gap یا padding سراسری دارند، تفاوت بین چیدمان سالم و چیدمان ریخته‌به‌هم است.

template areas: چیدمان با نام، نه عدد

محبوب‌ترین قابلیت Grid برای من همین است. به‌جای دست‌وپنجه نرم کردن با شماره‌ی خطوط، می‌توانید نقشه‌ی چیدمان را با نام بنویسید:

.layout {
  display: grid;
  grid-template-areas:
    "header header header"
    "sidebar main   aside"
    "footer footer footer";
  grid-template-columns: 200px 1fr 150px;
  grid-template-rows: auto 1fr auto;
  gap: 1rem;
}

.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.aside   { grid-area: aside; }
.footer  { grid-area: footer; }

همین یک قطعه کد، ساختار کامل یک صفحه‌ی داشبورد را توصیف می‌کند. مزیت واقعی: در بازبینی کد، اولین چیزی که چشم می‌بیند، ساختار صفحه است — نه شماره‌های انتزاعی. این یک تصمیم نگهداری است که در پروژه‌های بلندمدت پول زیادی ذخیره می‌کند.

وقتی چیدمان با نام نوشته می‌شود، کد به یک نقشه تبدیل می‌شود؛ هر کسی که به پروژه اضافه شود، در چند دقیقه ساختار را می‌فهمد.

minmax، auto-fit و ریسپانسیو بدون media query

یکی از جادویی‌ترین قابلیت‌های Grid همین است: می‌توانید کارت‌هایی بسازید که بدون حتی یک خط media query، خودشان در عرض‌های مختلف بازچینش شوند:

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 1rem;
}

این قطعه کد را در پروژه‌هایم بارها استفاده کرده‌ام و همچنان محبوب‌ترین قطعه‌ی Grid است. معنایش این است: «تا جایی که عرض اجازه بدهد، هر کارت حداقل ۲۵۰ پیکسل باشد؛ اگر بیشتر جا بود، فضا را به‌طور مساوی بین‌شان تقسیم کن.»

تفاوت auto-fit و auto-fill را در پروژه‌ها دیده‌ام که گیج‌کننده است:

مقداررفتارکجا استفاده کنم
auto-fitستون‌های خالی جمع می‌شوند و آیتم‌ها کشیده می‌شوندکارت‌ها، گالری، مقالات
auto-fillستون‌های خالی رزرو می‌مانندوقتی می‌خواهید آیتم‌ها فشرده نمانند

این الگو به‌خصوص در قالب‌های وردپرسی که لیست پست‌ها یا محصولات دارند، فوق‌العاده است. به‌جای نوشتن سه یا چهار media query، یک خط CSS همه‌چیز را حل می‌کند. برای مطالعه‌ی بیشتر در این زمینه، طراحی ریسپانسیو چیست و ریسپانسیو کردن سایت را ببینید.

ترازبندی در دو محور

Grid دو دسته خاصیت برای ترازبندی دارد، مشابه Flexbox اما در سطحی دقیق‌تر:

  • justify-items و justify-self — ترازبندی افقی.
  • align-items و align-self — ترازبندی عمودی.
  • justify-content و align-content — توزیع کل شبکه در container.

تفاوت اصلی با Flexbox: در Grid، ترازبندی روی هر آیتم می‌تواند مستقل از دیگران باشد و در سطح هر سلول اتفاق بیفتد. در Flexbox، ترازبندی روی کل محور انجام می‌شود.

.centered {
  display: grid;
  place-items: center;
  min-height: 100vh;
}

کوتاه‌نوشت place-items: center همان چیزی است که سال‌ها با ترفندهای پیچیده دنبالش بودیم. دو خاصیت align-items و justify-items را یک‌جا می‌نویسد.

گرید پنهان و ردیف‌های خودکار

یکی از مفاهیمی که در ابتدا سردرگم‌کننده است اما بعد از درک آن، تحول بزرگی در کد ایجاد می‌کند: Grid دو نوع شبکه دارد.

  • Grid صریح (Explicit): چیزی که شما با grid-template-columns و grid-template-rows تعریف می‌کنید.
  • Grid ضمنی (Implicit): شبکه‌ای که مرورگر وقتی محتوا بیشتر از فضای تعریف‌شده باشد، خودش می‌سازد.

اگر محتوای شما از سه سطر تعریف‌شده بیشتر شود، مرورگر ردیف چهارم را با اندازه‌ی پیش‌فرض (auto) می‌سازد. برای کنترل این رفتار:

.auto-rows {
  grid-auto-rows: minmax(100px, auto);
  grid-auto-flow: row dense;
}

grid-auto-flow: row dense باعث می‌شود مرورگر سوراخ‌های باقیمانده در شبکه را با آیتم‌های کوچکتر پر کند. این یک ترفند کوچک اما گاهی تفاوت بین یک گالری پیوسته و یک گالری پر از فضای خالی است.

الگوهای واقعی از پروژه‌ها

سه الگویی که در پروژه‌هایم بیش از همه به‌کارم آمده‌اند:

۱. چیدمان کامل صفحه (Holy Grail Layout)

با grid-template-areas، ساختار کلاسیک هدر، سایدبار، محتوا و فوتر در چند خط حل می‌شود. این الگو سال‌ها با float و ترفندهای عجیب حل می‌شد و امروز با شش خط CSS تمیز و خوانا است.

۲. گالری خودتنظیم

ترکیب repeat(auto-fit, minmax(...)) با gap یک گالری می‌سازد که در هر عرض، تعداد مناسبی آیتم نشان می‌دهد. در پروژه‌های فروشگاهی که تعداد کارت‌ها زیاد است، این یک قطعه‌ی دائمی CSS است.

۳. فرم پیچیده

فرم‌هایی که در دسکتاپ دو ستونه و در موبایل یک‌ستونه هستند، با Grid تمیزتر از Flexbox حل می‌شوند:

.form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem;
}

.form .full-width {
  grid-column: 1 / -1;
}

کد 1 / -1 یعنی «از خط اول تا آخرین خط»؛ یک ترفند ساده که به شما اجازه می‌دهد بعضی فیلدها کل عرض را بگیرند.

Grid یا Flexbox؛ تصمیم‌نامه‌ی همکاری

این سؤال هر ماه در تیم‌های فنی تکرار می‌شود و جواب صادقانه این است: هیچ‌کدام بهتر نیستند، برای کارهای متفاوتی طراحی شده‌اند.

موقعیتانتخابدلیل
ساختار کلی صفحه (نواحی)Gridکنترل صریح روی هر دو بعد
کارت‌های هم‌عرض در ردیف‌های چندگانهGridترازبندی دقیق بین ردیف‌ها
تولبار، منو، فرم سادهFlexboxچیدمان جریانی و سبک‌تر
ترازبندی یک‌بعدی محتواFlexboxمنطق محور واحد، مستقیم‌تر
گالری خودتنظیمGridauto-fit و minmax اختصاصی Grid
دکمه‌ها و بج‌ها در کنار همFlexboxجریان آزاد و بدون شبکه

الگوی خودم در پروژه‌های واقعی: ساختار با Grid، اجزا با Flexbox. یعنی ناحیه‌های اصلی صفحه (هدر، محتوا، سایدبار، فوتر) در یک Grid تعریف می‌شوند؛ و داخل هر ناحیه، اجزای ساده با Flexbox چیده می‌شوند. این ترکیب، هم خواناتر است و هم مقیاس‌پذیرتر.

برای مطالعه‌ی سمت مقابل این تصمیم و نکات ریز Flexbox، مقاله‌ی فلکس باکس در CSS را در کنار این مقاله بخوانید. اگر می‌خواهید این دو را در چارچوب قالب‌های وردپرسی ببینید، قالب وردپرس چیست نقطه‌ی شروع خوبی است.

اشتباهاتی که در پروژه‌ها دیدم

  • استفاده از Grid برای همه‌چیز: در پروژه‌ای که حتی برای یک دکمه از Grid استفاده کرده بودند، کد شبیه یک شبکه‌ی سازمانی شده بود. Grid ابزار چیدمان ساختاری است، نه ابزار جایگزین Flexbox برای هر چیز.
  • اشتباه گرفتن خطوط و ستون‌ها: grid-column: 1 / 3 یعنی «از خط یک تا خط سه» که شامل دو ستون می‌شود، نه سه. این تله در روزهای اول بیشترین گیجی را برای خود من هم ساخته بود.
  • تعریف نکردن grid-template-rows: اگر فقط ستون‌ها را تعریف کنید، ردیف‌ها با محتوا رشد می‌کنند و ممکن است ارتفاع ناهمگون بگیرند. برای کارت‌های هم‌ارتفاع، صریحاً ارتفاع یا grid-auto-rows را تنظیم کنید.
  • نادیده گرفتن min-width: 0 روی آیتم‌ها: همان تله‌ای که در Flexbox وجود دارد، در Grid هم هست. محتوای طولانی می‌تواند آیتم را از سلولش بیرون بزند اگر min-width: 0 را نگذارید.
  • استفاده از Grid برای جدول‌های داده‌ای: جدول‌های واقعی HTML معنای خودشان را دارند و برای screen readerها بهترند. Grid برای چیدمان بصری طراحی شده، نه برای جایگزینی ساختار semantically درست.

بخشی از این اشتباهات در ترفندهای CSS برای طراحی سریع‌تر هم فهرست شده. اگر در پروژه‌ای هستید که با وجود Grid هنوز چیدمان به هم می‌ریزد، پیشنهاد می‌کنم انتخابگرهای CSS را مرور کنید؛ چون بخش قابل توجهی از این مشکلات از انتخابگرهای شکننده می‌آید، نه از خود Grid.

لایه‌ای زیر سینتکس Grid

اگر می‌خواهید به لایه‌ی مهندسی موتور رندر نفوذ کنید، چهار مفهوم را بشناسید:

  1. Grid Formatting Context و Layout تک‌پاسه: برخلاف Flexbox که در بعضی موارد نیاز به چند پاس اندازه‌گیری دارد، Grid در اکثر سناریوها با یک پاس کامل چیدمان را resolve می‌کند. علتش این است که در Grid، مسیرها از قبل تعریف شده‌اند و مرورگر با یک الگوریتم خطی، آیتم‌ها را در سلول‌ها جای می‌دهد. اما اگر از auto و min-content و محتوای دینامیک زیاد استفاده کنید، همین الگوریتم ممکن است چند پاس شود.
  2. Intrinsic Sizing و چرخه‌ی اندازه‌گیری: وقتی minmax() را با auto یا min-content ترکیب می‌کنید، مرورگر ناچار می‌شود برای تعیین اندازه‌ی سلول، محتوای داخلش را اندازه بگیرد. این کار در گالری‌های بزرگ با تصاویر متنوع، می‌تواند زمان layout را افزایش دهد. توصیه‌ی عملی: برای گالری‌های بزرگ، اندازه‌ی سلول را صریح تعریف کنید و از مقدار پویا اجتناب کنید.
  3. Grid Item Placement Algorithm و الگوریتم dense: الگوریتم پیش‌فرض Grid آیتم‌ها را به‌ترتیب جای می‌دهد و اگر آیتمی با اندازه‌ی بزرگ‌تر از سلول‌های باقیمانده باشد، آن‌ها را خالی می‌گذارد. grid-auto-flow: dense این الگوریتم را تغییر می‌دهد تا مرورگر برگردد و سوراخ‌های قبلی را پر کند. این تصمیم کوچک، می‌تواند در گالری‌های پیچیده، تفاوت قابل توجهی در پروفایلر ایجاد کند — هم خوب (کاهش فضای خالی) و هم بد (افزایش زمان layout به‌خاطر جستجوهای متعدد).
  4. Interaction با فریم‌ورک‌های JS و Virtual DOM: اگر Grid را در React یا Vue با تعداد زیادی از آیتم‌های دینامیک به‌کار می‌برید، هر بار که تعداد آیتم‌ها تغییر می‌کند، مرورگر کل layout را از نو محاسبه می‌کند. این هزینه در پروژه‌های داشبوردی که مکرر داده‌ها آپدیت می‌شوند، محسوس است. برای مطالعه‌ی راه‌حل‌های سطح پایین‌تر، بهینه سازی جاوااسکریپت را ببینید.

یک تجربه‌ی واقعی از پروژه‌ی داشبورد که با آن شروع کردم: گالری کارت‌های آماری با ترکیب minmax و auto-fit زیبا بود، اما با اضافه شدن قابلیت فیلتر و رندر مجدد، زمان layout به‌طور محسوس بالا رفت. با صریح کردن اندازه‌ی سلول‌ها و کاهش تعداد آیتم‌های dynamic، تفاوت قابل توجهی در پروفایلر Chrome دیده شد. برای مطالعه‌ی موازی این لایه با ساختار سطح بالاتر، استانداردهای HTML و CSS و بهینه‌سازی CSS را در کنار این بخش بخوانید.

Grid چیدمان را از یک ترفند به یک زبان توصیفی تبدیل کرد؛ اما هر چه این زبان آزادتر باشد، به همان اندازه باید مراقب هزینه‌ی اندازه‌گیری موتور رندر بود.

برای درک اینکه این لایه چطور با حجم کلی CSS و سرعت رندر تعامل دارد، بهینه‌سازی سرعت سایت را ببینید؛ چون هزینه‌ی layout در نهایت روی همان سه شاخص سرعت و تجربه‌ی کاربری اثر می‌گذارد. اگر در پروژه‌ی وردپرسی با قالب سنگین کار می‌کنید، ترکیب Grid با قالب سبک و متغیرهای CSS یکی از تمیزترین تصمیم‌های معماری است.

آنچه در پایان این مسیر می‌گویم

Grid را می‌توان در یک جمله خلاصه کرد: «ابزار چیدمان دوبعدی با کنترل صریح روی ساختار.» سه درس که در پایان این مسیر روی آن‌ها تأکید می‌کنم:

  1. تفکر ساختاری را قبل از سینتکس تمرین کنید. قبل از نوشتن، روی کاغذ ناحیه‌های صفحه را رسم کنید و بعد به Grid ترجمه کنید. این یک دقیقه سرمایه‌گذاری، ساعت‌ها بازبینی را حذف می‌کند.
  2. auto-fit و minmax را به‌عنوان ابزار ریسپانسیو اصلی در نظر بگیرید. تا جایی که ممکن است، media query را با این دو جایگزین کنید. نتیجه، کدی است که در برابر تغییرات عرض ویوپورت بدون دخالت شما مقاوم می‌شود.
  3. Grid را جایگزین Flexbox نبینید. این دو مکمل همدیگرند. اگر در یک پروژه هر دو را به‌طور آگاهانه به‌کار ببرید، معماری CSS شما از هر پروژه‌ای که فقط یکی را می‌شناسد، پایدارتر خواهد بود.

اگر در پروژه‌ای با ترکیب این دو ابزار به یک الگوی جالب رسیده‌اید — مثلاً یک چیدمان پیچیده که با تعریف دقیق نواحی، کد را نصف کرده — تجربه‌ی خودتان را در دیدگاه بنویسید. مخصوصاً اگر در پروژه‌ای وردپرسی یا React با مشکل رندر مواجه شده‌اید و Grid یا ترکیب آن با Flexbox راه‌حل آورده، جزئیات همان سناریو برای خواننده‌ی بعدی از هر توضیح عمومی ارزشمندتر است. 🗺️