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

فصل ۵ از ۱۱

پیشرفت ترم
۰٪

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

SVG و آیکون

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

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

تا حالا هر تصویری که گذاشتی یک فایلِ .jpg یا .png بود که از بیرون می‌آمد. در این فصل نوعِ تازه‌ای از تصویر را می‌سازی که خودت داخلِ HTML می‌نویسی‌اش — یک نقاشیِ برداری که با کد ساخته می‌شود، هرقدر بزرگش کنی تیز و صاف می‌ماند، و مهم‌تر از همه، رنگش را CSS کنترل می‌کند. به این SVG می‌گویند. آخرِ فصل یک جفت دکمهٔ «پسند» و «ذخیره» داری که هرکدام یک آیکون دارند، و آیکون‌ها رنگِ متنِ دکمه را به ارث می‌برند — روی hover که رنگِ دکمه عوض می‌شود، آیکون هم با آن عوض می‌شود.

دو دکمهٔ گِرد کنار هم؛ دکمهٔ راست و آیکونِ قلبِ داخلش هر دو یک قرمزِ آجری‌اند، دکمهٔ چپ و آیکونِ ستارهٔ داخلش هر دو یک زردِ زعفرانی؛ رنگِ هر آیکون دقیقاً همرنگِ خطِ دورِ دکمهٔ خودش است

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

  • یک <svg> را مستقیم داخلِ HTML بنویسی و یک شکلِ ساده بکشی
  • فرقِ fill (رنگِ داخل) و stroke (رنگِ خط) را بفهمی و هرکدام را جدا کنترل کنی
  • یک آیکونِ واقعی را با یک <path> به دکمه اضافه کنی
  • با currentColor کاری کنی آیکون همیشه همرنگِ متنِ کنارش بماند

قبل از شروع#

  • از ترم ۲: رنگ با کدِ hex و color — همان رنگ‌ها را این‌بار به شکل هم می‌دهیم.
  • از فصل ۳ همین ترم: فکرِ component و کلاسِ modifier مثلِ .btn--like — دکمه‌ها را همان‌طور می‌سازیم.

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

۱. بردار در برابر عکس#

یک عکسِ معمولی — .jpg یا .png — از هزاران نقطهٔ رنگیِ ریز (pixel) ساخته شده. وقتی خیلی بزرگش کنی، همان نقطه‌ها بزرگ می‌شوند و تصویر پله‌پله و تار می‌شود. برای یک عکسِ کوه این خوب است، ولی برای یک آیکونِ ساده — یک قلب، یک ستاره، یک فلش — افتضاح است.

SVG جورِ دیگری کار می‌کند. به‌جای نقطه‌ها، یک دستورِ هندسی را نگه می‌دارد: «یک دایره اینجا، به این شعاع». مرورگر هر بار که لازم شود دوباره از روی همان دستور می‌کشدش — پس در هر اندازه‌ای تیز و صاف می‌ماند. برای آیکون‌ها و لوگوها دقیقاً همین را می‌خواهیم.

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

۲. یک <svg> درون‌خطی و یک شکل#

بهترین بخشِ SVG این است که مثلِ یک تصویرِ بیرونی نیست که با <img> صدایش بزنی؛ می‌توانی خودِ شکل را همین‌جا داخلِ HTML بنویسی. به این «SVG درون‌خطی» می‌گویند. بیا یک دایرهٔ ساده بکشیم. این را در آزمایشگاه امتحان کن:

<svg width="48" height="48" viewBox="0 0 24 24">
  <circle cx="12" cy="12" r="8" fill="#55731b" />
</svg>

یک دایرهٔ سبزِ کوچک می‌بینی. سه چیز اینجا مهم است. width و height اندازهٔ نمایشِ آیکون روی صفحه است. viewBox="0 0 24 24" یک صفحهٔ مختصاتِ ۲۴ در ۲۴ می‌سازد که همه‌چیز داخلش کشیده می‌شود — عددها مربوط به همین صفحه‌اند، نه به پیکسل. <circle> هم یک شکل است: مرکزش (cx, cy) و شعاعش (r).

