یادم می‌آید در یکی از اولین پروژه‌های فریلنسری‌ام، سایت را با وسواس در مرورگر دسکتاپ طراحی کردم، بعد فایل را برای مشتری فرستادم و همان شب پیام آمد که «روی گوشی به‌هم ریخته». عجیب بود؛ درست کار می‌کرد. بعدها فهمیدم که در DevTools مرورگرم، شبیه‌ساز موبایل باز مانده بود اما نه به‌اندازه‌ی صفحه‌ی واقعی. همان تجربه، سرآغاز یک مسیر طولانی در ریسپانسیو با CSS شد که در ده‌ها پروژه‌ی بعدی تکرار شد. حقیقتی که آن روز کشف کردم و امروز به‌عنوان قاعده‌ی کاری می‌شناسمش این است: ریسپانسیو یک قابلیت نیست، یک ذهنیت است.

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

چرا سایت شما در موبایل می‌شکند؟

وقتی سایت در موبایل به‌هم می‌ریزد، تقریباً همیشه یکی از سه دلیل پشتش است:

  • عرض ثابت: عنصر یا کل صفحه با width: 1200px یا مقداری ثابت طراحی شده و در عرض ۳۷۵ پیکسل، بیرون می‌زند. این یکی از رایج‌ترین خطاهایی است که در قالب‌های قدیمی وردپرسی زیاد می‌بینم.
  • نبود viewport: صفحه‌ی HTML فاقد تگ <meta name="viewport"> است. بدون آن، مرورگر موبایل فرض می‌کند عرض صفحه ۹۸۰ پیکسل است و همه‌چیز را در یک بوم کوچک زوم می‌کند؛ نتیجه، سایت ریز و غیرقابل‌استفاده است.
  • رفتار غلط در breakpointها: حتی اگر عنصر به‌درستی در موبایل بازچینش شود، اگر منطق طراحی از دسکتاپ به موبایل باشد (Top-Down)، به‌جای اینکه از موبایل به دسکتاپ باشد، معماری به هم می‌ریزد.

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

سایت جمع‌شونده، لباس گشاد در تن کوچک است؛ سایت ریسپانسیو، لباس دوخته‌شده. اولی دیده می‌شود، دومی پوشیده.

مدل ذهنی ریسپانسیو: سه مفهوم بنیادین

پیش از نوشتن یک خط CSS، این سه مفهوم باید درونی شوند:

۱. Viewport

ویوپورت ناحیه‌ی قابل‌مشاهده‌ی صفحه است. در دسکتاپ با عرض پنجره یکی است، در موبایل با عرض دستگاه مرتبط است اما نه دقیقاً. مرورگرهای موبایل به‌طور پیش‌فرض یک ویوپورت مجازی ۹۸۰ پیکسلی می‌سازند و بعد محتوا را در آن جای می‌دهند؛ به همین دلیل بدون تگ viewport، سایت‌ها روی موبایل ریز و غیرقابل‌خواندن نمایش داده می‌شوند.

۲. Breakpoint

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

۳. جریان محتوا

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

برای مطالعه‌ی این مفاهیم در سطح تکنیکال، اصول طراحی ریسپانسیو نقطه‌ی شروع مناسبی است.

تگ viewport و اولین جایی که همه اشتباه می‌کنند

بدون این تگ، بقیه‌ی کارهای ریسپانسیو تقریباً بی‌اثر است:

<meta name="viewport" content="width=device-width, initial-scale=1">

معنای این دو مقدار:

  • width=device-width — عرض ویوپورت را با عرض واقعی دستگاه هم‌تراز کن.
  • initial-scale=1 — بدون زوم اولیه، در مقیاس ۱ به ۱ نمایش بده.

اشتباهی که در پروژه‌های قدیمی دیده‌ام: اضافه کردن user-scalable=no برای جلوگیری از زوم دو‌انگشتی. این تصمیم، تجربه‌ی کاربری را در بعضی از کاربران (مثلاً افراد با ضعف بینایی) نابود می‌کند و امروز اکثر مرورگرها آن را نادیده می‌گیرند. اگر زوم روی سایت شما در بعضی قسمت‌ها آزاردهنده است، راه‌حل در تنظیمات CSS آن عنصر است، نه در بستن زوم کل صفحه.

