واحدهایی که نسبت به چیز دیگری اندازه می‌گیرند: واحدهای نسبی

در درس قبل دیدیم که واحدهای مطلق مثل px، ثابت و مستقل از هر عاملی هستن؛ که هم مزیته و هم گاهی محدودیت. حالا وقتشه با خانواده‌ی واحدهای نسبی (Relative Units) آشنا بشیم؛ واحدهایی که اندازه‌شون نسبت به یک مقدار مرجع دیگه (مثل اندازه فونت والد یا اندازه صفحه) محاسبه می‌شه و همین موضوع، انعطاف‌پذیری بسیار بیشتری بهشون می‌ده.

درصد (%): نسبت به والد

.child {
  width: 50%;
}
<div style="width: 400px;">
  <div class="child">این عنصر ۵۰٪ عرض والدش است.</div>
</div>

واحد درصد (%) همیشه نسبت به یک مقدار مرجع خاص محاسبه می‌شه؛ برای width، این مرجع معمولاً عرض عنصر والده. در این مثال، چون والد ۴۰۰ پیکسل عرض داره، فرزند با width: 50%، دقیقاً ۲۰۰ پیکسل عرض خواهد داشت.

نکته مهم: مرجع درصد، بسته به Property متفاوته. مثلاً درصد برای font-size نسبت به فونت والد محاسبه می‌شه، نه عرض یا ارتفاع؛ و درصد برای height، شرط خاصی داره که در ادامه بهش اشاره می‌کنیم.

em: نسبت به اندازه فونت والد (یا خود عنصر)

.parent {
  font-size: 20px;
}

.child {
  font-size: 1.5em;
}
<div class="parent">
  متن والد
  <span class="child">متن فرزند</span>
</div>

واحد em نسبت به اندازه فونت والد محاسبه می‌شه. در این مثال، چون فونت والد ۲۰ پیکسله، 1.5em برابر 20 × 1.5 = 30px خواهد بود.

رفتار em روی Propertyهای غیر از font-size

.box {
  font-size: 16px;
  padding: 2em;
}

وقتی em روی Propertyای غیر از font-size (مثل padding) استفاده بشه، مرجعش اندازه فونت خود همون عنصر است، نه والدش. در این مثال، padding: 2em برابر 16 × 2 = 32px خواهد بود.

مشکل معروف em: تأثیر تجمعی (Compounding)

body {
  font-size: 16px;
}

.level-1 {
  font-size: 1.2em; /* 16 × 1.2 = 19.2px */
}

.level-2 {
  font-size: 1.2em; /* 19.2 × 1.2 = 23.04px */
}

.level-3 {
  font-size: 1.2em; /* 23.04 × 1.2 = 27.648px */
}
<div class="level-1">
  سطح ۱
  <div class="level-2">
    سطح ۲
    <div class="level-3">سطح ۳</div>
  </div>
</div>

چون em همیشه نسبت به فونت والد مستقیم محاسبه می‌شه، در ساختارهای تودرتو (Nested)، این مقدار به‌صورت تجمعی و ضربی رشد می‌کنه. هرچه عمق تودرتو بیشتر بشه، اندازه فونت به‌طور غیرمنتظره‌ای بزرگ‌تر و بزرگ‌تر می‌شه؛ حتی اگه در هر سطح، همون مقدار 1.2em نوشته شده باشه. این رفتار، یکی از رایج‌ترین منابع سردرگمی با em است.

rem: نسبت به فونت عنصر ریشه (Root)

html {
  font-size: 16px;
}

.level-1 {
  font-size: 1.2rem; /* 16 × 1.2 = 19.2px */
}

.level-2 {
  font-size: 1.2rem; /* همچنان 19.2px، نه تجمعی */
}

واحد rem (Root em) دقیقاً همون رفتار em رو داره، با یک تفاوت کلیدی: همیشه نسبت به اندازه فونت عنصر html (یعنی ریشه سند) محاسبه می‌شه، نه والد مستقیم. این یعنی صرف‌نظر از اینکه یک عنصر چقدر عمیق در ساختار HTML تودرتو شده باشه، مقدار rem همیشه پیش‌بینی‌پذیر و ثابت می‌مونه؛ چون فقط به یک مرجع واحد (فونت html) وابسته‌ست، نه به زنجیره‌ای از والدها.

چرا rem معمولاً به em ترجیح داده می‌شود؟

به‌خاطر همین مشکل تجمعی، در اکثر پروژه‌های واقعی، rem برای font-size عناصر متنی (و حتی گاهی برای فاصله‌گذاری کلی مثل margin و padding) به em ترجیح داده می‌شه؛ چون رفتارش قابل‌پیش‌بینی‌تر و مستقل از عمق تودرتوی HTML است.

