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

فصل ۵ از ۹

پیشرفت ترم
۰٪

ترم ۷ · پل به JavaScript

روشن/خاموش‌کردنِ یک class: پلِ CSS و JS

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

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

این فصل کوچک‌ترین و مهم‌ترین قراردادِ front-end را یاد می‌گیری: JavaScript فقط اسمِ حالت را عوض می‌کند؛ ظاهر، تمامش کارِ CSS است. با یک خط classList.toggle یک کلیدِ چراغ می‌سازی که کلِ صفحه را به حالتِ شب می‌برد و برمی‌گرداند — و همهٔ زیبایی‌اش را استایل‌هایی انجام می‌دهند که ساختن‌شان را در ترم‌های قبل یاد گرفتی.

یک پل که دو جزیره را به هم وصل می‌کند: یک سمت قلم‌مو و پالتِ رنگ، سمتِ دیگر یک چرخ‌دنده با جرقه؛ وسطِ پل یک کلیدِ چراغ و پس‌زمینه نیمی روشن و نیمی تاریک

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

  • با classList.toggle یک class را با هر کلیک بیاوری و ببری
  • یک حالتِ کاملِ بصری (حالتِ شب) را فقط در CSS تعریف کنی و فقط با JS روشنش کنی
  • توضیح بدهی چرا نوشتنِ رنگ و استایل داخل JavaScript تقریباً همیشه اشتباه است
  • خرابیِ بی‌صدای «اسمِ class ناهماهنگ بینِ JS و CSS» را پیدا و رفع کنی

قبل از شروع#

  • از فصل ۴: addEventListener و رویدادِ click.
  • از فصل ۳: classList و کارِ add و remove.
  • از ترم ۵: transition — بدونِ حتی یک خطِ جدید، دوباره به کار می‌افتد.

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

۱. کلیدی که برمی‌گردد#

از فصل ۳ می‌توانی با classList.add یک class بگذاری و با classList.remove برش داری. برای یک تغییرِ یک‌بارمصرف کافی است، ولی برای یک کلید نه: کلیدِ چراغ باید بداند الان روشن است یا خاموش تا برعکسش کند. با add تنها، کلیکِ دوم هیچ کاری نمی‌کند — class از قبل هست.

چیزی که می‌خواهیم یک حرکتِ رفت‌وبرگشتی است: «اگر این class را ندارد بگذار؛ اگر دارد بردار.» JavaScript همین را در یک کلمه دارد: toggle.

۲. حالتِ شب: CSS آماده، JS یک خط#

اول ظاهرِ هر دو حالت باید کامل در CSS تعریف شود — در آزمایشگاه همین قاعده‌ها آماده در تبِ CSS نشسته‌اند، خط‌به‌خط بخوان‌شان — حالتِ عادی روی body، حالتِ شب پشتِ class ای به اسمِ night:

body {
  background-color: #f6edda;
  color: #2c2114;
  transition: background-color 0.4s, color 0.4s;
}

body.night {
  background-color: #221d15;
  color: #f0e6cf;
}

body.night را از ترم ۲ می‌شناسی: «همان body، وقتی class ای به اسمِ night دارد.» تا وقتی کسی این class را نگذارد، این قاعده خواب است. حالا کلید:

const lightSwitch = document.querySelector('.light-switch');
const body = document.querySelector('body');

lightSwitch.addEventListener('click', function () {
  body.classList.toggle('night');
});

چک کن: کلیک کن — کلِ صفحه نرم به شب می‌رود؛ دوباره کلیک کن — برمی‌گردد. آن نرمی هم کارِ transition ترم ۵ است که حالا با هر toggle جان می‌گیرد.

Checkpoint. قبل از ادامه، جواب بده: اگر به‌جای toggle بنویسی add و سه بار کلیک کنی چه می‌شود؟ (جواب: کلیکِ اول شب می‌شود و دیگر هیچ‌وقت برنمی‌گردد — add یک‌طرفه است، toggle رفت‌وبرگشتی.)

۳. حالا خرابش کن: دو اسم که به هم نمی‌خورند#

در JS به‌جای 'night' بنویس 'nigth' — جابه‌جاییِ حرفی که در تایپِ سریع دستِ همه درمی‌آید:

lightSwitch.addEventListener('click', function () {
  body.classList.toggle('nigth');
});

کلیک کن. هیچ اتفاقی نمی‌افتد و console هم کاملاً ساکت است.

🔧 اگر کار نکرد: جالب اینجاست که کدت دارد کار می‌کند! اگر با DevTools ترم ۲ به تبِ Elements نگاه کنی، می‌بینی class="nigth" واقعاً با هر کلیک می‌آید و می‌رود. خرابی جای دیگری است: در CSS هیچ قاعده‌ای برای .nigth نیست؛ قاعده‌ها برای .night نوشته شده‌اند. دو دنیا فقط با یک string به هم وصل‌اند و هیچ‌کس غلط‌گیریِ املایی نمی‌کند — نه مرورگر، نه JS. هر وقت toggle «کار نکرد»، اسمِ class را در JS و CSS کنارِ هم بگذار و حرف‌به‌حرف مقایسه کن.

۴. پل: تقسیمِ کار بینِ دو دنیا#

به کدت نگاه کن. JavaScript فقط یک کلمه را جابه‌جا می‌کند: night هست یا نیست — همین یعنی state، حالتِ فعلیِ صفحه. رنگِ پس‌زمینه، رنگِ متن، نرمیِ تغییر — همه در CSS اند، همان‌جا که شش ترم تمرینش کردی. این سلیقه نیست؛ قراردادِ کاریِ front-end است:

  • CSS صاحبِ ظاهر است: هر حالت (شب، باز، انتخاب‌شده) یک class با استایلِ کامل.
  • JS صاحبِ تصمیم است: فقط تصمیم می‌گیرد کدام حالت الان فعال باشد.