نکته‌ی ظریف: در بعضی پروژه‌های وردپرسی، تگ viewport توسط قالب به‌طور خودکار درج می‌شود اما مقدارش ممکن است ناقص باشد. اگر می‌خواهید بدانید در قالب‌ها این تگ چطور مدیریت می‌شود، قالب وردپرس چیست و کدنویسی اختصاصی برای قالب وردپرس را ببینید.

Media Queries: از max-width تا Mobile-First

Media Queries ابزار اصلی برای تغییر چیدمان در نقاط مشخص است. سینتکس پایه:

@media (max-width: 768px) {
  .container {
    flex-direction: column;
  }
}

اما تفاوت بین رویکرد Top-Down (max-width) و Mobile-First (min-width) یک تصمیم معماری است، نه سلیقه:

رویکردسینتکسچه زمانی منطقی است
Top-Downmax-widthبازسازی قالب‌های قدیمی که از دسکتاپ شروع شده‌اند
Mobile-Firstmin-widthپروژه‌های جدید و سایت‌های مبتنی بر ترافیک موبایل
محدوده‌ایmin-width + max-widthوقتی رفتار در یک بازه‌ی مشخص مهم است

در پروژه‌های جدید، Mobile-First را به‌طور جدی توصیه می‌کنم. تجربه‌ام این است که در سایت‌هایی که با min-width طراحی شده‌اند، نگهداری ساده‌تر است چون استایل‌های پایه کوچک‌ترند و فقط در breakpointهای بالاتر، لایه‌های اضافه می‌شوند. برای مطالعه‌ی عمیق‌تر این رویکرد، طراحی موبایل اول چیست و مدیا کوئری در طراحی ریسپانسیو را در کنار این بخش بخوانید.

یک نکته‌ی ظریف که در پروژه‌ها به‌کارم آمده: در Media Queries، فقط چیدمان را تغییر دهید، نه محتوا. اگر با display: none محتوای متفاوتی برای موبایل و دسکتاپ نمایش می‌دهید، هم از نظر سئو آسیب می‌بینید و هم از نظر تجربه‌ی کاربری. اگر واقعاً به دو نسخه‌ی متفاوت نیاز دارید، راه‌حل در HTML و ساختار است، نه در پنهان‌کردن CSS.

واحدهای نسبی: از px به rem، vw و clamp

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

واحدهای مبتنی بر فونت ریشه

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

واحدهای مبتنی بر ویوپورت

vw و vh به درصدی از عرض و ارتفاع ویوپورت اشاره می‌کنند. کاربرد واقعی: هیرو سکشن تمام‌صفحه، یا عرض‌های نسبی. اما دام مهم: در موبایل، 100vh می‌تواند مشکل‌ساز شود چون نوار آدرس مرورگر بالای صفحه حساب می‌شود اما هنگام اسکرول کوچک می‌شود. راه‌حل مدرن: استفاده از dvh (dynamic viewport height) که در پروژه‌های جدید جایگزین vh شده است.

تابع clamp

یکی از تحولات واقعی CSS در سال‌های اخیر، تابع clamp() است:

h1 {
  font-size: clamp(1.5rem, 4vw, 3rem);
}

این یک خط، تیتر شما را در عرض ۳۲۰ پیکسل ۱.۵ رم و در عرض ۱۴۴۰ پیکسل ۳ رم نمایش می‌دهد، با درون‌یابی خودکار در بین. در پروژه‌هایی که از clamp استفاده کرده‌ام، تعداد media queryهای مربوط به تایپوگرافی تقریباً به صفر رسیده. برای الگوهای بیشتر، ترفندهای CSS برای طراحی سریع‌تر را ببینید.

ریسپانسیو بدون واحدهای نسبی، فقط چند media query تزئینی است که چیدمان را جابه‌جا می‌کنند اما جریان را نمی‌سازند.