💡 نکته: چون عددها به viewBox وصل‌اند نه به پیکسل، width را از 48 به 120 عوض کن: دایره بزرگ می‌شود ولی هیچ‌جایش تار نمی‌شود. همین جادوی بردار است.

۳. fill و stroke: داخل و خط#

هر شکلِ SVG دو رنگِ جدا دارد. fill رنگِ داخلِ شکل است، و stroke رنگِ خطِ دورِ آن. تا حالا فقط fill دادیم و یک دایرهٔ توپُر گرفتیم. حالا داخل را خالی کن و فقط خط بده:

<svg width="48" height="48" viewBox="0 0 24 24">
  <circle cx="12" cy="12" r="8" fill="none" stroke="#55731b" stroke-width="2" />
</svg>

چک کن: حالا به‌جای یک دایرهٔ توپُر، یک حلقه می‌بینی — چون fill="none" داخلش را خالی کرد و stroke فقط لبه را رنگ کرد. stroke-width هم کلفتیِ آن خط است. همین دو تنظیم، تفاوتِ یک آیکونِ توپُر و یک آیکونِ خطی است.

۴. آیکونِ واقعی با <path>#

<circle> و <rect> برای شکل‌های ساده خوب‌اند، ولی یک قلب یا یک ستاره را نمی‌شود با آن‌ها کشید. آیکون‌های واقعی تقریباً همیشه با یک تگِ دیگر ساخته می‌شوند: <path>. آن رشتهٔ طولانیِ حرف و عددِ داخلِ d یک مسیرِ نقاشی است — لازم نیست خودت بنویسی‌اش؛ از یک مجموعهٔ آیکونِ آماده کپی‌اش می‌کنی. این یک قلب است:

<svg viewBox="0 0 24 24" width="24" height="24">
  <path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" fill="#bc3e1c" />
</svg>

یک قلبِ قرمزِ آجری. fill اینجا هم دقیقاً همان کارِ دایره را می‌کند: رنگِ داخلِ شکل.

🤖 با AI: یک آیکونِ ساده که لازم داری — مثلاً یک زنگوله یا یک فلش — از دستیار AI ات بخواه به‌شکلِ یک <svg> درون‌خطی بدهد، و بپرس «هر تکهٔ این کد چه‌کار می‌کند؟». بعد در آزمایشگاه بچسبانش و با چشمِ خودت ببین واقعاً همان شکل درمی‌آید یا نه — مدل‌ها گاهی مسیری می‌سازند که شبیهِ چیزِ دیگری است.

۵. currentColor: آیکون رنگِ متن را بگیرد#

حالا بیا آیکون را داخلِ دکمه بگذاریم. فرض کن دکمهٔ «پسند» متنش قرمزِ آجری است، و ما هم قلب را fill="#2c2114" (یک قهوه‌ایِ تیره) گذاشته‌ایم:

<button class="btn btn--like" type="button">
  <svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
    <path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" fill="#2c2114" />
  </svg>
  پسند
</button>

نگاه کن: متنِ «پسند» قرمز است، ولی قلب تیرهٔ سیاه مانده و با متن جور نیست. بدتر اینکه اگر بعداً رنگِ دکمه را عوض کنی، این قلب همان تیره می‌ماند و باید دستی هم عوضش کنی.

🔧 اگر کار نکرد: رنگِ آیکون سِفت به یک کدِ رنگ چسبیده (fill="#2c2114")، پس هرچه رنگِ متن باشد، آیکون توجهی نمی‌کند. راهِ حل یک کلمهٔ جادویی است: fill را به currentColor عوض کن. currentColor یعنی «همان رنگی که متنِ اینجا دارد». آیکون از این به بعد رنگِ color دکمه را می‌گیرد:

<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" fill="currentColor" />

چک کن: حالا قلب دقیقاً همان قرمزِ متن شد. ماوس را ببر روی دکمه: color عوض می‌شود و قلب همراهش عوض می‌شود، بی‌آنکه یک خطِ اضافه بنویسی. currentColor آیکون را به رنگِ متن گره می‌زند — یک تعریف، یک رنگ، همه‌جا هماهنگ.

