مخفی کردن بدون حذف کردن: visibility و opacity

در درس ۵-۱ با display: none آشنا شدیم که یک عنصر رو کاملاً از جریان صفحه حذف می‌کنه. اما گاهی می‌خوایم یک عنصر رو مخفی کنیم، بدون اینکه فضایی که اشغال کرده رو از دست بدیم؛ یا حتی می‌خوایم به‌جای مخفی کردن کامل، فقط شفافیتش رو تغییر بدیم. اینجاست که visibility و opacity وارد کار می‌شن.

visibility: hidden چیست؟

.hidden-box {
  visibility: hidden;
}
<div>جعبه اول</div>
<div class="hidden-box">جعبه دوم (مخفی می‌شود)</div>
<div>جعبه سوم</div>

وقتی visibility: hidden روی یک عنصر اعمال بشه، اون عنصر از نظر بصری کاملاً نامرئی می‌شه؛ ولی برخلاف display: none، فضایی که این عنصر در چیدمان اشغال کرده، همچنان باقی می‌مونه. یعنی در مثال بالا، بین جعبه اول و جعبه سوم، یه فضای خالی به‌اندازه جعبه دوم دیده می‌شه؛ فقط خود محتوا نامرئیه.

مقایسه display: none و visibility: hidden

ویژگی display: none visibility: hidden
نمایش بصری کاملاً حذف می‌شود نامرئی می‌شود
فضای اشغال‌شده در چیدمان حذف می‌شود (بدون فضا) باقی می‌ماند (فضا حفظ می‌شود)
تأثیر روی عناصر مجاور عناصر مجاور جای خالی را پر می‌کنند عناصر مجاور بدون تغییر باقی می‌مانند

یک مثال بصری برای تفاوت این دو

.box-a {
  display: none;
}

.box-b {
  visibility: hidden;
}
<div>قبل از جعبه مخفی</div>
<div class="box-a">این با display:none مخفی شده</div>
<div>بعد از جعبه مخفی (نزدیک‌تر می‌شود)</div>

<hr>

<div>قبل از جعبه مخفی</div>
<div class="box-b">این با visibility:hidden مخفی شده</div>
<div>بعد از جعبه مخفی (فاصله حفظ می‌شود)</div>

در گروه اول، چون .box-a کاملاً از جریان حذف شده، عنصر بعدی بلافاصله جای خالی رو پر می‌کنه. اما در گروه دوم، چون .box-b فقط نامرئی شده (نه حذف)، عنصر بعدی همچنان فاصله‌ی مربوط به جعبه مخفی رو حفظ می‌کنه.

visibility: visible و بازگرداندن نمایش

.box {
  visibility: hidden;
}

.box.show {
  visibility: visible;
}

مقدار پیش‌فرض این Property، visible است. می‌شه با تغییر مقدار (مثلاً از طریق یک Class دیگه یا جاوااسکریپت)، عنصر رو دوباره قابل‌مشاهده کرد؛ بدون این‌که فضای اشغال‌شده‌اش هیچ‌وقت تغییر کنه.

نکته‌ای درباره ارث‌بری در visibility

برخلاف display، Property به اسم visibility جزو Propertyهای ارث‌بری‌پذیر است (همون مفهومی که در فصل ۲ با Inheritance دیدیم). این یعنی اگه یک والد visibility: hidden داشته باشه، فرزندانش هم به‌طور پیش‌فرض مخفی می‌شن؛ مگر اینکه صراحتاً روی یکی از فرزندان، visibility: visible تعریف بشه که در این حالت، فقط همون فرزند خاص دوباره قابل‌مشاهده می‌شه، حتی اگه والدش مخفی باشه.

.parent {
  visibility: hidden;
}

.parent .child-visible {
  visibility: visible;
}
<div class="parent">
  <p>این پاراگراف مخفی است.</p>
  <p class="child-visible">این پاراگراف دوباره نمایان می‌شود.</p>
</div>

این رفتار با display: none کاملاً متفاوته؛ چون وقتی یک والد display: none داشته باشه، هیچ فرزندی، حتی با تعریف صریح display: block روی خودش، دوباره قابل‌مشاهده نمی‌شه (چون کل والد از جریان صفحه حذف شده).

opacity: کنترل شفافیت

.faded {
  opacity: 0.5;
}