تصاویر ریسپانسیو: srcset، picture و lazy loading

در بسیاری از سایت‌های وردپرسی که بررسی کرده‌ام، بزرگ‌ترین منبع کندی در موبایل، تصاویر بودند. اگر یک تصویر ۲۰۰۰ پیکسلی به موبایل ۳۷۵ پیکسلی بفرستید، کاربر شما چند مگابایت داده‌ی اضافه دانلود می‌کند که تأثیر مستقیمی روی LCP و نرخ پرش دارد. سه ابزار اصلی برای جلوگیری از این اتلاف:

srcset و sizes

<img
  src="image-800.jpg"
  srcset="image-400.jpg 400w,
          image-800.jpg 800w,
          image-1600.jpg 1600w"
  sizes="(max-width: 600px) 100vw, 50vw"
  alt="توضیح تصویر">

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

picture element

برای کنترل بیشتر، مثلاً وقتی می‌خواهید در موبایل نسخه‌ی برش‌خورده‌ی متفاوتی از تصویر نشان دهید، از <picture> استفاده کنید. این ابزار به شما کنترل کامل روی انتخاب منبع را می‌دهد.

lazy loading

تصاویر پایین‌تر از خط دید اولیه را با loading="lazy" علامت بزنید. اما در تصویر شاخص (LCP) هرگز از lazy استفاده نکنید؛ چون آن تصویر باید در سریع‌ترین زمان ممکن بارگذاری شود.

اگر در سایت وردپرسی هستید و می‌خواهید این تنظیمات را خودکار کنید، سئوی تصویر را بخوانید که در آن تمام لایه‌ها از alt تا srcset توضیح داده شده است. برای فشرده‌سازی و انتخاب فرمت درست، فشرده‌سازی تصاویر سایت و بهترین فرمت تصویر وب مسیر کاملی هستند.

چیدمان ریسپانسیو با Flexbox و Grid

دو ابزاری که امروز ستون فقرات چیدمان ریسپانسیو را می‌سازند. اگر این دو را درست بلد باشید، ۹۰٪ مشکلات چیدمان ریسپانسیو با چند خط حل می‌شوند:

Flexbox برای جریان یک‌بعدی

برای نوارهای ابزار، لیست‌های ساده، فرم‌های کوچک و هر چیزی که در یک محور جریان دارد، Flexbox انتخاب اول است. با flex-wrap و gap، بسیاری از بازچینش‌های موبایل بدون media query حل می‌شوند. جزئیات کامل در فلکس باکس در CSS آمده است.

Grid برای چیدمان دوبعدی و خودتنظیم

قوی‌ترین ابزار ریسپانسیو در CSS مدرن، ترکیب auto-fit و minmax است:

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

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

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

تایپوگرافی فارسی در موبایل

تایپوگرافی فارسی چالش‌های خاص خودش را دارد که در مقالات انگلیسی به آن پرداخته نمی‌شود:

  • فونت سنگین: فونت‌های فارسی با وزن‌های زیاد، حجم بزرگی دارند. در موبایل، فقط دو وزن (Regular و Bold) را با ساب‌ست فارسی محدود بارگذاری کنید.
  • ارتفاع خط: متن فارسی در موبایل به ارتفاع خط بیشتر از متن انگلیسی نیاز دارد. مقدار line-height: 1.7 در پروژه‌هایم نقطه‌ی شروع است.
  • اندازه فونت پایه: زیر ۱۶ پیکسل، متن فارسی در موبایل خسته‌کننده است. اگر می‌خواهید از rem استفاده کنید، مطمئن شوید فونت ریشه کمتر از ۱۶ پیکسل نباشد.
  • نیم‌فاصله در شکستن خطوط: فونت‌هایی که نیم‌فاصله را به‌درستی رندر نمی‌کنند، باعث شکستن عجیب کلمات در موبایل می‌شوند. هنگام انتخاب فونت، این را در عرض ۳۲۰ پیکسل تست کنید.

