Media Query در CSS
بهنام نوبخت · ۱۴۰۵/۶/۲۸
در مقاله قبل با مفهوم Responsive Design آشنا شدیم و دیدیم که یک وبسایت باید بتواند خودش را با اندازههای مختلف صفحه تطبیق دهد. برای رسیدن به این هدف، CSS ابزارهای مختلفی مانند Flexbox، Grid، واحدهای نسبی، clamp() و minmax() را در اختیار ما قرار میدهد.
اما گاهی Layout به تغییرات مشخصی نیاز دارد؛ مثلاً در دسکتاپ منوی کامل نمایش داده شود، در موبایل فقط یک دکمه منو دیده شود، یا یک بخش که در دسکتاپ دو ستون دارد در موبایل به یک ستون تبدیل شود.
اینجاست که Media Query وارد میشود.
Media Query به CSS اجازه میدهد بر اساس شرایط محیط نمایش، مجموعه خاصی از قوانین CSS را اعمال کند. این شرایط میتوانند شامل عرض و ارتفاع Viewport، جهت نمایش، قابلیت Hover، نوع ورودی کاربر، ترجیح کاربر برای کاهش حرکت و موارد دیگر باشند.
در این مقاله یاد میگیریم:
Media Query چیست؟
ساختار
@mediaچگونه است؟min-widthوmax-widthچه تفاوتی دارند؟چگونه Breakpoint انتخاب کنیم؟
Mobile First چیست؟
چگونه چند شرط را با هم ترکیب کنیم؟
orientationچیست؟hoverوpointerچه کاربردی دارند؟چگونه Media Query را برای Accessibility استفاده کنیم؟
Syntax جدید Range Query چیست؟
چگونه Media Query را در یک پروژه واقعی به کار ببریم؟
Media Query چیست؟
Media Query روشی برای اعمال شرطی قوانین CSS است.
به زبان ساده میتوانیم به مرورگر بگوییم:
اگر صفحه از یک اندازه کوچکتر بود، این CSS را اجرا کن.
یا:
اگر صفحه از یک اندازه بزرگتر بود، Layout را تغییر بده.
ساختار پایه:
@media (condition) {
/* CSS */
}مثلاً:
@media (max-width: 768px) {
body {
background: #f5f5f5;
}
}یعنی اگر عرض Viewport حداکثر 768px باشد، رنگ پسزمینه تغییر کند.
Media Query یکی از ابزارهای اصلی Responsive Design است، اما Responsive Design فقط به Media Query محدود نمیشود؛ Layoutهای مدرن مانند Grid و Flexbox و واحدهای انعطافپذیر نیز میتوانند بدون Media Query بخش زیادی از رفتار Responsive را ایجاد کنند.
ساختار media@
ساختار کلاسیک Media Query به صورت زیر است:
@media media-type and (media-feature) {
selector {
property: value;
}
}مثلاً:
@media screen and (max-width: 768px) {
.container {
padding-inline: 16px;
}
}در اینجا سه بخش داریم:
@media
↓
media type
↓
media feature
↓
CSS rulesMedia Type چیست؟
Media Query میتواند نوع Media را نیز مشخص کند.
رایجترین انواع:
all
screen
printمثلاً:
@media screen {
body {
font-family: sans-serif;
}
}یا برای چاپ:
@media print {
.navigation {
display: none;
}
}در حالت چاپ، منوی سایت دیگر کاربردی ندارد، بنابراین میتوانیم آن را مخفی کنیم.
Media Type اختیاری است؛ اگر آن را مشخص نکنیم، Media Query به صورت پیشفرض برای همه Mediaهای مناسب اعمال میشود.
مهمترین Media Feature: width
یکی از پرکاربردترین Media Featureها width است.
این ویژگی عرض Viewport را بررسی میکند.
مثلاً:
@media (width: 600px) {
body {
background: red;
}
}یعنی فقط وقتی عرض Viewport دقیقاً 600px باشد.
اما در طراحی Responsive معمولاً بررسی یک بازه کاربردیتر است.
max-width
با max-width میتوانیم بگوییم:
اگر عرض Viewport کمتر یا مساوی مقدار مشخصی بود، این CSS را اعمال کن.
مثلاً:
@media (max-width: 768px) {
.navigation {
display: none;
}
}در این مثال وقتی عرض صفحه 768px یا کمتر باشد، Navigation مخفی میشود.
min-width
min-width برعکس max-width عمل میکند.
یعنی:
اگر عرض Viewport حداقل مقدار مشخصی داشت، این CSS را اعمال کن.
مثلاً:
@media (min-width: 768px) {
.navigation {
display: flex;
}
}یعنی از 768px به بالا Navigation به صورت Flex نمایش داده شود.
تفاوت min-width و max-width
به این دو مثال دقت کنید.
max-width
@media (max-width: 768px) {
.card {
width: 100%;
}
}یعنی:
0px ─────────────── 768px
فعالmin-width
@media (min-width: 768px) {
.card {
width: 50%;
}
}یعنی:
768px ───────────────────→
فعالMobile First با Media Query
یکی از بهترین روشها برای استفاده از Media Query، رویکرد Mobile First است.
در این روش ابتدا CSS پایه را برای صفحات کوچک مینویسیم و سپس برای Viewportهای بزرگتر، قابلیتهای بیشتری اضافه میکنیم.
مثلاً:
.services {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
}این حالت پایه برای موبایل است.
سپس:
@media (min-width: 768px) {
.services {
grid-template-columns: repeat(2, 1fr);
}
}و در صفحههای بزرگتر:
@media (min-width: 1100px) {
.services {
grid-template-columns: repeat(4, 1fr);
}
}نتیجه:
Mobile
┌─────────┐
│ Card 1 │
├─────────┤
│ Card 2 │
├─────────┤
│ Card 3 │
├─────────┤
│ Card 4 │
└─────────┘
Tablet
┌───────┬───────┐
│ Card1 │ Card2 │
├───────┼───────┤
│ Card3 │ Card4 │
└───────┴───────┘
Desktop
┌──────┬──────┬──────┬──────┐
│ 1 │ 2 │ 3 │ 4 │
└──────┴──────┴──────┴──────┘این الگوی Mobile First با توصیههای فعلی MDN نیز همراستا است: ابتدا سبک پایه برای صفحههای باریک و سپس Media Queryهای min-width برای عرضهای بزرگتر.
Breakpoint چیست؟
Breakpoint نقطهای است که Layout در آن تغییر میکند.
مثلاً:
Mobile
0 ───────── 767px
Tablet
768 ─────── 1099px
Desktop
1100px ───────────→اما یک نکته بسیار مهم:
Breakpoint را نباید فقط بر اساس مدل موبایل، تبلت یا لپتاپ انتخاب کنیم.
بهتر است ابتدا Layout را بسازیم و ببینیم در چه عرضی محتوا شروع به خراب شدن میکند.
مثلاً فرض کنید Navigation در این حالت مشکل پیدا میکند:
900px
↓
Logo + 6 menu items
↓
فضای کافی وجود نداردپس میتوانیم Breakpoint را نزدیک همان محدوده قرار دهیم.
MDN نیز توصیه میکند Breakpointها بر اساس نیاز Layout و محتوا انتخاب شوند، نه بر اساس دستگاههای خاص.
Breakpointهای رایج
در پروژهها ممکن است مقادیری مانند این ببینید:
@media (min-width: 640px) { }
@media (min-width: 768px) { }
@media (min-width: 1024px) { }
@media (min-width: 1280px) { }اما این اعداد قانون جهانی نیستند.
نباید تصور کنید:
640 = موبایل
768 = تبلت
1024 = لپتاپ
1280 = دسکتاپاین دستهبندی همیشه درست نیست.
ممکن است پروژه شما در 850px به Breakpoint نیاز داشته باشد یا اصلاً به Breakpoint در آن محدوده نیاز نداشته باشد.
استفاده از واحدهای نسبی در Breakpoint
در پروژههای حرفهای میتوان از واحدهایی مانند rem برای Breakpointها نیز استفاده کرد.
مثلاً:
@media (min-width: 48rem) {
.services {
grid-template-columns: repeat(2, 1fr);
}
}و:
@media (min-width: 64rem) {
.services {
grid-template-columns: repeat(4, 1fr);
}
}استفاده از واحدهای نسبی برای Breakpointها میتواند از وابستگی به یک اندازه مطلق خاص جلوگیری کند. MDN نیز استفاده از واحدهای نسبی را در تعریف Breakpointها توصیه میکند.
چند Media Query پشت سر هم
میتوانیم چند Media Query در یک فایل داشته باشیم:
body {
font-size: 16px;
}
@media (min-width: 768px) {
body {
font-size: 17px;
}
}
@media (min-width: 1100px) {
body {
font-size: 18px;
}
}در اینجا:
Mobile
16px
Tablet
17px
Desktop
18pxاین روش در Mobile First بسیار کاربردی است.
Media Query با چند شرط
میتوانیم چند شرط را با and ترکیب کنیم.
مثلاً:
@media (min-width: 768px) and (max-width: 1200px) {
.container {
max-width: 960px;
}
}یعنی CSS زمانی اعمال شود که عرض بین این دو مقدار قرار داشته باشد.
Syntax مدرن Range
CSS مدرن Syntax خواناتری برای Range Query ارائه میکند.
به جای:
@media (min-width: 768px) and (max-width: 1200px) {
/* CSS */
}میتوان نوشت:
@media (768px <= width <= 1200px) {
/* CSS */
}هر دو روش مفهوم یکسانی دارند. Syntax جدید Range کوتاهتر و در بعضی موارد خواناتر است.
مثال:
@media (width >= 768px) {
.services {
grid-template-columns: repeat(2, 1fr);
}
}و:
@media (width < 768px) {
.services {
grid-template-columns: 1fr;
}
}آیا باید همیشه از Syntax جدید استفاده کنیم؟
خیر.
هر دو Syntax در پروژههای مدرن کاربرد دارند:
@media (min-width: 768px) {
}و:
@media (width >= 768px) {
}اگر در پروژهای Syntax قدیمیتر استفاده شده، لازم نیست صرفاً برای مدرنسازی همه فایلها را تغییر دهید.
مهمتر از Syntax، ساختار صحیح Breakpointها و خوانایی کد است.
ترکیب Media Query با and
مثلاً:
@media screen and (width >= 768px) {
.hero {
display: grid;
}
}یعنی:
Media باید
screenباشد.عرض Viewport حداقل
768pxباشد.
هر دو شرط باید برقرار باشند.
استفاده از or
میتوانیم چند حالت جایگزین داشته باشیم.
در Syntax کلاسیک معمولاً از کاما استفاده میشود:
@media (max-width: 600px), (orientation: portrait) {
.hero {
padding-block: 48px;
}
}یعنی اگر یکی از شرایط برقرار باشد، CSS اعمال میشود.
Orientation چیست؟
Media Feature دیگری که میتواند مفید باشد orientation است.
دو مقدار اصلی:
portrait
landscapeportrait یعنی Viewport ارتفاع بیشتری نسبت به عرض دارد و landscape یعنی عرض بیشتر از ارتفاع است.
مثلاً:
@media (orientation: landscape) {
.hero {
grid-template-columns: 1fr 1fr;
}
}و:
@media (orientation: portrait) {
.hero {
grid-template-columns: 1fr;
}
}یک نکته مهم
orientation الزاماً به معنای وضعیت فیزیکی دستگاه نیست؛ این Feature بر اساس نسبت عرض و ارتفاع Viewport ارزیابی میشود. مثلاً باز شدن Keyboard موبایل میتواند روی ابعاد Viewport تأثیر بگذارد.
استفاده از hover
همه دستگاهها قابلیت Hover واقعی ندارند.
مثلاً ماوس معمولاً میتواند روی یک عنصر قرار بگیرد، اما صفحه لمسی رفتار متفاوتی دارد.
میتوانیم این موضوع را بررسی کنیم:
@media (hover: hover) {
.service-card:hover {
transform: translateY(-8px);
}
}یعنی افکت Hover را فقط در محیطی فعال کنیم که Hover به شکل مناسب پشتیبانی میشود.
این موضوع برای طراحی سایتهای لمسی بسیار مهم است.
pointer چیست؟
Media Feature دیگری به نام pointer وجود دارد که درباره دقت ابزار اشارهگر اصلی کاربر اطلاعات میدهد.
مقادیر مهم:
none
coarse
fineمثلاً coarse میتواند به یک ورودی کمدقت مانند لمس انگشت روی صفحه اشاره کند.
مثلاً:
@media (pointer: coarse) {
.button {
min-height: 48px;
padding-inline: 24px;
}
}میتوانیم برای محیطهای لمسی فضای بیشتری برای کنترلها در نظر بگیریم.
hover و pointer را با هم استفاده کنیم
مثلاً:
@media (hover: hover) and (pointer: fine) {
.service-card:hover {
transform: translateY(-6px);
}
}این الگو میتواند برای افکتهای Hover مناسب باشد؛ زیرا به جای فرض اینکه همه کاربران ماوس دارند، شرایط ورودی را بررسی میکنیم.
Media Query برای Print
Media Query فقط برای Responsive Design نیست.
مثلاً:
@media print {
.header,
.footer,
.navigation,
.print-button {
display: none;
}
}در هنگام چاپ، بخشهای غیرضروری حذف میشوند.
این قابلیت برای:
فاکتورها
گزارشها
صفحات آموزشی
رزومه
مقالات
میتواند کاربردی باشد.
Media Query و Accessibility
Media Query میتواند در دسترسپذیری نیز نقش داشته باشد.
یکی از نمونههای مهم:
prefers-reduced-motionاین Feature بررسی میکند آیا کاربر در سیستم خود ترجیح داده است حرکتها و انیمیشنهای غیرضروری کاهش پیدا کنند یا خیر.
مثلاً:
.card {
transition: transform 0.3s ease;
}
.card:hover {
transform: translateY(-8px);
}
@media (prefers-reduced-motion: reduce) {
.card {
transition: none;
}
}این کار باعث میشود در صورت درخواست کاربر، حرکتهای غیرضروری کاهش پیدا کنند.
ساختار حرفهای برای پروژه
فرض کنید پروژه ما چنین ساختاری دارد:
styles/
│
├── base.css
├── layout.css
├── components.css
└── responsive.cssمیتوانیم Media Queryهای مربوط به Layout را در فایل مربوط به همان Component یا Layout نگه داریم.
مثلاً:
/* Header */
.header {
display: flex;
}
/* Mobile */
@media (width < 768px) {
.header {
flex-direction: column;
}
}لازم نیست تمام Media Queryها را حتماً در یک فایل جداگانه قرار دهیم.
در پروژههای بزرگ، محل قرارگیری Media Query باید بر اساس معماری CSS پروژه انتخاب شود.
پروژه عملی: Responsive Header
یک Header برای سایت بنو سرویس ایجاد کنیم.
HTML
<header class="site-header">
<div class="container">
<nav class="navbar">
<a href="#" class="logo">
بنو سرویس
</a>
<div class="nav-links">
<a href="#">خانه</a>
<a href="#">خدمات</a>
<a href="#">محصولات</a>
<a href="#">آموزش</a>
<a href="#">درباره ما</a>
<a href="#">تماس با ما</a>
</div>
<button class="menu-button">
☰
</button>
</nav>
</div>
</header>
CSS پایه
.site-header {
width: 100%;
}
.container {
width: min(100% - 32px, 1200px);
margin-inline: auto;
}
.navbar {
min-height: 72px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
}
.nav-links {
display: flex;
align-items: center;
gap: 24px;
}
.menu-button {
display: none;
}در موبایل:
@media (width < 768px) {
.nav-links {
display: none;
}
.menu-button {
display: inline-flex;
}
}حالا ساختار در دسکتاپ:
Logo
خانه
خدمات
محصولات
آموزش
درباره
تماسو در موبایل:
Logo ☰پروژه عملی: کارتهای خدمات
HTML:
<section class="services">
<article class="service-card">
<h3>طراحی سایت</h3>
<p>
طراحی وبسایتهای مدرن و حرفهای.
</p>
</article>
<article class="service-card">
<h3>فروشگاه ساز</h3>
<p>
ساخت فروشگاه اینترنتی حرفهای.
</p>
</article>
<article class="service-card">
<h3>سئو</h3>
<p>
بهینهسازی سایت برای موتورهای جستجو.
</p>
</article>
<article class="service-card">
<h3>ربات تلگرامی</h3>
<p>
طراحی رباتهای اختصاصی تلگرام.
</p>
</article>
</section>CSS پایه:
.services {
display: grid;
grid-template-columns: 1fr;
gap: 20px;
}
.service-card {
padding: 24px;
border-radius: 20px;
}Tablet:
@media (width >= 768px) {
.services {
grid-template-columns: repeat(2, 1fr);
}
}Desktop:
@media (width >= 1100px) {
.services {
grid-template-columns: repeat(4, 1fr);
}
}این مثال یک ساختار واضح Mobile First ایجاد میکند.
یک نکته مهم: آیا همیشه به Media Query نیاز داریم؟
خیر.
فرض کنید میخواهیم چهار کارت Responsive داشته باشیم.
ممکن است بنویسیم:
.services {
display: grid;
grid-template-columns:
repeat(auto-fit, minmax(240px, 1fr));
gap: 24px;
}در بسیاری از موارد دیگر نیازی نیست بنویسیم:
@media (...) { ... }زیرا Grid خودش بر اساس فضای موجود Layout را تنظیم میکند.
MDN نیز تأکید میکند که Media Query برای Responsive Design مفید است، اما الزاماً برای هر بخش Responsive لازم نیست.
اشتباه رایج: Media Query برای هر تغییر کوچک
فرض کنید:
@media (width < 1200px) { ... }
@media (width < 1100px) { ... }
@media (width < 1000px) { ... }
@media (width < 900px) { ... }
@media (width < 800px) { ... }
@media (width < 700px) { ... }
@media (width < 600px) { ... }
@media (width < 500px) { ... }این ساختار میتواند CSS را بسیار پیچیده کند.
به جای آن ابتدا بررسی کنید آیا میتوانید مشکل را با موارد زیر حل کنید:
Grid
Flexbox
minmax()
clamp()
min()
max()
درصدها
واحدهای نسبیو تنها زمانی Media Query اضافه کنید که واقعاً نیاز دارید Layout یا رفتار Component تغییر کند.
اشتباه رایج: وابستگی به نام دستگاه
این کد از نظر مفهومی مناسب نیست:
/* iPhone */
@media (...) { }
/* Samsung */
@media (...) { }
/* iPad */
@media (...) { }چون هدف ما طراحی برای دستگاه خاص نیست.
هدف:
عرض کم
↓
Layout A
عرض متوسط
↓
Layout B
عرض زیاد
↓
Layout Cاست.
اشتباه رایج: نادیده گرفتن ترتیب CSS
به ترتیب زیر دقت کنید:
.title {
font-size: 32px;
}
@media (width >= 768px) {
.title {
font-size: 48px;
}
}در شرایط مناسب، قانون داخل Media Query مقدار قبلی را Override میکند.
اما اگر ترتیب یا Specificity را اشتباه مدیریت کنیم، ممکن است نتیجه مورد انتظار را نبینیم.
پس هنگام Debug کردن Media Query همیشه موارد زیر را بررسی کنید:
آیا Query واقعاً Match شده است؟
آیا Selector درست است؟
آیا قانون دیگری Specificity بیشتری دارد؟
آیا قانون دیگری بعد از آن آمده است؟
آیا CSS در فایل درست Load شده است؟
تست Media Query با DevTools
یکی از بهترین روشهای یادگیری Responsive Design، استفاده از DevTools مرورگر است.
در Chrome یا Edge:
F12
↓
Toggle Device Toolbarسپس میتوانید عرض Viewport را تغییر دهید:
390px
480px
768px
1024px
1440pxو ببینید Layout چگونه تغییر میکند.
اما بهتر است فقط چند اندازه ثابت را تست نکنید.
عرض را به صورت پیوسته تغییر دهید و ببینید در چه نقطهای Layout دچار مشکل میشود.
این کار به شما کمک میکند Breakpoint واقعی موردنیاز پروژه را پیدا کنید.
تمرینهای عملی
تمرین ۱ — تغییر رنگ
یک صفحه بسازید که:
در موبایل پسزمینه سفید باشد.
در Tablet خاکستری باشد.
در Desktop مشکی باشد.
از سه Media Query استفاده کنید.
تمرین ۲ — Responsive Typography
یک عنوان ایجاد کنید:
<h1>بنو سرویس</h1>سپس:
Mobile → 32px
Tablet → 44px
Desktop → 64pxرا با Media Query پیادهسازی کنید.
سپس همان تمرین را یک بار با clamp() انجام دهید و تفاوت را بررسی کنید.
تمرین ۳ — Navigation
یک Navigation بسازید که:
Mobile
Logo ☰Tablet
Logo خانه | خدمات | ☰Desktop
Logo | خانه | خدمات | محصولات | آموزش | تماسبرای هر حالت Layout مناسب ایجاد کنید.
تمرین ۴ — کارت خدمات
چهار کارت خدمات بسازید:
Mobile
1
2
3
4Tablet
1 | 2
3 | 4Desktop
1 | 2 | 3 | 4سپس دو نسخه بسازید:
نسخه اول: با Media Query
نسخه دوم: با auto-fit و minmax()
و بررسی کنید کدام نسخه CSS کمتری نیاز دارد.
جمعبندی
Media Query یکی از مهمترین ابزارهای CSS برای کنترل Responsive Layout است.
با آن میتوانیم CSS را بر اساس شرایط محیط نمایش تغییر دهیم؛ از عرض Viewport گرفته تا Orientation، قابلیت Hover، نوع Pointer و ترجیحات کاربر مانند کاهش حرکت.
مهمترین مفاهیمی که در این مقاله یاد گرفتیم عبارتاند از:
@mediamin-widthmax-widthorientationhoverpointerprefers-reduced-motionو همچنین Syntax مدرن:
@media (768px <= width <= 1200px) {
}اما یک نکته مهم را همیشه به خاطر داشته باشید:
Media Query ابزار Responsive Design است، نه خود Responsive Design.
اگر بتوانید بخشی از Layout را با Grid، Flexbox، minmax()، clamp() و واحدهای انعطافپذیر حل کنید، معمولاً نیازی نیست برای هر تغییر کوچک Media Query اضافه کنید.
هدف نهایی این نیست که تعداد زیادی Breakpoint بنویسیم؛ هدف این است که با کمترین پیچیدگی، Layoutی انعطافپذیر و قابل نگهداری ایجاد کنیم.
نظرات
هنوز نظری ثبت نشده است.