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

فصل ۳ از ۱۱

پیشرفت ترم
۰٪

ترم ۶ · حرفه‌ای و واقعی

مثل component فکر کن

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

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

تا حالا CSS را قاعده‌به‌قاعده نوشتی. حرفه‌ای‌ها یک قدم عقب‌تر می‌ایستند و به تکه‌های تکرارشوندهٔ صفحه — دکمه، کارت، نشان — به‌عنوان component فکر می‌کنند: یک قطعهٔ مستقل که یک بار می‌سازی و همه‌جا به‌کار می‌بری. این فصل یک دکمهٔ واقعی می‌سازی که هرجای صفحه بگذاری‌اش — بالای نوار ابزار یا پایینِ پاصفحه — بی‌کم‌وکاست درست کار می‌کند، چون به همسایه‌اش وابسته نیست.

یک دکمهٔ آبی که سه بار در سه جای متفاوتِ یک صفحه نشسته — یک بار در نوار بالا، یک بار وسط، یک بار در پاصفحه — و هر سه دقیقاً یک شکل‌اند

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

  • یک تکهٔ تکرارشونده را در یک class مستقل جدا کنی
  • حالت‌های یک component را بسازی (:hover، :disabled، و یک modifier)
  • component ای بنویسی که به جای قرارگیری‌اش وابسته نباشد
  • بگویی چرا یک component «داخلِ» خودش را دارد ولی فاصلهٔ بیرونش کارِ والد است

قبل از شروع#

  • از ترم ۵: حالت‌ها — :hover، :disabled.
  • از ترم ۳: flex، gap، و logical properties مثل border-block-end.
  • از فصل ۱ همین ترم: قرارداد اسمِ block و modifier (.btn، .btn--danger).

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

۱. دکمه‌ای که فقط سرِ جای خودش خوب است#

فرض کن دکمه‌های نوار ابزار را این‌طور استایل داده‌ای — بر اساسِ جایی که هستند، یعنی «هر button که داخلِ .toolbar است»:

.toolbar button {
  background-color: #2a6b93;
  color: #ffffff;
  border: none;
  border-radius: 8px;
  padding: 8px 18px;
}

سه دکمهٔ نوار ابزار عالی شدند: آبی، گِرد، تروتمیز. ولی حالا در پاصفحه یک دکمهٔ دیگر داری («بازگشت به بالا») و آن خام و بی‌ریخت است — یک دکمهٔ خاکستریِ پیش‌فرضِ مرورگر. چرا؟

🔧 اگر کار نکرد: selector ات .toolbar button است، یعنی «هر button که درونِ .toolbar باشد». دکمهٔ پاصفحه داخلِ .toolbar نیست، پس هیچ‌کدام از این استایل‌ها به آن نمی‌رسد. استایلِ دکمه را به جایی که نشسته گره زده‌ای، نه به خودِ دکمه. راهِ درست: ظاهر را از مکان جدا کن — به خودِ دکمه یک class مستقل بده و هرجا خواستی همان class را بگذار.

این همان تفاوتِ «چند قاعدهٔ CSS» و «فکرِ component» است. یک component نباید بپرسد «من کجا هستم؟»؛ باید همه‌چیزِ لازم برای درست‌دیده‌شدن را با خودش داشته باشد.

۲. یک class مستقل و خوداتکا#

استایل را از .toolbar button جدا کن و بگذارش در یک class به اسمِ .btn. حالا این class همه‌چیزِ ظاهرِ دکمه را در خودش دارد، بی‌هیچ وابستگی به والد:

.btn {
  font: inherit;
  background-color: #2a6b93;
  color: #ffffff;
  border: none;
  border-radius: 8px;
  padding: 8px 18px;
  cursor: pointer;
}

بعد در HTML، به هر دکمه — چه در نوار ابزار، چه در پاصفحه — همین class="btn" را بده. دیگر مهم نیست کجاست.

چک کن: حالا هر چهار دکمه (سه‌تای نوار بالا و یکیِ پاصفحه) دقیقاً یک شکل‌اند. دکمهٔ پاصفحه را با موس بگیر و به هر جای دیگرِ صفحه ببر (در HTML جابه‌جایش کن)؛ باز هم همان دکمهٔ آبیِ سالم است. این معنیِ مستقل از جای قرارگیری است.

۳. حالت‌های component#

یک component فقط یک ظاهرِ ثابت نیست؛ چند حالت دارد. دکمه وقتی موس رویش می‌رود باید بازخورد بدهد، و وقتی غیرفعال است باید فرق داشته باشد. این‌ها را — که از ترم ۵ می‌شناسی — کنارِ همان class تعریف کن، و یک modifier هم برای «دکمهٔ خطر» (حذف) بساز:

.btn:hover {
  background-color: #21567a;
}

.btn:disabled {
  background-color: #c9bfa8;
  cursor: not-allowed;
}

.btn--danger {
  background-color: #bc3e1c;
}

.btn--danger:hover {
  background-color: #9e3216;
}

چک کن: موس را روی «ذخیره» ببر — کمی تیره‌تر می‌شود. دکمهٔ «ارسال» که disabled است، خاکستریِ کم‌جان است و نشانگرِ موس رویش حالتِ «ممنوع» می‌گیرد. و «حذف» به‌خاطرِ btn--danger قرمز است. همهٔ این‌ها بخشی از همان component اند — یک تکه با چند حالت.