برای انتخاب فونت مناسب، بهترین فونت‌های فارسی برای وب و اصول کلی در اصول تایپوگرافی در طراحی وب آمده است. اگر در قالب وردپرسی هستید و می‌خواهید فونت را ریسپانسیو کنید، آماده‌سازی قالب برای فارسی و تفاوت قالب فارسی و انگلیسی را از دست ندهید.

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

سه الگویی که در پروژه‌ها بیشترین اثر را داشته‌اند:

  1. هدر ریسپانسیو: در دسکتاپ منو افقی، در موبایل منوی همبرگری. الگوی کلاسیک اما همیشه چالش‌برانگیز. راه‌حل تمیز من: یک markup، دو حالت با CSS. اگر منو در موبایل با کلاس‌های متفاوت در HTML ساخته شود، پیچیدگی نگهداری دو برابر می‌شود.
  2. کارت‌های محصول: در دسکتاپ چهار کارت در ردیف، در تبلت دو، در موبایل یک. ترکیب auto-fit و minmax این کار را با یک خط انجام می‌دهد. اگر روی قالب مناسب ووکامرس کار می‌کنید، این الگو را جدی بگیرید.
  3. فرم تماس: در دسکتاپ دو ستونه، در موبایل یک‌ستونه. با Grid و grid-column: 1 / -1 برای فیلدهای عرض‌کامل، فرم بدون مشکل بازچینش می‌شود.

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

  • فراموش کردن overflow-x: اگر یک عنصر از عرض بیرون بزند، ممکن است کل صفحه اسکرول افقی بگیرد و ظاهر سایت کاملاً به‌هم بریزد. یک overflow-x: hidden روی body مشکل را پنهان می‌کند اما ریشه را حل نمی‌کند.
  • اندازه‌های ثابت برای عناصر کلیدی: دکمه‌ها، آیکون‌ها و فرم‌های با اندازه‌ی پیکسلی، در موبایل ممکن است کوچک‌تر از حد لمس شوند. حداقل ۴۴ پیکسل را برای تپ‌تارگت رعایت کنید.
  • نادیده گرفتن حالت Landscape موبایل: کاربری که گوشی را افقی می‌گیرد، عرض بیشتر اما ارتفاع کمتر دارد. اگر چیدمان شما فقط Portrait را دیده باشد، در Landscape به‌هم می‌ریزد.
  • تست فقط در DevTools: شبیه‌ساز مرورگر دسکتاپ، رفتار موبایل را کامل شبیه‌سازی نمی‌کند. تست روی گوشی واقعی با اینترنت سلفون، خیلی چیزها را نشان می‌دهد.
  • نادیده گرفتن ترافیک موبایل: اگر سایت شما در آمار، ۷۰٪ ترافیک موبایل دارد اما طراحی از دسکتاپ شروع شده، تصمیم‌ها همه وارونه گرفته می‌شوند.

بخشی از این اشتباهات در اشتباهات رایج طراحی ریسپانسیو به‌طور تفصیلی آمده است.

تست ریسپانسیو روی دستگاه واقعی

سه ابزار در پروژه‌هایم بیشترین استفاده را داشته‌اند:

  1. DevTools Responsive Mode: برای تست سریع در عرض‌های مختلف. اما دروغِ مؤدبانه می‌گوید چون شبیه‌سازی کامل نیست.
  2. گوشی واقعی با اینترنت سلفون: استاندارد طلایی. رفتار لمسی، سرعت واقعی، رفتار نوار آدرس، همه اینجا معلوم می‌شود.
  3. ابزارهای تست ریسپانسیو آنلاین: برای تست در دستگاه‌های مختلف که در دسترس نیستند. مفید اما محدود.

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

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

