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

فصل ۷ از ۸

پیشرفت ترم
۰٪

ترم ۴ · Responsive

dark mode

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

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

خیلی از کاربرها گوشی و کامپیوترشان را روی تمِ تیره گذاشته‌اند و انتظار دارند سایتِ تو هم تیره باشد. در این فصل یاد می‌گیری بفهمی کاربر تمِ روشن خواسته یا تیره، و کلِ صفحه را بینِ این دو جابه‌جا کنی — با همان custom property هایی که در ترم ۲ ساختی. آخر فصل یک صفحه داری که در سیستمِ روشن، روشن است و در سیستمِ تیره، تیره، و در هر دو رنگ‌هایش خوانا می‌مانند.

یک کارتِ یک‌شکل که دو بار نشان داده شده: یک‌بار با پس‌زمینهٔ کاغذیِ روشن و متنِ تیره، یک‌بار با پس‌زمینهٔ تیره و متنِ روشن؛ بینشان یک دسته نمونه‌رنگ که مقدارهایش بین دو حالت عوض می‌شود

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

  • با prefers-color-scheme بفهمی کاربر تمِ روشن خواسته یا تیره
  • یک theme بسازی که مقدارِ token هایش در حالتِ تیره عوض می‌شود
  • بگویی چرا وصله‌کردنِ تک‌تکِ رنگ‌ها همیشه یک‌جا را خراب می‌کند
  • با color-scheme کاری کنی حتی فرم‌ها و اسکرول‌بارِ مرورگر هم تیره شوند

قبل از شروع#

  • از ترم ۲ فصل ۹: custom property و var() — این فصل تماماً روی همان بنا شده.
  • از فصل ۲ (همین ترم): @mediaprefers-color-scheme هم یک ویژگیِ @media است، مثلِ min-width.
  • از ترم ۲ فصل ۵: contrast و اینکه رنگِ متن و پس‌زمینه باید فاصلهٔ کافی داشته باشند.

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

۱. مشکل: رنگ‌های چسبیده به کد#

فرض کن کارتت رنگ‌هایش را مستقیم و ثابت نوشته:

body {
  background-color: #f6edda;
  color: #2c2114;
}

.card {
  background-color: #ffffff;
}

در حالتِ روشن عالی است. حالا می‌خواهی dark mode اضافه کنی. مرورگر یک ویژگیِ @media مخصوص دارد که می‌گوید کاربر تمِ تیره خواسته: prefers-color-scheme: dark. پس ساده‌ترین فکر این است که در آن حالت، پس‌زمینه‌ها را تیره کنی:

@media (prefers-color-scheme: dark) {
  body {
    background-color: #14181f;
  }

  .card {
    background-color: #1e2530;
  }
}

در آزمایشگاه امتحانش کن (پایین‌تر می‌گویم چطور تمِ تیره را روشن کنی). پس‌زمینه‌ها تیره شدند، ولی نتیجه فاجعه است: تیتر و متن تقریباً ناپدید شده‌اند. متن هنوز رنگِ تیرهٔ #2c2114 را دارد، و حالا روی یک کارتِ تیره نشسته — تیره روی تیره. کاربر یک لکهٔ محو می‌بیند، نه یک جمله.

🔧 اگر کار نکرد: تو فقط پس‌زمینه‌ها را عوض کردی و رنگِ متن ثابت ماند. حالا باید برگردی و رنگِ <h1>، <p>، حاشیه‌ها، دکمه و... را هم تک‌تک وصله بزنی — و هر بار یکی را جا می‌اندازی، چون رنگ‌ها همه‌جای فایل پخش‌اند. این دقیقاً همان دردِ «یک رنگ، ده جا» از ترم ۲ است. راهِ حل هم همان است: theme با custom property. به‌جای وصله‌کردنِ رنگ‌ها، پس‌زمینه و متن را با هم به‌عنوان یک جفت تعریف کن تا همیشه با هم عوض شوند و هیچ‌وقت تیره روی تیره نیفتد.

۲. راهِ حل: theme با custom property#

از ترم ۲ یادت هست: token ها را یک‌جا روی :root تعریف می‌کنی و همه‌جا با var() صدایشان می‌زنی. اینجا یک قدمِ تازه اضافه می‌کنیم: همان token ها را داخلِ @media (prefers-color-scheme: dark) دوباره تعریف می‌کنیم، با مقدارِ تیره. خودِ کارت تغییری نمی‌کند؛ فقط مقدارِ متغیرها عوض می‌شود.

:root {
  --bg: #f6edda;
  --card: #ffffff;
  --ink: #2c2114;
  --line: #d8ccae;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #14181f;
    --card: #1e2530;
    --ink: #f2f4f8;
    --line: #2c3644;
  }
}

حالا هرجای CSS به‌جای رنگِ ثابت، var(--bg)، var(--ink) و مثلِ این‌ها را می‌نویسی. دقت کن که --bg و --ink یک جفت‌اند: هر بار یکی تیره می‌شود، دیگری روشن. برای همین دیگر هیچ‌وقت تیره روی تیره نمی‌افتد — چون هر دو با هم و در یک‌جا عوض می‌شوند.

