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

فصل ۲ از ۸

پیشرفت ترم
۰٪

ترم ۴ · Responsive

media query

فصل ۲پیش‌نمایش رایگان
۹ دقیقه مطالعه فصل ۲

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

آخر این فصل یک گالری از کارت‌ها داری که چیدمانش را با عرضِ صفحه عوض می‌کند: روی موبایلِ باریک یک ستون، و روی صفحهٔ پهن سه ستون. فرقِ این فصل با فصل قبل مهم است — آنجا صفحه فقط جمع و باز می‌شد، اینجا واقعاً چیدمان عوض می‌شود. ابزارش یک قاعدهٔ تازه است به اسم media query: راهی که به CSS بگویی «این استایل‌ها فقط وقتی اجرا شوند که عرضِ صفحه از فلان مقدار بیشتر باشد».

یک گالریِ کارت که با عرضِ صفحه چیدمانش عوض می‌شود: روی نمایشِ باریک یک ستونِ عمودی، و روی نمایشِ پهن سه ستونِ کنارِ هم، با یک خطِ آستانه که مرزِ تغییر را نشان می‌دهد

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

  • یک @media بنویسی که فقط در عرض‌های مشخص اجرا شود
  • بگویی breakpoint چیست و کجای طرح باید گذاشته شود
  • فرقِ min-width و max-width را بگویی و درست را انتخاب کنی
  • یک چیدمان را mobile-first بنویسی، از یک ستون به سه ستون

قبل از شروع#

  • از فصل ۱ (همین ترم): meta viewport و mobile-first — این فصل مستقیم روی همان‌ها سوار است.
  • از ترم ۳: display: grid، grid-template-columns و واحد fr — گالری را با همین می‌سازیم.
  • از ترم ۳: gap — فاصلهٔ بین کارت‌ها.

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

۱. media query یعنی چه#

تا اینجا هر قاعدهٔ CSS ای که نوشتی همیشه اجرا می‌شد. media query یک شرط دور یک دسته قاعده می‌گذارد: «این‌ها را فقط وقتی اعمال کن که یک چیزی دربارهٔ صفحه درست باشد» — معمولاً یک چیز دربارهٔ عرضِ صفحه. با آن می‌توانی به مرورگر بگویی «روی صفحه‌های پهن این‌طور بچین، روی باریک آن‌طور».

شکلش این است: کلمهٔ @media، بعد شرط داخل پرانتز، بعد یک { } که قاعده‌های معمولی داخلش می‌روند:

@media (min-width: 700px) {
  /* har CSS injaa faghat rooye arze 700px va bishtar ejraa mishavad */
}

(min-width: 700px) یعنی «اگر عرضِ صفحه حداقل ۷۰۰ پیکسل است». هر قاعده‌ای که داخلِ آن { } بگذاری، فقط روی صفحه‌های ۷۰۰ پیکسل و پهن‌تر اجرا می‌شود؛ روی باریک‌تر انگار اصلاً نوشته نشده. بیرونِ @media قاعده‌های همیشگی می‌مانند — پایهٔ کار.

۲. اولین @media: از یک ستون به سه ستون#

بیا گالری را بسازیم. اول HTML: یک <main> با شش کارت. <article> را برای کارت به‌کار می‌بریم چون هر کارت یک تکهٔ مستقل است، همان‌طور که در ترم ۱ یاد گرفتی:

<main class="grid">
  <article class="card">یک</article>
  <article class="card">دو</article>
  <article class="card">سه</article>
  <article class="card">چهار</article>
  <article class="card">پنج</article>
  <article class="card">شش</article>
</main>

حالا استایلِ پایه. چون mobile-first کار می‌کنیم، حالتِ پیش‌فرض همان حالتِ موبایل است: یک ستون. این قاعده‌ها بیرونِ هر @media می‌مانند تا همیشه اجرا شوند:

.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

.card {
  background-color: #2a6b93;
  color: #ffffff;
  padding: 24px;
  border-radius: 8px;
  text-align: center;
}

چک کن: شش کارتِ آبی در یک ستونِ عمودی می‌بینی، زیرِ هم. این حالتِ موبایل است و باید ساده و بی‌عیب باشد. حالا امکانِ «صفحهٔ پهن» را رویش سوار می‌کنیم.

یک @media اضافه کن که فقط روی عرضِ پهن، ستون‌ها را سه‌تا کند:

