چند سال پیش، نشستم تا یک داشبورد بسازم. چیز خاصی نبود—فقط یک سایدبار ثابت، یک ناحیه محتوای اصلی و یک فوتر. Flexbox انتخاب بدیهی به نظر می‌رسید و در ابتدا هم درست کار می‌کرد. اما بعد، یک ردیف از کارت‌ها را در بخش اصلی قرار دادم. کل چیدمان از هم پاشید. سه ساعت بعدی را صرف کلنجار رفتن با نسبت‌های flex-grow و عرض‌های درصدیِ تو در تو کردم و تماشا کردم که کانتینرها هر چقدر هم که پدینگ (padding) کم می‌کردم، از قرارگیری در یک خط خودداری می‌کردند. صفحه مثل برجی بود که در آستانه سقوط است.

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

تفاوت در بُعد است

Flexbox را مانند یک راهرو تصور کنید. آیتم‌ها در یک جهت جریان دارند، یا به صورت ردیف یا به صورت ستون. این ابزار برای توزیع یک‌بعدی ساخته شده است. مرورگر به محتوا نگاه می‌کند و سپس تصمیم می‌گیرد که چگونه آن را در طول آن محور واحد، کشیده، کوچک یا تراز کند. این ویژگی باعث می‌شود Flexbox برای موقعیت‌هایی که در آن محتوا تعیین‌کننده چیدمان است، عالی باشد. یک نوار ناوبری (navigation bar)، مجموعه‌ای از فیلدهای فرم، یا مجموعه‌ای از تگ‌ها که نیاز به فاصله یکسان دارند، همگی به طور طبیعی در یک کانتینر flex قرار می‌گیرند، زیرا همگی از یک منطق خطی پیروی می‌کنند.

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

Flexbox هنوز هم کارایی خود را دارد

برای جایگزین کردن هر کانتینر flex با Grid عجله نکنید. در داخل اجزای (components) مجزا، Flexbox اغلب تمیزتر و منطقی‌تر است. اگر یک فوتر کارت با دو دکمه دارید و می‌خواهید یکی در سمت چپ و دیگری در سمت راست قرار بگیرد، justify-content: space-between دقیقاً همان کاری را انجام می‌دهد که مد نظر شماست. اگر نیاز دارید یک آیکون را در داخل دکمه‌ای با ارتفاع نامشخص به صورت عمودی وسط‌چین کنید، align-items: center ساده‌ترین راه است. محتوای متغیر—مانដូច ردیفی از نشان‌های کاربری با طول نام‌های متفاوت—به راحتی در Flexbox جای می‌گیرد زیرا اولویت با محتواست (content-first). کانتینر خود را با آنچه در بر می‌گیرد تطبیق می‌دهد.

در مقابل، Grid اولویت را به کانتینر می‌دهد (container-first). شما به مرورگر می‌گویید چه تعداد مسیر (track) وجود دارد و اندازه آن‌ها چقدر باید باشد، و سپس آیتم‌ها را در آن سلول‌ها قرار می‌دهید. اگر چیدمان شما واقعاً فقط یک خط از آیتم‌های هم‌سطح است که فضا را با هم تقسیم می‌کنند، استفاده از Grid فقط پیچیدگی‌های غیرضروری ایجاد می‌کند.

چیدمان صفحه متعلق به Grid است

اینجاست که Grid کنترل را به دست می‌گیرد. کابوس داشبورد من را به یاد دارید؟ ساختار باید از ابتدا به این شکل می‌بود:

.page {
  display: grid;
  min-height: 100vh;
  grid-template-rows: auto 1fr auto;
  grid-template-columns: 200px 1fr;
}

.header { grid-row: 1; grid-column: 1 / -1; }
.sidebar { grid-row: 2; grid-column: 1; }
.main { grid-row: 2; grid-column: 2; }
.footer { grid-row: 3; grid-column: 1 / -1; }

به آنچه در حال رخ دادن است نگاه کنید. کانتینر .page سه ردیف و دو ستون ایجاد می‌کند. ردیف اول به لطف auto اندازه خود را بر اساس محتوای هدر تنظیم می‌کند. ردیف میانی تمام فضای باقی‌مانده را با 1fr اشغال می‌کند. فوتر در ردیف نهایی قرار می‌گیرد و اندازه آن بر اساس محتوای خودش تنظیم می‌شود. در همین حال، سایدبار روی عرض ۲۰۰ پیکسل قفل می‌شود و ناحیه اصلی بقیه فضا را پر می‌کند.

منطق قرارگیری، تسکین‌دهنده اصلی است. هدر از خط ستون ۱ تا خط ۱- امتداد می‌یابد، که یعنی بدون توجه به اینکه بعداً چند ستون اضافه می‌کنید، در هر دو ستون کشیده می‌شود. سایدبار و محتوای اصلی ردیف ۲ را به اشتراک می‌گذارند اما در ستون‌های جداگانه قرار می‌گیرند. فوتر در ردیف ۳ دوباره به عرض کامل برمی‌گردد. شما نیازی به محاسبات درصدی روی فرزندان ندارید. نیازی به پوشش‌های (wrappers) تو در تو که بر سر ارتفاع با هم می‌جنگند، ندارید. عرض سایدبار را در یک جا تغییر دهید، و ناحیه اصلی به طور خودکار تنظیم می‌شود. کل چیدمان مانند یک سیستم واحد نفس می‌کشد.

خوانایی با استفاده از grid-template-areas

برای وضوح بیشتر، می‌توانید بخش‌های خود را نام‌گذاری کنید. به جای مدیریت شماره خطوط، یک نقشه بصری می‌نویسید:

.page {
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
}

.header { grid-area: header; }
.main { grid-area: main; }

حالا استایل‌شیت شما مانند یک وایرفریم (wireframe) خوانده می‌شود. اگر زمانی خواستید سایدبار برای یک نقطه شکست (breakpoint) متفاوت در سمت راست ظاهر شود، کافی است دو کلمه را در رشته‌ی قالب (template string) جابجا کنید. این نوع خوانایی ساختاری در میان انبوهی از کانتینرهای تو در تو flex غیرقابل دستیابی است.

دو درس سخت

Grid جادو نیست. دو اشتباه وجود دارد که چیدمان شما را به سرعت خراب می‌کند.

اولین مورد، استفاده‌ی بی‌دقت از واحدها است. اگر grid-template-columns: 1fr 1fr 1fr را تعریف کنید اما طراحی شما تنها به دو ستون محتوا نیاز داشته باشد، آن ستون (track) سوم همچنان وجود خواهد داشت. این ستون یا خالی می‌ماند و شکافی غیرمنتظره ایجاد می‌کند، یا محتوای اصلی شما را مجبور می‌کند تا به شکلی فشرده شود که طراحی شما را به‌هم می‌ریزد. آگاهانه عمل کنید. وقتی منظورتان دو ستون است، بنویسید repeat(2, 1fr).