اندازه‌گیری نسبت به صفحه‌نمایش: واحدهای Viewport

تا اینجا واحدهایی دیدیم که نسبت به فونت والد، فونت ریشه یا ابعاد یک عنصر خاص محاسبه می‌شدن. حالا وقتشه با خانواده‌ای از واحدها آشنا بشیم که مستقیماً نسبت به اندازه Viewport (یعنی ناحیه قابل‌مشاهده مرورگر) محاسبه می‌شن؛ ابزاری کلیدی برای طراحی Responsive.

Viewport چیست؟

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

vw: درصدی از عرض Viewport

.banner {
  width: 100vw;
}

واحد vw (Viewport Width) برابر یک‌صدم عرض کامل Viewport است. یعنی 1vw همیشه برابر ۱٪ از عرض ناحیه قابل‌مشاهده مرورگره، و 100vw دقیقاً برابر کل عرض Viewport.

<div class="banner">این بنر همیشه دقیقاً به‌اندازه عرض کامل صفحه‌نمایش است.</div>

برخلاف width: 100% که نسبت به عرض عنصر والد محاسبه می‌شه، 100vw همیشه نسبت به کل صفحه‌نمایش محاسبه می‌شه؛ حتی اگه والد این عنصر عرض کوچک‌تری داشته باشه.

vh: درصدی از ارتفاع Viewport

.hero-section {
  height: 100vh;
}

واحد vh (Viewport Height) دقیقاً همون منطق vw رو داره، ولی برای ارتفاع. 100vh یعنی این عنصر همیشه دقیقاً به‌اندازه کل ارتفاع قابل‌مشاهده صفحه‌نمایش، بدون توجه به میزان محتوای داخلش، ارتفاع خواهد داشت. این تکنیک برای بخش‌های Hero (بخش معرفی اول صفحه) بسیار رایجه.

vmin و vmax: کوچک‌ترین و بزرگ‌ترین بعد

.square {
  width: 50vmin;
  height: 50vmin;
}

vmin برابر با کوچک‌ترین مقدار بین vw و vh در همون لحظه است؛ و vmax برعکسش، بزرگ‌ترین مقدار بین این دو. اگه صفحه‌نمایش عمودی و باریک باشه (مثل موبایل در حالت Portrait)، vmin برابر vw خواهد بود؛ و اگه صفحه‌نمایش افقی و پهن باشه (مثل دسکتاپ)، vmin برابر vh خواهد بود.

این ویژگی، vmin رو برای ساخت عناصری که باید همیشه، صرف‌نظر از جهت صفحه‌نمایش، در کوچک‌ترین بعد ممکن جا بگیرن (مثل یه مربع کامل که هیچ‌وقت از صفحه بیرون نزنه)، بسیار مفید می‌کنه.

مشکل معروف vh در مرورگرهای موبایل

یکی از مشکلات شناخته‌شده vh، رفتارش در مرورگرهای موبایله. در بسیاری از مرورگرهای موبایل، نوار آدرس (Address Bar) بسته به رفتار کاربر (اسکرول کردن به بالا یا پایین)، ظاهر یا پنهان می‌شه؛ و این تغییر باعث می‌شه ارتفاع واقعی Viewport هم دائماً تغییر کنه. نتیجه این می‌شه که یک عنصر با height: 100vh، ممکنه گاهی کمی بزرگ‌تر یا کوچک‌تر از ارتفاع واقعی قابل‌مشاهده صفحه به‌نظر برسه، یا حتی باعث ایجاد اسکرول ناخواسته بشه.

راه‌حل مدرن: واحدهای Dynamic، Small و Large Viewport

برای حل دقیقاً همین مشکل، نسخه‌های جدیدتری از واحدهای Viewport به استاندارد CSS اضافه شدن که رفتار دقیق‌تری در برابر تغییرات پویای Viewport (مثل ظاهر و پنهان شدن نوار آدرس موبایل) دارن.

dvw و dvh: Dynamic Viewport

.full-height {
  height: 100dvh;
}

dvh (Dynamic Viewport Height) و dvw (Dynamic Viewport Width)، به‌طور پویا و لحظه‌ای با تغییرات واقعی اندازه Viewport (مثلاً وقتی نوار آدرس مرورگر موبایل ظاهر یا پنهان می‌شه) هماهنگ می‌شن. یعنی 100dvh همیشه دقیقاً برابر ارتفاع واقعی و در‌حال‌‌حاضر قابل‌مشاهده صفحه‌ست؛ نه یک مقدار ثابت که ممکنه با تغییر نوار آدرس، نادرست بشه.