html {
  font-size: 16px;
}

h1 {
  font-size: 2rem;    /* 32px */
}

p {
  font-size: 1rem;    /* 16px */
  margin-bottom: 1.5rem; /* 24px */
}

مزیت مهم rem و em نسبت به px: واکنش به تنظیمات کاربر

همون‌طور که در درس قبل به‌عنوان محدودیت px اشاره کردیم، اگه کاربر اندازه فونت پیش‌فرض مرورگرش رو تغییر بده، مقادیر تعریف‌شده با remem) به‌طور خودکار با این تغییر هماهنگ می‌شن؛ چون این واحدها نسبت به یک مقدار قابل‌تغییر محاسبه می‌شن، نه یک عدد کاملاً ثابت. این ویژگی، یکی از مهم‌ترین دلایل ترجیح این واحدها در طراحی دسترسی‌پذیر (Accessible) است.

ex: نسبت به ارتفاع حرف x

.text {
  line-height: 2ex;
}

واحد ex نسبت به ارتفاع حرف کوچک «x» در فونت جاری محاسبه می‌شه. این واحد بسیار به‌ندرت در پروژه‌های واقعی استفاده می‌شه، چون مقدار دقیقش به فونت انتخاب‌شده بستگی داره و بین فونت‌های مختلف، یکسان نیست؛ همین غیرقابل‌پیش‌بینی بودن، باعث محبوبیت پایینش شده.

ch: نسبت به عرض کاراکتر 0

input {
  width: 20ch;
}

واحد ch نسبت به عرض کاراکتر «0» (صفر) در فونت جاری محاسبه می‌شه. این واحد کاربرد نسبتاً خاصی داره: مشخص کردن عرض یک فیلد ورودی بر اساس تعداد تقریبی کاراکترهایی که باید در خودش جا بده؛ مثلاً width: 20ch یعنی «عرض این input، تقریباً به‌اندازه ۲۰ کاراکتر باشه».

<input type="text" placeholder="کد پستی" style="width: 10ch;">

در این مثال، عرض input تقریباً به‌اندازه ۱۰ کاراکتر تنظیم شده؛ مناسب برای فیلدهایی مثل کد پستی که تعداد کاراکترهاشون معمولاً مشخصه.

جدول جمع‌بندی واحدهای نسبی

واحد نسبت به چه چیزی محاسبه می‌شود مشکل یا نکته خاص
% مقدار مرجع Property (معمولاً ابعاد والد) مرجع دقیق بسته به Property متفاوت است
em فونت والد (برای font-size) یا فونت خود عنصر (برای بقیه Propertyها) در ساختار تودرتو، تجمعی و غیرقابل‌پیش‌بینی می‌شود
rem فونت عنصر html (ریشه سند) مستقل از عمق تودرتو، پیش‌بینی‌پذیرتر از em
ex ارتفاع حرف x در فونت جاری بسته به فونت متغیر است؛ کاربرد محدود
ch عرض کاراکتر 0 در فونت جاری مناسب برای عرض فیلدهای ورودی بر اساس تعداد کاراکتر

نکات مهم

  • درصد همیشه نسبت به یک مقدار مرجع خاص محاسبه می‌شود که بسته به Property متفاوت است.
  • em در ساختارهای تودرتو می‌تواند به‌صورت تجمعی و غیرقابل‌پیش‌بینی رشد کند؛ rem این مشکل را ندارد.
  • rem و em، برخلاف px، نسبت به تنظیمات بزرگ‌نمایی فونت کاربر در مرورگر واکنش‌پذیر هستند.

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

  • استفاده گسترده از em برای font-size در ساختارهای تودرتوی عمیق، بدون توجه به رشد تجمعی و غیرمنتظره اندازه فونت.
  • فراموش کردن اینکه em روی Propertyهای غیر از font-size، نسبت به فونت خود عنصر (نه والد) محاسبه می‌شود.
  • استفاده از درصد بدون درک درستی از این‌که مرجع محاسبه، بسته به Property، دقیقاً چیست.

جمع‌بندی

واحدهای نسبی مثل %، em، rem، ex و ch، برخلاف واحدهای مطلق، نسبت به یک مقدار مرجع خارجی محاسبه می‌شوند. em نسبت به فونت والد یا خود عنصر، rem نسبت به فونت عنصر ریشه، ex نسبت به ارتفاع حرف x و ch نسبت به عرض کاراکتر صفر عمل می‌کنند. به‌دلیل مشکل رشد تجمعی em در ساختارهای تودرتو، rem معمولاً برای font-size در پروژه‌های واقعی ترجیح داده می‌شود.