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

فصل ۱ از ۱۱

پیشرفت ترم
۰٪

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

CSS را سازماندهی کن

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

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

تا اینجا کلی CSS بلدی — رنگ، فاصله، layout، حالت. ولی در یک پروژهٔ واقعی، مشکل دیگر «چطور این کار را بکنم؟» نیست؛ مشکل این است که فایلِ CSS ات بعد از دویست خط تبدیل می‌شود به یک انبارِ به‌هم‌ریخته که خودت هم تویش گم می‌شوی. این فصل دربارهٔ همان است: یک صفحهٔ کوچکِ فروشگاه با چند کارتِ محصول می‌سازی، و مهم‌تر از خروجی، stylesheet ای مرتب تحویل می‌دهی که شش ماه بعد هم بتوانی بخوانی‌اش.

یک stylesheet که به بخش‌های مرتب تقسیم شده: بالا یک بخش کوچک، بعد بخش پایه، بعد بخش چیدمان، و پایین بخش بزرگ‌ترِ component ها؛ سمتِ دیگر همان کد به‌هم‌ریخته و بدون بخش‌بندی

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

  • قاعده‌های CSS را در چند بخشِ منطقی (reset، base، layout، component) مرتب کنی
  • برای هر تکه یک نامِ class یک‌دست انتخاب کنی (قرارداد block و element و modifier)
  • بفهمی چرا دو قاعدهٔ تکراری با هم می‌جنگند و کدام برنده می‌شود
  • یک stylesheet را طوری بنویسی که ماه‌ها بعد هم قابل نگه‌داری باشد

قبل از شروع#

  • از ترم ۲: cascade — وقتی دو قاعده specificity برابر دارند، قاعدهٔ بعدی برنده می‌شود. این فصل دقیقاً روی همین می‌چرخد.
  • از ترم ۲: selector نوع و class و گروه‌کردن.
  • از ترم ۳: grid برای کنارِ‌هم‌چیدنِ کارت‌ها.

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

۱. یک stylesheet شلوغ#

فرض کن این CSS را برای کارت‌ها نوشته‌ای. قاعده‌ها بی‌ترتیب افتاده‌اند و یک نفر (خودت، دو هفتهٔ پیش) پایینش یک «اصلاحِ سریع» اضافه کرده:

.card__buy {
  background-color: #2a6b93;
  color: #ffffff;
  padding: 8px 16px;
}

.card {
  background-color: #ffffff;
  border: 1px solid #d8ccae;
  border-radius: 12px;
  padding: 16px;
}

