مقایسه جامع Container Queries و Media Queries | طراحی ریسپانسیو مدرن در CSS
خلاصه مطلب
Media Queries سالها استاندارد طراحی ریسپانسیو بودند، اما Container Queries انقلابی در این حوزه ایجاد کردهاند. در این مقاله، تفاوتهای این دو رویکرد را یاد میگیرید و میفهمید کی از کدام استفاده کنید. همراه با ۱۵+ مثال عملی، ساخت ویجتهای مستقل و پروژه کامل.
مقدمه: محدودیت Media Queries و تولد Container Queries
برای سالهای طولانی، Media Queries تنها راه طراحی ریسپانسیو بود. اما یک مشکل بزرگ داشت: Media Queries به اندازه صفحه نمایش (viewport) نگاه میکند، نه به اندازه المان والد. این یعنی اگر یک کامپوننت (مثل کارت محصول) را در جای مختلف صفحه با عرضهای مختلف قرار دهید، نمیتواند واکنش متفاوتی نشان دهد.
محدودیت Media Queries:
-
یک کارت در سایدبار (عرض ۲۵۰px) و در main (عرض ۸۰۰px) یکسان به نظر میرسد
-
کامپوننتها قابل استفاده مجدد در هر جای صفحه نیستند
-
برای هر اندازه صفحه باید جداگانه کد بزنید
راه حل: Container Queries
Container Queries به اندازه المان والد (container) نگاه میکند. یعنی یک کامپوننت مستقل از اندازه صفحه، بر اساس جایگاهی که در آن قرار گرفته، استایل متفاوت میگیرد.
مقایسه سریع: Media Queries vs Container Queries
| ویژگی | Media Queries | Container Queries |
|---|---|---|
| نگاه به | اندازه viewport (صفحه نمایش) | اندازه المان والد (container) |
| کاربرد اصلی | چیدمان کلی صفحه | کامپوننتهای مستقل |
| قابلیت استفاده مجدد | محدود (به جایگاه وابسته است) | بالا (کاملاً مستقل) |
| ساخت ویجت | دشوار | بسیار آسان |
| سینتکس | @media (max-width: 768px) | @container (max-width: 400px) |
| پشتیبانی مرورگر | کامل (از قدیم) | تمام مرورگرهای مدرن از ۲۰۲۳ |
| نیاز به تعریف کانتینر | خیر | بله (با container-type) |
مفاهیم پایه Container Queries (مرور سریع)
| ویژگی | مقدارهای رایج | توضیح |
|---|---|---|
| container-type | inline-size, block-size, size, normal | نوع کانتینر (معمولاً inline-size) |
| container-name | نام دلخواه (مثل sidebar, card) | نامگذاری کانتینر |
| @container | (min-width: 300px) | شرط query |
| container (مخفف) | sidebar / inline-size | ترکیب type و name |
۱۵+ مثال کاربردی Container Queries در مقایسه با Media Queries
مثال ۱: تفاوت اساسی – Media Queries به کل صفحه نگاه میکند
/* Media Queries – به کل صفحه نگاه میکند */ @media (max-width: 600px) { .card { display: block; } .card img { width: 100%; } } @media (min-width: 601px) { .card { display: flex; } .card img { width: 200px; } }
مشکل: اگر این کارت را در سایدبار ۲۵۰px قرار دهید، باز هم نمایش flex میگیرد (چون صفحه بزرگ است) و ظاهر آن خراب میشود.
مثال ۲: راه حل با Container Queries – کامپوننت هوشمند
/* تعریف کانتینر */ .card-container { container-type: inline-size; } /* Container Queries – به اندازه والد نگاه میکند */ @container (max-width: 300px) { .card { display: block; } .card img { width: 100%; } } @container (min-width: 301px) { .card { display: flex; } .card img { width: 120px; } }
<!-- این کارت در هر جایی که قرار بگیرد، بر اساس عرض والد خودش رفتار میکند --> <div class="card-container" style="width: 250px;"> <div class="card"> <img src="image.jpg"> <div class="card-content">...</div> </div> </div> <div class="card-container" style="width: 500px;"> <div class="card"> <!-- اینجا flex نمایش داده میشود --> <img src="image.jpg"> <div class="card-content">...</div> </div> </div>
مثال ۳: کارت محصول هوشمند – کاملاً مستقل
یک کارت محصول که در عرضهای مختلف، چیدمان خود را تغییر میدهد.
.product-container { container-type: inline-size; container-name: product; } .product-card { background: white; border-radius: 12px; overflow: hidden; transition: all 0.3s; } /* حالت باریک (موبایل داخل سایدبار) */ @container product (max-width: 300px) { .product-card { display: block; text-align: center; } .product-image { width: 100%; height: 150px; } .product-title { font-size: 16px; } } /* حالت متوسط */ @container product (min-width: 301px) and (max-width: 500px) { .product-card { display: flex; gap: 15px; } .product-image { width: 120px; height: 120px; } } /* حالت پهن (برای main صفحه) */ @container product (min-width: 501px) { .product-card { display: flex; gap: 20px; } .product-image { width: 200px; height: 200px; } .product-title { font-size: 24px; } }
مثال ۴: ویجت آب و هوا (Weather Widget) – قابلیت استفاده مجدد بالا
یک ویجت که در هدر، سایدبار و فوتر میتواند قرار بگیرد و هر بار ظاهر متفاوتی داشته باشد.
.weather-container { container-type: inline-size; container-name: weather; } .weather-widget { background: linear-gradient(135deg, #667eea, #764ba2); border-radius: 16px; padding: 16px; color: white; } /* حالت کوچک (برای سایدبار یا فوتر) */ @container weather (max-width: 200px) { .weather-widget { text-align: center; } .temp { font-size: 24px; } .details { display: none; /* جزئیات را مخفی کن */ } } /* حالت بزرگ (برای هدر یا main) */ @container weather (min-width: 201px) { .weather-widget { display: flex; justify-content: space-between; align-items: center; } .temp { font-size: 48px; } .details { display: block; } }
مثال ۵: ناوبری (Navbar) که با عرض کانتینر تغییر میکند
یک منو که در هدر پهن، همه آیتمها را نشان میدهد و در سایدبار، به صورت آیکون درمیآید.
.nav-container { container-type: inline-size; container-name: nav; } .nav-menu { display: flex; gap: 10px; } .nav-item { padding: 10px; } /* عرض کم: فقط آیکونها */ @container nav (max-width: 300px) { .nav-item span { display: none; } .nav-item { font-size: 24px; } } /* عرض متوسط: متن + آیکون */ @container nav (min-width: 301px) and (max-width: 500px) { .nav-item { display: flex; gap: 8px; } } /* عرض زیاد: همه چیز */ @container nav (min-width: 501px) { .nav-menu { justify-content: space-around; } }
مثال ۶: گالری تصاویر تطبیقی با Container Queries
گالری که بر اساس عرض والد، تعداد ستونها را تغییر میدهد.
.gallery-container { container-type: inline-size; } .gallery { display: grid; gap: 16px; } @container (min-width: 600px) { .gallery { grid-template-columns: repeat(3, 1fr); } } @container (min-width: 400px) and (max-width: 599px) { .gallery { grid-template-columns: repeat(2, 1fr); } } @container (max-width: 399px) { .gallery { grid-template-columns: 1fr; } }
مثال ۷: مقاله یا بلاگ پست با چیدمان متغیر
یک مقاله که در عرضهای مختلف، اندازه فونت و حاشیه را تغییر میدهد.
.article-container { container-type: inline-size; } .article { padding: 20px; } @container (min-width: 800px) { .article { font-size: 18px; padding: 40px; max-width: 700px; margin: 0 auto; } .article h1 { font-size: 36px; } } @container (max-width: 799px) { .article { font-size: 14px; padding: 15px; } .article h1 { font-size: 24px; } }
مثال ۸: دکمه جستجو (Search Bar) هوشمند
یک نوار جستجو که در عرض کم، فقط آیکون و در عرض زیاد، ورودی کامل نشان میدهد.
.search-container { container-type: inline-size; } .search-bar { display: flex; align-items: center; background: #f0f0f0; border-radius: 24px; } .search-input { border: none; background: transparent; padding: 10px; transition: all 0.3s; } .search-icon { padding: 10px; cursor: pointer; } @container (max-width: 150px) { .search-input { display: none; /* فقط آیکون */ } } @container (min-width: 151px) { .search-input { display: block; width: 100%; } }
مثال ۹: مقایسه مستقیم – ساخت یک صفحه کامل با هر دو روش
/* Media Queries – برای چیدمان کلی صفحه */ @media (max-width: 768px) { .page { grid-template-columns: 1fr; } .sidebar { order: 2; } } @media (min-width: 769px) { .page { grid-template-columns: 280px 1fr; } } /* Container Queries – برای کامپوننتهای داخل صفحه */ .sidebar-container { container-type: inline-size; } .main-container { container-type: inline-size; } /* ویجت سایدبار – بر اساس عرض سایدبار */ @container (max-width: 250px) { .widget { display: block; text-align: center; } .widget-icon { font-size: 32px; } } @container (min-width: 251px) { .widget { display: flex; gap: 15px; } } /* ویجت main – بر اساس عرض اصلی */ @container (min-width: 600px) { .product-grid { grid-template-columns: repeat(3, 1fr); } } @container (max-width: 599px) { .product-grid { grid-template-columns: repeat(2, 1fr); } }
مثال ۱۰: کارت نظرات کاربران (Comment Card)
یک کارت نظر که در عرض کم، تصویر بالا و در عرض زیاد، تصویر کنار متن است.
.comment-container { container-type: inline-size; } .comment { display: flex; gap: 16px; padding: 16px; background: #f8f9fa; border-radius: 12px; } .avatar { width: 50px; height: 50px; border-radius: 50%; background: #3498db; } @container (max-width: 300px) { .comment { flex-direction: column; text-align: center; } .avatar { margin: 0 auto; } }
مثال ۱۱: نامگذاری چندین کانتینر (container-name)
استفاده از نام برای کانتینرهای مختلف در یک صفحه.
.sidebar { container-name: sidebar; container-type: inline-size; } .main { container-name: main; container-type: inline-size; } .footer { container-name: footer; container-type: inline-size; } /* هر کدام قوانین جداگانه دارند */ @container sidebar (max-width: 200px) { .menu-item span { display: none; } } @container main (min-width: 700px) { .product-card { display: flex; } } @container footer (max-width: 400px) { .footer-links { flex-direction: column; } }
مثال ۱۲: کانتینرهای تو در تو (Nested Containers)
قدرت واقعی Container Queries زمانی است که کانتینرها داخل هم قرار میگیرند.
.outer { container-type: inline-size; container-name: outer; } .inner { container-type: inline-size; container-name: inner; } @container outer (min-width: 500px) { .outer-box { background: red; } } @container inner (max-width: 200px) { .inner-box { background: blue; } }
مثال ۱۳: استفاده با CSS Grid برای حداکثر قدرت
ترکیب Container Queries و Grid برای ساخت ویجتهای فوقالعاده تطبیقی.
.dashboard-widget { container-type: inline-size; } .widget-content { display: grid; gap: 16px; } @container (min-width: 400px) { .widget-content { grid-template-columns: repeat(2, 1fr); } } @container (min-width: 600px) { .widget-content { grid-template-columns: repeat(4, 1fr); } }
مثال ۱۴: انیمیشن با Container Queries
تغییر استایل همراه با انیمیشن.
.animated-container { container-type: inline-size; transition: all 0.3s; } .box { width: 100px; height: 100px; background: #3498db; transition: all 0.3s; } @container (min-width: 300px) { .box { width: 150px; background: #e74c3c; transform: rotate(10deg); } }
مثال ۱۵: پشتیبانی از Container Queries در مرورگرهای قدیمی (fallback)
روش نوشتن کد برای مرورگرهای قدیمی که Container Queries را پشتیبانی نمیکنند.
/* Fallback برای مرورگرهای قدیمی */ .card { display: block; } /* فقط مرورگرهای مدرن این را میبینند */ @supports (container-type: inline-size) { .card-container { container-type: inline-size; } @container (min-width: 400px) { .card { display: flex; } } }
پروژه عملی: ساخت داشبورد با کامپوننتهای مستقل (کامل)
/* تنظیمات پایه */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: system-ui, sans-serif; background: #f5f6fa; } /* چیدمان کلی صفحه با Media Queries */ .dashboard { display: grid; grid-template-columns: 260px 1fr; min-height: 100vh; } @media (max-width: 768px) { .dashboard { grid-template-columns: 1fr; } } /* سایدبار – از Container Queries استفاده میکند */ .sidebar { background: #2c3e50; color: white; container-type: inline-size; container-name: sidebar; } /* Main area */ .main { padding: 20px; container-type: inline-size; container-name: main; } /* ویجت آمار – خودش را با عرض والد تنظیم میکند */ .stats-widget { background: white; border-radius: 12px; padding: 20px; margin-bottom: 20px; container-type: inline-size; } .stats-grid { display: grid; gap: 15px; } @container stats-widget (min-width: 400px) { .stats-grid { grid-template-columns: repeat(2, 1fr); } } @container stats-widget (min-width: 600px) { .stats-grid { grid-template-columns: repeat(4, 1fr); } } /* منوی سایدبار – در عرض کم فقط آیکون */ @container sidebar (max-width: 200px) { .menu-item span { display: none; } .menu-item { justify-content: center; } } /* کارت محصول در main */ .product-card-container { container-type: inline-size; } .product-card { background: white; border-radius: 12px; overflow: hidden; display: flex; transition: all 0.3s; } @container product-card-container (max-width: 300px) { .product-card { flex-direction: column; } .product-image { height: 150px; } } @container product-card-container (min-width: 301px) { .product-card { flex-direction: row; } .product-image { width: 120px; } }
<div class="dashboard"> <aside class="sidebar"> <div class="menu-item">🏠 <span>خانه</span></div> <div class="menu-item">📊 <span>آمار</span></div> <div class="menu-item">⚙️ <span>تنظیمات</span></div> </aside> <main class="main"> <div class="stats-widget"> <div class="stats-grid"> <div class="stat-card">بازدید: ۱۲٬۰۰۰</div> <div class="stat-card">فروش: ۳۴۰</div> <div class="stat-card">کاربر: ۱٬۲۰۰</div> <div class="stat-card">امتیاز: ۴.۸</div> </div> </div> <div class="product-card-container"> <div class="product-card"> <div class="product-image">تصویر</div> <div class="product-info"> <h3>محصول عالی</h3> <p>توضیحات محصول...</p> </div> </div> </div> </main> </div>
جدول مرجع: کی از کدام استفاده کنیم؟
| سناریو | راهحل بهتر | دلیل |
|---|---|---|
| چیدمان کلی صفحه (هدر، فوتر، سایدبار) | Media Queries | وابسته به اندازه کل صفحه است |
| کامپوننتهای قابل استفاده مجدد (کارت، ویجت، دکمه) | Container Queries | مستقل از صفحه عمل میکنند |
| طراحی ریسپانسیو برای دستگاههای مختلف (موبایل/تب/دسکتاپ) | Media Queries | device-based design |
| کتابخانه کامپوننت (مثل کارت محصول در هر جای سایت) | Container Queries | کاملاً portable |
| تغییر فونت و spacing بر اساس عرض صفحه | Media Queries | تجربه خوانایی بهتر |
| تغییر layout یک ویجت در سایدبار vs main | Container Queries | تنها راه حل صحیح |
| پشتیبانی از مرورگرهای قدیمی (قبل از ۲۰۲۳) | Media Queries | پشتیبانی کامل |
| پروژههای جدید با هدف آینده | هر دو با هم | قدرت ترکیبی |
11. ویژگیها و بخشهای مختلف
-
✅ مقایسه کامل Media vs Container Queries
-
✅ ۱۵+ مثال کاربردی با کدهای آماده
-
✅ پروژه عملی (داشبورد با کامپوننتهای مستقل)
-
✅ جدول مرجع برای انتخاب درست
-
✅ پشتیبانی از fallback برای مرورگرهای قدیمی
-
✅ نامگذاری کانتینر (container-name) برای پروژههای بزرگ
-
✅ کانتینرهای تو در تو (Nested Containers)
-
✅ کدهای کاملاً قابل کپی و اجرا
۱۴. بخش تمرین عملی (چالش نهایی)
💡 چالش نهایی (پروژه محور):
یک صفحه فروشگاهی کامل بسازید که شامل:
چیدمان کلی صفحه با Media Queries (موبایل: ۱ ستون، تبلت: ۲ ستون، دسکتاپ: سایدبار + main)
کامپوننت کارت محصول با Container Queries که در ۳ حالت مختلف ظاهر شود:
عرض کمتر از ۲۰۰px (فقط تصویر)
عرض بین ۲۰۰ تا ۳۵۰px (تصویر + عنوان)
عرض بیشتر از ۳۵۰px (تصویر + عنوان + قیمت + دکمه)
- ویجت سبد خرید در سایدبار که در عرض کم (موبایل) به صورت افقی و در عرض زیاد عمودی شود
- سرچ بار هوشمند که در عرض کم فقط آیکون و در عرض زیاد ورودی کامل نشان دهد
- فوتر با ۳ ستون که در موبایل عمودی و در دسکتاپ افقی شود (با Media Queries)
کدهای خود را در بخش نظرات به اشتراک بگذارید. بهترین پروژهها را در مقاله بعدی معرفی میکنیم.
کلمات کلیدی:
Container Queries,Media Queries,طراحی ریسپانسیو,CSS مدرن,responsive design,container-type,container query vs media query
نظرات (0)