لایه‌ای زیر سینتکس: موتور رندر و ریسپانسیو

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

  1. Rendering Pipeline در تغییر عرض: وقتی کاربر گوشی را می‌چرخاند یا نوار آدرس موبایل کوچک و بزرگ می‌شود، عرض ویوپورت تغییر می‌کند. هر تغییر عرض، چرخه‌ی کامل layout و paint را تحریک می‌کند. اگر در حین resize از توابع جاوااسکریپت سنگین استفاده کنید، main thread خفه می‌شود. الگوی درست: debounce در resize و اجرای محاسبات سنگین در requestAnimationFrame یا حتی Web Worker. جزئیات در بهینه سازی جاوااسکریپت.
  2. Viewport Units و چرخه‌ی اندازه‌گیری: وقتی از vw و vh استفاده می‌کنید، موتور رندر باید در هر تغییر اندازه، مقدار نهایی را از نو محاسبه کند. در پروژه‌های بزرگ با انیمیشن‌های مبتنی بر vw، این هزینه می‌تواند در پروفایلر محسوس باشد. راه‌حل: استفاده از clamp() و rem به‌جای vw در جاهایی که مقیاس‌پذیری خودکار کافی است.
  3. Container Queries و آینده‌ی ریسپانسیو: Container Queries به شما اجازه می‌دهند رفتار یک کامپوننت را بر اساس عرض والدش تعیین کنید، نه عرض ویوپورت. این یعنی یک کارت می‌تواند در سایدبار کوچک و در صفحه‌ی اصلی بزرگ نمایش داده شود، بدون هیچ کلاس یا media query اضافه. این ویژگی در مرورگرهای مدرن امروز پشتیبانی می‌شود و در پروژه‌های Component-Based یک تحول واقعی است.

نکته‌ی عملی برای مهندسان پلتفرم: اگر در سایت شما پروفایلر نشان می‌دهد که Recalculate Style هزینه‌ی بالایی دارد و کاربران با اسکرول افقی مشکل دارند، احتمالاً یک یا چند عنصر با عرض ثابت بزرگ‌تر از عرض ویوپورت وجود دارد. یافتن این عناصر با document.querySelectorAll('*') و مقایسه‌ی scrollWidth در چند خط JS ساده است، و راه‌حل معمولاً صریح‌کردن عرض عنصر است، نه اضافه‌کردن overflow: hidden روی body. اگر سایت روی وردپرس و قالب سنگین اجرا می‌شود، پیشنهاد می‌کنم دلایل کندی قالب و افزایش سرعت وردپرس را هم در کنار این بخش مرور کنید.

هر media query که به‌جای جریان طبیعی محتوا اضافه می‌کنید، یک نقطه‌ی جدید برای شکستن در آینده می‌سازد؛ کمترین تعداد، پایدارترین نتیجه را می‌دهد.

خط پایان این نقشه

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

  1. از جریان شروع کنید، نه از media query. اگر بتوانید چیدمان خود را با واحدهای نسبی، Flexbox و Grid خودتنظیم طراحی کنید، اکثر دستگاه‌ها بدون دخالت شما کار می‌کنند. media query برای موارد استثنا نگه دارید.
  2. تست را از گوشی واقعی شروع کنید. DevTools برای سرعت خوب است اما حقیقت را نمی‌گوید. سه دقیقه روی گوشی خودتان با اینترنت سلفون، بیشتر از یک ساعت در شبیه‌ساز ارزش دارد.
  3. Container Queries را جدی بگیرید. این ویژگی، آینده‌ی ریسپانسیو در پروژه‌های Component-Based است. اگر امروز با React یا Vue کار می‌کنید، ارزشش را دارد که با آن آشنا شوید.

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

اگر در پروژه‌ای با یک مشکل عجیب ریسپانسیو روبرو شده‌اید — مثلاً چیدمانی که در ۳۷۵ پیکسل به‌هم می‌ریزد اما در ۳۲۰ پیکسل درست است، یا موردی که فقط در حالت Landscape رخ می‌دهد — جزئیات سناریو را در دیدگاه بنویسید. مخصوصاً اگر با یک راه‌حل غیرمتعارف مشکل را حل کرده‌اید، همان تجربه برای خواننده‌ی بعدی از هر توضیح کلی ارزشمندتر است. 📱