.cards {
  list-style: none;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

/* yek tweak-e sari'e ke ba'dan ezafe shod */
.card {
  background-color: #e7ddc4;
}

به کارت‌ها نگاه کن: به‌جای سفید، بژِ کدر شده‌اند. تو که background-color: #ffffff نوشته بودی؛ پس چرا سفید نیست؟

🔧 اگر کار نکرد: دنبال اسمِ .card بگرد — دو بار تعریف شده. هر دو قاعده specificity برابر دارند (هر دو یک class اند)، پس همان قانونِ cascade از ترم ۲ تصمیم می‌گیرد: قاعده‌ای که بعد آمده برنده است. آن «اصلاحِ سریعِ» پایین، رنگِ سفید را با بژ عوض کرده و چون آخر است، برنده شده. راهِ درست: آن قاعدهٔ تکراری را پاک کن و برای هر selector فقط یک قاعده نگه‌دار.

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

۲. یک ترتیبِ منطقی#

CSS را الکی از بالا به پایین ننویس. قاعده‌ها را در چند بخش دسته‌بندی کن، همیشه به یک ترتیب — از عام به خاص:

  1. reset — صفرکردنِ چیزهای پیش‌فرضِ مرورگر (margin, padding, box-sizing).
  2. base — استایلِ پایهٔ خودِ صفحه: body، فونت، رنگِ متن، heading ها.
  3. layout — چیدمانِ بزرگ: جایی که grid و flex می‌چینی.
  4. component — تکه‌های قابل‌تکرار: کارت، دکمه، فرم.

چرا از عام به خاص؟ چون همان cascade: قاعده‌های عام باید اول بیایند تا قاعده‌های خاصِ بعدی بتوانند رویشان را بگیرند، نه برعکس. وقتی ترتیب طبیعی همین باشد، دیگر کمتر پیش می‌آید که ندانی چرا چیزی override شده.

💡 نکته: بین بخش‌ها یک کامنتِ عنوان بگذار، مثل /* ---------- layout ---------- */. این کامنت‌ها مثلِ تیترِ فصل‌های یک کتاب‌اند؛ وقتی فایل بلند می‌شود، با یک نگاه می‌فهمی هر چیز کجاست.

۳. یک نامِ یک‌دست برای class ها#

مشکلِ دومِ فایل‌های شلوغ، اسم‌گذاریِ سلیقه‌ای است: یکی .redButton، یکی .btn2، یکی .card-title-big. شش ماه بعد هیچ‌کدام معنا نمی‌دهند. یک قرارداد ساده و پرطرفدار این را حل می‌کند. سه نوع اسم داریم:

  • block — خودِ تکهٔ مستقل: .card.
  • element — جزئی درونِ آن block، با دو زیرخط: .card__title، .card__price.
  • modifier — یک حالتِ متفاوتِ همان block، با دو خط‌تیره: .card--featured (کارتِ ویژه).

از روی اسم .card__price بلافاصله می‌فهمی «قیمت، جزئی از کارت است»، و از .card--featured می‌فهمی «همان کارت، ولی در حالتِ ویژه». این‌ها را انگلیسی و بامعنا نگه‌دار؛ یک اسمِ خوب، نصفِ مستندسازی است.

یک کارت که کادرِ بیرونی‌اش به‌عنوان block رنگ خورده، دو ناحیهٔ درونی‌اش (عنوان و قیمت) با رنگِ متفاوت به‌عنوان element مشخص شده، و کنارش همان کارت در نسخهٔ ویژه با کادرِ نارنجی به‌عنوان modifier

⚠️ مواظب باش: این قرارداد را به‌عنوان قانونِ آهنین نگیر که برای هر <div> سه‌تا اسمِ عجیب بسازی. هدف خواناییِ توست، نه رعایتِ تشریفات. اگر یک اسمِ ساده کافی است، همان کافی است.

۴. همه را کنارِ هم: فایلِ مرتب#

حالا همان قاعده‌ها را در ترتیبِ درست، با اسم‌های یک‌دست و بدونِ تکراری بازنویسی می‌کنیم. این نسخهٔ نهاییِ styles.css است:

/* styles.css */

/* ---------- reset ---------- */
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

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

.page {
  max-width: 560px;
  margin-inline: auto;
  padding: 24px;
}

h1 {
  margin-block-end: 20px;
}

/* ---------- layout ---------- */
.cards {
  list-style: none;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

/* ---------- components ---------- */

/* card */
.card {
  background-color: #ffffff;
  border: 1px solid #d8ccae;
  border-radius: 12px;
  padding: 16px;
}

.card__title {
  font-size: 1.1rem;
  margin-block-end: 8px;
}

.card__price {
  color: #55731b;
  margin-block-end: 12px;
}

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

/* card--featured: kart-e vizhe */
.card--featured {
  border-color: #bc3e1c;
  background-color: #fff7ef;
}

و index.html که این class ها را به‌کار می‌برد:

<!-- 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 class="page">
      <h1>فروشگاه کوچک</h1>
      <ul class="cards">
        <li class="card card--featured">
          <h2 class="card__title">هدفون</h2>
          <p class="card__price">۲۵۰ هزار تومان</p>
          <button class="card__buy">خرید</button>
        </li>
        <li class="card">
          <h2 class="card__title">کیبورد</h2>
          <p class="card__price">۴۸۰ هزار تومان</p>
          <button class="card__buy">خرید</button>
        </li>
      </ul>
    </main>
  </body>
</html>

چک کن: دو کارتِ سفید کنارِ هم می‌بینی، اولی با کادرِ نارنجی و پس‌زمینهٔ کمی روشن‌تر (چون class اش card--featured است)، و هر کدام یک دکمهٔ آبیِ «خرید» دارند. حالا .card را در فایل جست‌وجو کن: فقط یک بار پیدا می‌شود. همان تکراریِ جنگ‌جو رفته، و کارت‌ها دوباره سفیدند.

Checkpoint. قبل از ادامه، جواب بده: اگر دوباره یک قاعدهٔ دومِ .card با رنگِ متفاوت، ولی این‌بار بالای قاعدهٔ اصلی بگذاری، کارت چه رنگی می‌شود؟ (جواب: رنگِ قاعدهٔ اصلی، چون آن پایین‌تر است و در برابریِ specificity، بعدی برنده است. به همین دلیل جای هر قاعده مهم است.)

🤖 با AI: بعد از اینکه خودت فایل را مرتب کردی، اسم‌های class ات را به دستیار AI ات بده و بپرس «این اسم‌ها با قرارداد block/element/modifier یک‌دست‌اند؟ کدام گنگ است؟». جوابش را با معیارِ خودت بسنج — هر اسمی که خودت با یک نگاه نمی‌فهمی، واقعاً بد است؛ ولی پیشنهادهای AI را هم خط‌به‌خط چک کن، چون گاهی برای سادگی، اسمِ خوبِ تو را بی‌دلیل پیچیده‌تر می‌کند.

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

کلمه تلفظ به حروف فارسی یعنی چه
reset ری‌سِت بخشِ اولِ CSS که پیش‌فرض‌های مرورگر را صفر می‌کند
base بیس استایلِ پایهٔ صفحه: body، فونت، heading
block بلاک یک تکهٔ مستقل، مثل .card
element اِلِمِنت جزئی درونِ یک block، با __ (مثل .card__title)
modifier مادیفایِر یک حالتِ متفاوتِ block، با -- (مثل .card--featured)
maintainable مِین‌تِین‌اِبِل کدی که ماه‌ها بعد هم راحت خوانده و عوض می‌شود

تمرین‌ها

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

در فصل بعد#

الان می‌توانی CSS ات را با دست مرتب کنی. ولی وقتی پروژه بزرگ می‌شود، حتی نظمِ دستی هم کم می‌آورد و باز سرِ اینکه «کدام قاعده برنده شود» با specificity می‌جنگی. فصل بعد دو ابزارِ تازه یاد می‌گیری که همین را در مقیاسِ بزرگ حل می‌کنند: @layer که به تو اجازه می‌دهد ترتیبِ برنده‌شدن را خودت تعیین کنی — حتی بالاتر از specificity — و nesting که قاعده‌های مربوط به هم را تودرتو و کنارِ هم نگه می‌دارد.

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

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