💡 نکته: آن aria-hidden="true" روی <svg> یعنی «این آیکون فقط تزئینی است، برای screen reader نخوانش» — چون کلمهٔ «پسند» کنارش خودش معنا را می‌رساند. فعلاً همین‌قدر بدان؛ در فصل ۶ (دسترس‌پذیری عمیق) کامل یادش می‌گیریم.

۶. کد کامل#

اول index.html با دو دکمه، هرکدام یک آیکونِ currentColor:

<!-- 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>SVG و آیکون</title>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <article class="card">
      <h1>یک عکس از کوه</h1>
      <p class="desc">این عکس را دوست داشتی؟ نشانش کن تا بعد پیدایش کنی.</p>
      <footer class="actions">
        <button class="btn btn--like" type="button">
          <svg class="icon" viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
            <path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" fill="currentColor" />
          </svg>
          پسند
        </button>
        <button class="btn btn--save" type="button">
          <svg class="icon" viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
            <path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" fill="currentColor" />
          </svg>
          ذخیره
        </button>
      </footer>
    </article>
  </body>
</html>

و styles.css — دقت کن که رنگِ آیکون هیچ‌جا جدا تعریف نشده؛ فقط color دکمه را می‌دهیم و currentColor بقیه‌اش را می‌سازد:

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

:root {
  --bg: #f6edda;
  --card: #ffffff;
  --ink: #2c2114;
  --muted: #6b6150;
  --like: #bc3e1c;
  --save: #a36207;
  --line: #d8ccae;
}

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

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

.card h1 {
  margin: 0 0 6px;
  font-size: 1.4rem;
}

.desc {
  margin: 0 0 18px;
  color: var(--muted);
}

.actions {
  display: flex;
  gap: 12px;
  margin: 0;
}

.icon {
  /* icon dar khat-e matn balaparin mimanad */
  vertical-align: middle;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  border: 1px solid currentColor;
  border-radius: 10px;
  background-color: transparent;
  font-family: inherit;
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
}

.btn--like {
  color: var(--like);
}

.btn--save {
  color: var(--save);
}

.btn:hover {
  color: var(--ink);
}

چک کن: دو دکمه می‌بینی، هرکدام با آیکونِ همرنگِ متنِ خودش — قلبِ قرمز، ستارهٔ زعفرانی. حتی خطِ دورِ دکمه هم currentColor است، پس همه‌چیزِ دکمه یک رنگ دارد. روی هرکدام ماوس ببر: کلِ دکمه، آیکون و خط با هم تیره می‌شوند.

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

کلمه تلفظ به حروف فارسی یعنی چه
SVG اِس‌وی‌جی تصویرِ برداری که با کد ساخته می‌شود و در هر اندازه تیز می‌ماند
viewBox ویوباکس صفحهٔ مختصاتِ داخلِ <svg> که شکل‌ها روی آن کشیده می‌شوند
path پَث تگی که با یک رشتهٔ مسیر (d) شکل‌های پیچیده مثلِ آیکون را می‌کشد
fill فیل رنگِ داخلِ یک شکلِ SVG
stroke اِستروک رنگِ خطِ دورِ یک شکلِ SVG
currentColor کارِنت‌کالر کلمه‌ای که یعنی «همان رنگِ متنِ اینجا»؛ آیکون را همرنگِ متن می‌کند

تمرین‌ها

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

در فصل بعد#

الان می‌توانی آیکون بسازی و رنگش را به متن گره بزنی. یک نکتهٔ ریز را هم دیدی که فصلِ بعد کامل می‌شود: روی آیکون‌ها aria-hidden="true" گذاشتیم تا screen reader آن‌ها را نخواند. فصل بعد یک فصلِ کاملِ دسترس‌پذیریِ عمیق است: مدیریتِ focus، اینکه ARIA کِی لازم است و کِی به‌جای کمک ضرر می‌زند، خواناییِ رنگ، و تستِ صفحه فقط با صفحه‌کلید.

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

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