Checkpoint. قبل از ادامه، جواب بده: اگر یک دکمهٔ سبز برای «تأیید» بخواهی، کدام راه درست‌تر است — یک class کاملاً جدید به اسمِ .green-button، یا یک modifier به اسمِ .btn--confirm؟ (جواب: modifier؛ چون همان component است در یک حالتِ رنگیِ دیگر، پس همهٔ خوداتکاییِ .btn را به ارث می‌برد و فقط رنگش فرق می‌کند. یک class جدا یعنی دوباره‌نویسیِ همه‌چیز.)

۴. داخلت را داشته باش، بیرونت را نه#

یک نکتهٔ ظریف که component را واقعاً قابل‌جابه‌جایی می‌کند: component داخلِ خودش را مالک است، ولی فاصلهٔ بیرونش را نه. یعنی .btn باید padding خودش (فاصلهٔ داخلی، از لبهٔ دکمه تا متن) را داشته باشد، ولی نباید margin (فاصله تا همسایه) را در خودش بپزد.

چرا؟ چون فاصلهٔ بینِ دکمه‌ها به جایی بستگی دارد که دکمه نشسته، نه به خودِ دکمه. در نوار ابزار، فاصله را والد با gap: 12px می‌دهد؛ در پاصفحه شاید اصلاً فاصله‌ای لازم نباشد. اگر .btn یک margin ثابت با خودش حمل کند، در هر layout تازه با آن می‌جنگی. پس قانون ساده است: رنگ و padding و گوشه و حالت‌ها مالِ component؛ فاصلهٔ اطراف مالِ والد.

یک دکمه که فاصلهٔ داخلی‌اش — از لبه تا متن — با یک رنگ به‌عنوان مالِ خودِ دکمه مشخص شده، و فاصلهٔ بیرونی تا دکمهٔ کناری با رنگِ دیگری به‌عنوان مالِ ظرفِ دربرگیرنده نشان داده شده

💡 نکته: همین باعث می‌شود بتوانی دکمه را در نوار ابزار، فرم، کارت، یا پاصفحه بیندازی و هر بار والد فاصله‌گذاری‌اش را انجام دهد. component را مثلِ یک قطعهٔ لِگو بساز: خودش کامل است، و جای اتصالش را محیط تعیین می‌کند.

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

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

body {
  font-family: Tahoma, sans-serif;
  background-color: #f6edda;
  color: #2c2114;
  line-height: 1.7;
}

.toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 24px;
  background-color: #ffffff;
  border-block-end: 1px solid #d8ccae;
}

.toolbar__title {
  font-size: 1.2rem;
  margin-inline-end: auto;
}

.page {
  padding: 24px;
}

.page-footer {
  padding: 16px 24px;
  border-block-start: 1px solid #d8ccae;
}

/* ---------- component: btn ---------- */
.btn {
  font: inherit;
  background-color: #2a6b93;
  color: #ffffff;
  border: none;
  border-radius: 8px;
  padding: 8px 18px;
  cursor: pointer;
}

.btn:hover {
  background-color: #21567a;
}

.btn:disabled {
  background-color: #c9bfa8;
  cursor: not-allowed;
}

/* modifier: btn-e khatar */
.btn--danger {
  background-color: #bc3e1c;
}

.btn--danger:hover {
  background-color: #9e3216;
}

و index.html که همان .btn را در سه جای متفاوت به‌کار می‌برد:

<!-- 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>
    <header class="toolbar">
      <h1 class="toolbar__title">ویرایشگر</h1>
      <button class="btn">ذخیره</button>
      <button class="btn btn--danger">حذف</button>
      <button class="btn" disabled>ارسال</button>
    </header>
    <main class="page">
      <p>همان دکمه، این‌بار پایینِ محتوا و بیرون از نوار ابزار:</p>
    </main>
    <footer class="page-footer">
      <button class="btn">بازگشت به بالا</button>
    </footer>
  </body>
</html>

🤖 با AI: بعد از اینکه component ات را ساختی، کدِ CSS دکمه را به دستیار AI ات بده و بپرس «آیا این دکمه به هیچ استایلی از والدش وابسته است؟ اگر ببرمش به یک صفحهٔ دیگر، چیزی می‌شکند؟». جوابش را با آزمایش بسنج — دکمه را واقعاً به یک جای دیگر ببر و ببین. AI گاهی وابستگیِ پنهان (مثلِ رنگی که از body به ارث می‌رسد) را جا می‌اندازد، پس دیدن در آزمایشگاه حرفِ آخر را می‌زند.

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

کلمه تلفظ به حروف فارسی یعنی چه
component کامپوننت یک تکهٔ مستقلِ قابل‌تکرار، مثل یک دکمه یا کارت
self-contained سِلف-کانتِیند خوداتکا؛ همه‌چیزِ لازمش را خودش دارد، بی‌وابستگی به والد
state اِستِیت یک حالتِ component، مثل :hover یا :disabled
modifier مادیفایِر یک گونهٔ متفاوتِ همان component (.btn--danger)
portable پورتِبِل قابل‌جابه‌جایی؛ هرجای صفحه بگذاری‌اش کار می‌کند

تمرین‌ها

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

در فصل بعد#

الان می‌توانی هر تکهٔ صفحه را به‌شکلِ یک component مستقل بسازی. ولی وقتی چند component داری — دکمه، کارت، فرم — از کجا مطمئن شوی همه یک زبانِ بصری دارند؛ یک آبیِ واحد، یک مقیاسِ فاصلهٔ واحد، یک گوشهٔ گِردیِ واحد؟ فصل بعد یک design system کوچک می‌سازی: چند design token (رنگ و فاصله و فونت به‌شکلِ متغیرهای CSS، همان‌ها که در ترم ۲ ساختی) که همهٔ component هایت را یک‌دست و هماهنگ نگه می‌دارند.

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

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