Opacity (کدری/شفافیت) میزان شفاف بودن یک عنصر رو، از ۰ (کاملاً نامرئی) تا ۱ (کاملاً واضح)، مشخص می‌کنه.

<img src="photo.jpg" style="opacity: 1;" alt="تصویر کامل">
<img src="photo.jpg" style="opacity: 0.5;" alt="تصویر نیمه‌شفاف">
<img src="photo.jpg" style="opacity: 0;" alt="تصویر کاملاً نامرئی">

وقتی opacity برابر 0 باشه، عنصر کاملاً نامرئی می‌شه؛ ولی درست مثل visibility: hidden، فضای اشغال‌شده‌اش در چیدمان همچنان باقی می‌مونه.

تفاوت مهم: opacity: 0 در برابر visibility: hidden

با اینکه هر دو باعث نامرئی شدن کامل عنصر می‌شن و فضای چیدمان رو حفظ می‌کنن، یک تفاوت اساسی دارن:

  • visibility: hidden عنصر رو کاملاً از تعامل خارج می‌کنه؛ یعنی نه قابل کلیک است، نه قابل انتخاب با ماوس.
  • opacity: 0 عنصر رو فقط از نظر بصری نامرئی می‌کنه؛ ولی عنصر همچنان در صفحه «حضور فیزیکی» داره و می‌تونه کلیک بشه یا حتی توسط کاربر انتخاب (Select) بشه، مگر اینکه صراحتاً با Property دیگه‌ای (مثل pointer-events: none) این رفتار هم غیرفعال بشه.

کاربرد رایج opacity در انیمیشن و Transition

برخلاف visibility که فقط بین دو حالت کاملاً مشخص (visible و hidden) سوییچ می‌کنه، opacity یک مقدار عددی پیوسته‌ست (بین ۰ و ۱) که می‌تونه به‌آرومی و با انیمیشن تغییر کنه. به همین دلیل، opacity یکی از پرکاربردترین Propertyها برای ساخت جلوه‌های محو شدن تدریجی (Fade) با Transition و Animation‌هاست؛ موضوعی که در فصل‌های آینده کامل بررسیش می‌کنیم.

.fade-in {
  opacity: 0;
  transition: opacity 0.3s;
}

.fade-in.visible {
  opacity: 1;
}

جدول جمع‌بندی سه روش مخفی‌سازی

روش فضای چیدمان قابلیت تعامل (کلیک و...) قابل انیمیشن تدریجی
display: none حذف می‌شود خیر خیر
visibility: hidden حفظ می‌شود خیر خیر (فقط دو حالت مشخص)
opacity: 0 حفظ می‌شود بله (مگر با pointer-events غیرفعال شود) بله

نکات مهم

  • visibility: hidden فضای عنصر را حفظ می‌کند، ولی برخلاف display: none، ارث‌بری‌پذیر است.
  • opacity: 0 عنصر را کاملاً نامرئی می‌کند، ولی همچنان قابل کلیک و تعامل باقی می‌ماند.
  • opacity برای ساخت افکت‌های محو شدن تدریجی مناسب‌تر است، چون مقداری پیوسته و قابل انیمیشن‌سازی است.

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

  • استفاده از opacity: 0 برای مخفی کردن کامل یک عنصر، بدون توجه به این‌که عنصر همچنان قابل کلیک باقی می‌ماند و می‌تواند مشکلات دسترسی‌پذیری ایجاد کند.
  • قاطی کردن visibility: hidden با display: none، در حالی که رفتار این دو در حفظ یا حذف فضای چیدمان کاملاً متفاوت است.
  • فراموش کردن ارث‌بری‌پذیر بودن visibility، که می‌تواند رفتار غیرمنتظره‌ای در فرزندان یک عنصر مخفی‌شده ایجاد کند.

جمع‌بندی

visibility: hidden یک عنصر را نامرئی می‌کند ولی فضای چیدمانش را حفظ می‌کند و ارث‌بری‌پذیر است؛ این رفتار کاملاً متفاوت از display: none است که عنصر را کاملاً از جریان صفحه حذف می‌کند. opacity هم می‌تواند با مقدار صفر، عنصر را کاملاً نامرئی کند، ولی برخلاف visibility، عنصر همچنان قابل تعامل باقی می‌ماند و به‌خاطر ماهیت پیوسته‌اش، برای ساخت جلوه‌های محو شدن تدریجی بسیار مناسب‌تر است.