svw و svh: Small Viewport

.footer-fixed {
  height: 100svh;
}

svh (Small Viewport Height) و svw (Small Viewport Width)، همیشه بر اساس کوچک‌ترین حالت ممکن Viewport محاسبه می‌شن؛ یعنی حالتی که تمام نوارهای مرورگر (مثل نوار آدرس) کاملاً نمایان هستن و کمترین فضا رو در اختیار محتوا می‌ذارن.

lvw و lvh: Large Viewport

.hero {
  height: 100lvh;
}

lvh (Large Viewport Height) و lvw (Large Viewport Width)، برعکس نسخه Small، همیشه بر اساس بزرگ‌ترین حالت ممکن Viewport محاسبه می‌شن؛ یعنی حالتی که نوارهای مرورگر پنهان شدن و بیشترین فضای ممکن در اختیار محتواست.

جدول مقایسه‌ای واحدهای Viewport

واحد رفتار
vw / vh مقدار پایه؛ در برخی مرورگرهای موبایل ممکن است دچار نوسان یا مشکل نمایش شود
dvw / dvh به‌طور پویا و لحظه‌ای با تغییرات واقعی Viewport هماهنگ می‌شود
svw / svh همیشه بر اساس کوچک‌ترین حالت ممکن Viewport (کمترین فضا)
lvw / lvh همیشه بر اساس بزرگ‌ترین حالت ممکن Viewport (بیشترین فضا)

یک مثال کاربردی: تایپوگرافی واکنش‌گرا با vw

h1 {
  font-size: 5vw;
}

در این مثال، اندازه فونت تیتر مستقیماً با عرض صفحه‌نمایش تغییر می‌کنه؛ در صفحه‌نمایش‌های بزرگ‌تر، فونت بزرگ‌تر می‌شه و در صفحه‌نمایش‌های کوچک‌تر، کوچک‌تر. این تکنیک، پایه‌ی مفهوم Fluid Typography است که در فصل Responsive Design با جزئیات بیشتری (و معمولاً در ترکیب با clamp() برای محدود کردن حداقل و حداکثر اندازه) بررسیش می‌کنیم.

نکات مهم

  • vw و vh نسبت به کل Viewport محاسبه می‌شوند، نه نسبت به عنصر والد.
  • vmin کوچک‌ترین و vmax بزرگ‌ترین مقدار بین vw و vh در همان لحظه را برمی‌گرداند.
  • واحدهای dvh، svh و lvh برای حل مشکل نوسان ارتفاع Viewport در مرورگرهای موبایل (به‌خاطر نوار آدرس) طراحی شده‌اند.

اشتباهات رایج

  • استفاده بی‌قید از height: 100vh در طراحی موبایل، بدون توجه به مشکل نوسان ناشی از نوار آدرس مرورگر.
  • قاطی کردن vw با درصد معمولی (%)؛ اولی نسبت به کل Viewport، دومی نسبت به والد محاسبه می‌شود.
  • استفاده مستقیم از vw برای font-size بدون محدود کردن آن با min() یا clamp()، که می‌تواند در صفحه‌نمایش‌های خیلی بزرگ یا خیلی کوچک، متن را غیرقابل‌خواندن کند.

سازگاری مرورگرها

واحدهای پایه vw و vh پشتیبانی گسترده و دیرینه‌ای در تمام مرورگرهای مدرن دارند. اما واحدهای جدیدتر مثل dvh، svh و lvh، به‌نسبت جدیدترن؛ پیش از استفاده در پروژه‌های واقعی، بررسی وضعیت پشتیبانی مرورگرهای هدف پروژه ضروریه.

جمع‌بندی

واحدهای Viewport مثل vw و vh، اندازه‌ای نسبت به کل ناحیه قابل‌مشاهده مرورگر محاسبه می‌کنند و برای طراحی Responsive بسیار کاربردی هستند. vmin و vmax کوچک‌ترین و بزرگ‌ترین بعد Viewport را برمی‌گردانند. نسخه‌های جدیدتر (dvw/dvh، svw/svh، lvw/lvh) برای حل دقیق‌تر مشکل نوسان ارتفاع در مرورگرهای موبایل، به‌خاطر ظاهر و پنهان شدن پویای نوار آدرس، طراحی شده‌اند.