@media (min-width: 700px) {
  .grid {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

چک کن: حالا عرضِ پیش‌نمایش را آرام پهن کن. تا وقتی باریک است یک ستون می‌ماند؛ لحظه‌ای که از ۷۰۰ پیکسل رد شد، ناگهان سه ستون می‌شود. باریکش کن، دوباره یک ستون. همین جهش، قلبِ media query است.

💡 نکته: داخلِ یک @media هر تعداد قاعده که بخواهی می‌گذاری، نه فقط یکی. سرِ یک breakpoint معمولاً چند چیز با هم عوض می‌شوند — مثلاً هم ستون‌ها بیشتر می‌شوند، هم gap بازتر، هم فونتِ تیتر کمی بزرگ‌تر. همه را کنارِ هم داخلِ همان یک @media (min-width: 700px) بنویس؛ لازم نیست برای هر property یک query جدا بسازی.

۳. breakpoint چیست#

آن عددِ ۷۰۰ که چیدمان سرِ آن عوض شد، یک اسم دارد: breakpoint. یعنی «نقطهٔ شکست» — عرضی که در آن، طرحِ صفحه از یک حالت به حالتِ دیگر می‌رود. هر سایتی چند breakpoint دارد؛ جاهایی که تصمیم می‌گیری چیدمان عوض شود.

breakpoint را از کجا انتخاب کنیم؟ بهترین راهنما خودِ محتواست، نه اندازهٔ یک گوشیِ خاص. عرضِ پیش‌نمایش را آرام پهن کن و ببین کجا چیدمانت شروع به بدشکل‌شدن می‌کند — مثلاً کارت‌ها آن‌قدر پهن می‌شوند که زشت‌اند، یا متن خیلی کش می‌آید. همان‌جا یک breakpoint بگذار. عددهایی مثل ۶۰۰، ۷۰۰ و ۹۰۰ نقطه‌های شروعِ رایج‌اند، ولی قانونِ آسمانی نیستند.

💡 نکته: breakpoint را با عددِ ثابتِ گوشیِ امروز گره نزن؛ گوشی‌ها هر سال عوض می‌شوند. به‌جای «این دقیقاً عرضِ فلان موبایل است» فکر کن «اینجا چیدمانم بد می‌شود، پس اینجا عوضش می‌کنم». این‌طوری طرحت با هر دستگاهِ آینده هم جور درمی‌آید.

قبل از ادامه، جواب بده: اگر یک قاعده را داخلِ @media (min-width: 700px) بگذاری، روی یک موبایلِ ۳۶۰ پیکسلی اجرا می‌شود؟ (نه — چون ۳۶۰ کمتر از ۷۰۰ است، شرط برقرار نیست.)

۴. min-width در برابر max-width#

دو جهت برای شرط داری:

  • (min-width: 700px) یعنی «عرض حداقل ۷۰۰» — از ۷۰۰ به بالا. این جهتِ mobile-first است: پایه را برای موبایل می‌نویسی، بعد با min-width امکاناتِ صفحهٔ بزرگ را اضافه می‌کنی.
  • (max-width: 700px) یعنی «عرض حداکثر ۷۰۰» — از ۷۰۰ به پایین. این جهتِ desktop-first است: پایه را برای دسکتاپ می‌نویسی، بعد برای صفحهٔ کوچک چیزها را پس می‌گیری.

هر دو کار می‌کنند، ولی در تاروپود mobile-first را انتخاب می‌کنیم، پس min-width ابزارِ اصلیِ توست. دلیلش همان است که فصل قبل گفتیم: از ساده به پیچیده رفتن مطمئن‌تر است. با min-width، پایه‌ات ساده‌ترین حالت است و هر @media فقط چیزی رویش می‌گذارد.

یک محورِ افقیِ عرض با یک نقطهٔ breakpoint در وسط: بازهٔ سمتِ باریک با یک رنگ برای max-width و بازهٔ سمتِ پهن با رنگی دیگر برای min-width، تا نشان دهد هر جهت کدام طرفِ مرز را می‌پوشاند

۵. وقتی دو query دعوا می‌کنند#

حالا یک اشتباهِ رایج و آموزنده. فرض کن به‌جای mobile-first، بخواهی هر دو حالت را جدا با query بنویسی — یکی برای باریک، یکی برای پهن — و هر دو را روی همان عددِ ۷۰۰ بگذاری:

@media (max-width: 700px) {
  .grid { grid-template-columns: 1fr; }
}

@media (min-width: 700px) {
  .grid { grid-template-columns: 1fr 1fr 1fr; }
}

به‌نظر منطقی می‌آید: زیرِ ۷۰۰ یک ستون، بالای ۷۰۰ سه ستون. ولی عرضِ پیش‌نمایش را دقیقاً روی ۷۰۰ بگذار. یک مشکلِ ظریف هست: در دقیقاً ۷۰۰ پیکسل، هر دو شرط برقرارند — max-width: 700 یعنی «۷۰۰ یا کمتر» و min-width: 700 یعنی «۷۰۰ یا بیشتر»، و ۷۰۰ در هر دو می‌گنجد. پس هر دو قاعده اجرا می‌شوند و آن‌که در فایل پایین‌تر است برنده می‌شود. مرزِ دو query روی هم افتاده.

🔧 اگر کار نکرد: روی عددِ مرزی رفتارِ عجیب دیدی، یا مطمئن نیستی کدام قاعده برنده است؟ علتش همین هم‌پوشانیِ min-width: 700 و max-width: 700 روی یک عددِ یکسان است. راهِ درست این نیست که مرز را با اعشار جابه‌جا کنی؛ راهِ تمیز این است که اصلاً دو query نگذاری. mobile-first بنویس: پایه را یک‌ستونه بگذار (بی‌هیچ query) و فقط یک @media (min-width: 700px) برای سه‌ستونه اضافه کن. حالا هیچ دو شرطی نیست که سرِ مرز دعوا کنند — و همان کدِ بخش ۲ است.

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

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

<!-- index.html -->
<!DOCTYPE html>
<html lang="fa" dir="rtl">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>چیدمان responsive</title>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <main class="grid">
      <article class="card">یک</article>
      <article class="card">دو</article>
      <article class="card">سه</article>
      <article class="card">چهار</article>
      <article class="card">پنج</article>
      <article class="card">شش</article>
    </main>
  </body>
</html>

و styles.css — دقت کن که فقط یک @media با min-width داریم، دقیقاً همان راهِ تمیزِ mobile-first:

/* styles.css */
* {
  box-sizing: border-box;
}

body {
  background-color: #f6edda;
  margin: 0;
  padding: 16px;
}

.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

.card {
  background-color: #2a6b93;
  color: #ffffff;
  padding: 24px;
  border-radius: 8px;
  text-align: center;
}

@media (min-width: 700px) {
  .grid {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

چک کن: روی صفحه شش کارتِ آبی می‌بینی که روی باریک یک‌ستونه و روی پهن سه‌ستونه‌اند. عرضِ پیش‌نمایش را از باریک تا پهن بکش و لحظهٔ جهش روی ۷۰۰ را ببین.

🤖 با AI: از دستیار AI ات بپرس «یک media query بنویس که این گالری روی صفحهٔ متوسط دو ستون و روی صفحهٔ پهن سه ستون شود». جوابش را خط‌به‌خط بخوان: چند تا @media گذاشته؟ min-width است یا max-width؟ آیا mobile-first است؟ بعد همان کد را در آزمایشگاه بگذار و عرض را بکش تا با چشمت ببینی سرِ مرزها درست جهش می‌کند یا نه — AI دربارهٔ layout با اطمینان اشتباه می‌گوید.

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

کلمه تلفظ به حروف فارسی یعنی چه
media query مدیا کوئری شرطی که یک دسته قاعدهٔ CSS را فقط در وضعیتِ مشخصی از صفحه اجرا می‌کند
@media اَت-مدیا کلمه‌ای که یک media query را شروع می‌کند
breakpoint بریک‌پوینت عرضی که در آن چیدمانِ صفحه از یک حالت به حالتِ دیگر می‌رود
min-width مین-ویدث شرطِ «عرض حداقل این‌قدر»؛ جهتِ mobile-first
max-width مکس-ویدث شرطِ «عرض حداکثر این‌قدر»؛ جهتِ desktop-first

تمرین‌ها

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

در فصل بعد#

الان می‌توانی چیدمانِ صفحه را با عرض عوض کنی. ولی یک چیزِ مهم هنوز جا مانده: تصویرها. یک عکس به‌طور پیش‌فرض به media query گوش نمی‌دهد و می‌تواند از جعبه‌اش بیرون بزند یا بدشکل شود. فصل بعد سراغِ همین می‌رویم: با max-width: 100%، object-fit و srcset یاد می‌گیری تصویرها را هم مثل بقیهٔ صفحه responsive کنی.

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

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