چک کن: تمِ سیستمت را بین روشن و تیره عوض کن (در تنظیماتِ ویندوز، مک یا موبایل؛ یا در DevTools مرورگر، بخشِ Rendering، گزینهٔ Emulate prefers-color-scheme). صفحه با هر تغییر، کامل بین روشن و تیره می‌رود و در هر دو حالت متن خواناست. یک token را دستکاری کن — مثلاً --bg تیره را به یک سرمه‌ایِ روشن‌تر ببر — و ببین فقط پس‌زمینه عوض می‌شود و بقیه دست‌نخورده می‌ماند.

💡 نکته: رنگِ تیره را هیچ‌وقت سیاهِ مطلق (#000000) نگذار و متن را سفیدِ مطلق نکن؛ کنترستِ خیلی‌شدید چشم را در تاریکی می‌زند. یک سرمه‌ایِ خیلی‌تیره برای پس‌زمینه و یک سفیدِ کمی‌شکسته برای متن، هم خواناست هم چشم‌نواز.

۳. color-scheme: به مرورگر خبر بده#

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

:root {
  color-scheme: light dark;
}

color-scheme: light dark یعنی «این صفحه هم روشن را بلد است هم تیره؛ هرکدام که کاربر خواست، عناصرِ بومی‌ات را هم همان‌طور بکش». برخلافِ --bg، این یک custom property نیست — یک property واقعیِ CSS است، و کارش هماهنگ‌کردنِ همان چیزهایی است که از دستِ تو خارج‌اند.

چک کن: در تمِ تیره، حالا اسکرول‌بار و هر ورودی‌ای هم تیره‌اند و دیگر لکهٔ سفید نداری. صفحه یک‌دست است.

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

اول 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>dark mode</title>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <main class="page">
      <article class="card">
        <h1>سلام، تاریکی</h1>
        <p>این صفحه تمِ سیستمِ تو را می‌خواند و خودش را روشن یا تیره می‌کند.</p>
        <a class="btn" href="#">شروع</a>
      </article>
    </main>
  </body>
</html>

و styles.css:

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

/* tem-e roshan: meghdar-e pishfarz-e token-ha */
:root {
  color-scheme: light dark;
  --bg: #f6edda;
  --card: #ffffff;
  --ink: #2c2114;
  --muted: #6b6150;
  --brand: #2a6b93;
  --line: #d8ccae;
}

/* tem-e tire: haman token-ha, meghdar-e digar */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #14181f;
    --card: #1e2530;
    --ink: #f2f4f8;
    --muted: #aab3c5;
    --line: #2c3644;
  }
}

body {
  margin: 0;
  font-family: Tahoma, sans-serif;
  background-color: var(--bg);
  color: var(--ink);
  line-height: 1.9;
}

.page {
  padding: 40px 20px;
}

.card {
  max-width: 360px;
  margin-inline: auto;
  padding: 24px;
  background-color: var(--card);
  border: 1px solid var(--line);
  border-radius: 16px;
}

.card h1 {
  margin-block: 0 10px;
  color: var(--ink);
}

.card p {
  margin-block: 0 16px;
  color: var(--muted);
}

.btn {
  display: inline-block;
  padding: 10px 18px;
  border-radius: 10px;
  background-color: var(--brand);
  color: #ffffff;
  font-weight: 700;
}

یک کلید یا تنظیمِ سیستم که روی حالتِ تیره است و از آن یک جریان به سمتِ صفحه می‌رود؛ صفحه رنگ‌هایش را از دستهٔ نمونه‌رنگِ تیره می‌گیرد

چک کن: صفحهٔ کامل را در هر دو تم ببین. در روشن: کاغذیِ گرم با متنِ تیره. در تیره: سرمه‌ایِ تیره با متنِ روشن. تنها رنگی که ثابت ماند، سفیدِ رویِ دکمه است — چون دکمه در هر دو تم آبیِ پررنگ دارد و سفید رویش خواناست.

🤖 با AI: رنگ‌های تمِ تیره‌ات را به دستیار AI ات بده و بپرس «کنترستِ متن روی پس‌زمینه در حالتِ تیره برای خواندن کافی است؟». این یکی از بهترین کاربردهای AI است — یک بازبینیِ دسترس‌پذیری. ولی جوابش را دربست نپذیر: همان‌جا در آزمایشگاه، تمِ تیره را روشن کن و با چشمِ خودت ببین متن راحت خوانده می‌شود یا نه. عدد مهم است، ولی چشم داورِ آخر است.

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

کلمه تلفظ به حروف فارسی یعنی چه
dark mode دارک مود تمِ تیرهٔ صفحه، برای وقتی کاربر سیستمش را تیره گذاشته
prefers-color-scheme پریفِرز کالر اسکیم ویژگیِ @media که می‌گوید کاربر تمِ روشن خواسته یا تیره
color-scheme کالر اسکیم property ای که به مرورگر می‌گوید صفحه هر دو تم را دارد تا عناصرِ بومی هم هماهنگ شوند
token توکِن همان custom property های theme؛ رنگ و اندازه‌هایی که یک‌جا تعریف و همه‌جا مصرف می‌شوند

تمرین‌ها

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

در فصل بعد#

الان می‌توانی به هر صفحه dark mode بدهی. این آخرین مفهومِ تازهٔ ترمِ Responsive بود. فصل بعد فصلِ پروژه است: همهٔ چیزهایی که این ترم ساختی — @media، تصویرِ responsive، تایپوگرافیِ سیال، منوی بازشو و همین dark mode — را در یک صفحهٔ کامل کنارِ هم می‌گذاری که از موبایل تا دسکتاپ، در روشن و تیره، درست کار کند.

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

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