💡 نکته: هر وقت وسطِ JS داشتی رنگ و اندازه و فونت می‌نوشتی، بایست. جای آن کد تقریباً همیشه داخلِ یک class در CSS است و سهمِ JS فقط یک toggle.

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

<!-- 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>کلید چراغ</title>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <main>
      <article class="card">
        <h1>اتاق مطالعه</h1>
        <p>این صفحه یک کلیدِ چراغ دارد. روشن و خاموشش کن و ببین چه چیزهایی با هم عوض می‌شوند.</p>
        <button class="light-switch">چراغ</button>
      </article>
    </main>
    <script src="script.js"></script>
  </body>
</html>
/* styles.css */
body {
  font-family: Tahoma, sans-serif;
  background-color: #f6edda;
  color: #2c2114;
  line-height: 1.7;
  padding: 24px;
  transition: background-color 0.4s, color 0.4s;
}

.card {
  background-color: #ffffff;
  border: 1px solid #d8ccae;
  border-radius: 12px;
  padding: 16px;
  max-width: 360px;
  transition: background-color 0.4s, border-color 0.4s;
}

.light-switch {
  font-family: inherit;
  font-size: 1rem;
  padding: 8px 16px;
  border: 1px solid #b98a2f;
  border-radius: 8px;
  background-color: #f3d491;
  cursor: pointer;
}

body.night {
  background-color: #221d15;
  color: #f0e6cf;
}

body.night .card {
  background-color: #2e2820;
  border-color: #4b4133;
}
// script.js
const lightSwitch = document.querySelector('.light-switch');
const body = document.querySelector('body');

lightSwitch.addEventListener('click', function () {
  body.classList.toggle('night');
});

۵. همیار AI: پل را با AI هم نگه دار#

سه قانونِ ثابتِ کار با AI را از ترم ۱ می‌شناسی؛ اینجا دوباره لازم‌شان داری:

🤖 با AI: «اول خودت، بعد AI» — اول با معیارهای خودت تصمیم بگیر، بعد نظرِ AI را به‌عنوان نظرِ دوم بشنو. «خط به خط» — هر چیزی که AI می‌دهد را خط‌به‌خط بخوان و بفهم، هیچ‌وقت یک‌جا کپی نکن. «AI هم اشتباه می‌کند» — و پایین‌تر یک نمونهٔ واقعی‌اش را می‌بینیم.

کاربردِ خوب. حالا که کلیدِ چراغ را خودت ساخته‌ای، از دستیار AI ات بپرس: «غیر از حالتِ شب، چه حالت‌هایی را سایت‌های واقعی با toggle یک class روشن و خاموش می‌کنند؟ برای هرکدام فقط اسمِ class و دو خط CSS پیشنهاد بده.» دو تا از جواب‌ها را در آزمایشگاه با همان الگوی این فصل بساز و با چیزی که می‌بینی چک کن.

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

<button onclick="document.querySelector('body').style.backgroundColor = '#000000'; document.querySelector('body').style.color = '#ffffff'">حالت شب</button>

خط‌به‌خط بخوانش؛ سه چیز غلط است. اول: آن onclick یک attribute قدیمی است که JS را داخلِ HTML می‌چپاند — همان مخلوط‌کردنِ محتوا و رفتار که ترم ۲ یادت داد از هم جدایشان کنی. رفتار جایش در فایلِ JS و addEventListener است. دوم: رنگ‌ها را دانه‌دانه از JS می‌نویسد؛ یعنی کارِ CSS را در JS دوباره‌سازی می‌کند و حالتِ شب دیگر یک‌جا زندگی نمی‌کند: اگر ده قاعدهٔ CSS داشته باشد، می‌شود ده خطِ JS که باید جدا نگه‌داری‌شان کنی و جدا خراب می‌شوند. سوم: راهِ برگشت ندارد — کلیکِ دوم همان سیاه می‌ماند؛ کلید نیست، یک درِ یک‌طرفه است. درستش همان است که خودت ساختی: یک class در CSS و یک classList.toggle در JS. از همین خانواده: اگر از AI افکتِ hover بخواهی، گاهی برایت listener می‌نویسد، در حالی که :hover ترم ۵ همان را با یک خط CSS می‌دهد. معیارِ گرفتنِ این اشتباه‌ها همان قانونِ پل است: هر جا AI داشت داخلِ JS ظاهر می‌نوشت، بایست و بپرس «این چرا class نیست؟».

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

کلمه تلفظ به حروف فارسی یعنی چه
classList.toggle کلاس‌لیست تاگِل اگر class نبود بگذار، اگر بود بردار — یک کلیدِ رفت‌وبرگشتی
state استِیت حالتِ فعلیِ صفحه (شب/روز، باز/بسته) که JS تعیینش می‌کند
onclick آن‌کلیک attribute قدیمیِ چسباندنِ JS به تگ؛ بشناسش، ولی استفاده نکن

تمرین‌ها

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

در فصل بعد#

حالا حالتِ صفحه دستِ توست. فصل بعد سراغِ گفت‌وگوی واقعی با کاربر می‌رویم: فرم. چیزی که کاربر تایپ کرده را با value می‌خوانی، با preventDefault جلوی عادتِ قدیمیِ مرورگر (بارگذاریِ دوبارهٔ صفحه) را می‌گیری، و با if/else اولین تصمیمِ واقعیِ کدت را می‌گیری.

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

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