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

فصل ۶ از ۸

پیشرفت ترم
۰٪

ترم ۴ · Responsive

ناوبری responsive

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

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

منوی بالای سایت روی دسکتاپ راحت یک ردیفِ لینک است، ولی روی موبایل جا نمی‌شود و به‌هم می‌ریزد. راهِ حلِ همه‌جا این است که در صفحهٔ کوچک، لینک‌ها پشتِ یک دکمهٔ «منو» جمع شوند و با یک ضربه باز شوند. در این فصل یاد می‌گیری این منوی بازشو را بدونِ یک خط JavaScript بسازی — فقط با دو tag که خودِ HTML برای همین دارد: <details> و <summary>. و مهم‌تر، طوری بسازی‌اش که با صفحه‌کلید هم کاملاً کار کند.

مقایسهٔ دو حالت از یک منو: در صفحهٔ پهن یک ردیفِ افقی از چند لینک، و در صفحهٔ باریک همان لینک‌ها جمع‌شده پشتِ یک دکمهٔ منو با یک مثلثِ کوچکِ بازشو

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

  • یک منوی بازشو با <details> و <summary> بسازی که بدونِ JavaScript کار کند
  • بگویی چرا یک <div> نمی‌تواند دکمهٔ منو باشد، حتی اگر شبیهش باشد
  • منو را با صفحه‌کلید (Tab و Enter) باز و بسته کنی و focus را نشکنی
  • با @media منو را در دسکتاپ افقی و در موبایل عمودی کنی

قبل از شروع#

  • از فصل ۲ (همین ترم): @media و min-width — برای فرقِ موبایل و دسکتاپ.
  • از ترم ۱: <nav>، <ul>/<li> و لینک‌ها — منو یک فهرست از لینک‌هاست.
  • از ترم ۳: flexbox — برای سرصفحه و ردیفِ افقیِ لینک‌ها.

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

۱. مشکل: منوی افقی در صفحهٔ کوچک#

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

۲. تلاشِ اشتباه: دکمه‌ای که دکمه نیست#

اولین چیزی که به ذهن می‌رسد این است که یک کادر با نوشتهٔ «منو» بسازیم. شاید وسوسه شوی یک <div> برداری:

<nav>
  <div class="toggle">منو</div>
  <ul>
    <li><a href="#home">خانه</a></li>
    <li><a href="#lessons">درس‌ها</a></li>
  </ul>
</nav>

روی صفحه، این «منو» شبیهِ یک دکمه است. ولی امتحانش کن: رویش کلیک کن — هیچ اتفاقی نمی‌افتد. حالا سعی کن با کلیدِ Tab به آن برسی — نمی‌شود؛ انگشتِ صفحه‌کلید از رویش رد می‌شود و اصلاً بهش نمی‌رسد. این کادر فقط شبیهِ دکمه است، ولی هیچ کاری نمی‌کند.

🔧 اگر کار نکرد: یک <div> یک جعبهٔ بی‌معناست (از ترم ۱ یادت هست)؛ مرورگر آن را یک کنترلِ قابلِ فشردن نمی‌داند، پس نه در مسیرِ Tab می‌گذاردش، نه به Enter جواب می‌دهد، و نه screen reader آن را «دکمه» اعلام می‌کند. از همه بدتر: بازوبسته‌کردنِ لیست کارِ رفتار است، و رفتار بدونِ JavaScript از یک <div> درنمی‌آید — JavaScript را هم تا ترم ۷ نداریم. پس این راه بن‌بست است. خبرِ خوب: HTML یک جفت tag دارد که این منوی بازشو را بدونِ هیچ کدی می‌سازد. سراغِ همان می‌رویم.

۳. <details> و <summary>: منوی بازشو بدونِ کد#

<details> یک جعبهٔ بازشوست که خودِ مرورگر بلد است باز و بسته‌اش کند. داخلش یک <summary> می‌گذاری که همیشه دیده می‌شود — این همان دکمهٔ ماست — و بقیهٔ محتوا فقط وقتی باز است دیده می‌شود. لینک‌ها را داخلش بگذار:

<nav>
  <details class="menu">
    <summary>منو</summary>
    <ul>
      <li><a href="#home">خانه</a></li>
      <li><a href="#lessons">درس‌ها</a></li>
      <li><a href="#about">درباره</a></li>
      <li><a href="#contact">تماس</a></li>
    </ul>
  </details>
</nav>

چک کن: حالا یک دکمهٔ «منو» با یک مثلثِ کوچک می‌بینی. رویش کلیک کن: لیستِ لینک‌ها باز می‌شود؛ دوباره کلیک کن: بسته می‌شود. هیچ CSS و هیچ JavaScript ای برای این بازوبسته‌شدن ننوشتی — خودِ <details> این رفتار را دارد.

حالا مهم‌ترین آزمون را بده: دستت را از ماوس بردار. کلیدِ Tab را بزن تا focus به «منو» برسد (یک قابِ نازک دورش ظاهر می‌شود که می‌گوید «الان اینجایی»)، بعد Enter یا Space را بزن. منو باز می‌شود. <summary> از پایه یک کنترلِ واقعی است: در مسیرِ Tab هست، به صفحه‌کلید جواب می‌دهد، و screen reader هم می‌گوید «باز» یا «بسته». این دقیقاً همان چیزی است که <div> نداشت.

⚠️ مواظب باش: آن قابِ نازکِ دورِ «منو» موقعِ Tab را هیچ‌وقت با outline: none پاک نکن. تنها راهنمای کسی که با صفحه‌کلید کار می‌کند همین است که بداند کجای صفحه است؛ برداشتنش یعنی او را کور کردن. اگر ظاهرش را دوست نداری، عوضش کن، ولی حذفش نکن.

۴. responsive: عمودی در موبایل، افقی در دسکتاپ#

الان منو در هر عرضی یک لیستِ عمودی باز می‌کند. برای موبایل عالی است. در دسکتاپ که جا زیاد است، بیا لیستِ باز را یک ردیفِ افقی کنیم تا مثلِ یک نوارِ منو دیده شود. این کارِ @media است — لیست را در عرضِ پهن flex می‌کنیم:

@media (min-width: 700px) {
  .menu ul {
    display: flex;
    gap: 6px;
    padding: 6px;
  }
}

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

💡 نکته: پاک‌ترین کاری که پیدا کردی این است که در موبایل و دسکتاپ یک فهرستِ لینک داری، نه دو تا. اگر برای دسکتاپ یک منو و برای موبایل یک منوی دیگر بسازی، هم کد دوتا می‌شود هم screen reader دو بار لینک‌ها را می‌خواند. یک منبع، یک منو.

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

اول 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>ناوبری responsive</title>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <header class="site-header">
      <a class="logo" href="#">تاروپود</a>
      <nav>
        <details class="menu">
          <summary>منو</summary>
          <ul>
            <li><a href="#home">خانه</a></li>
            <li><a href="#lessons">درس‌ها</a></li>
            <li><a href="#about">درباره</a></li>
            <li><a href="#contact">تماس</a></li>
          </ul>
        </details>
      </nav>
    </header>

    <main class="page">
      <h1>یک منوی responsive بدونِ JavaScript</h1>
      <p>روی «منو» بزن تا باز و بسته شود — با ماوس و با صفحه‌کلید. بعد پنجره را پهن و باریک کن و ببین منو از حالتِ عمودی به یک ردیفِ افقی می‌رود.</p>
    </main>
  </body>
</html>

و styles.css:

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

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

.site-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 14px 20px;
  background-color: #ffffff;
  border-block-end: 1px solid #d8ccae;
}

.logo {
  font-weight: 700;
  font-size: 1.3rem;
  color: #2a6b93;
}

/* summary = dokme-ye baz/baste kardan-e menu */
.menu summary {
  width: max-content;
  cursor: pointer;
  padding: 8px 14px;
  border: 1px solid #d8ccae;
  border-radius: 8px;
  font-weight: 700;
}

.menu ul {
  list-style: none;
  margin-block: 10px 0;
  margin-inline: 0;
  padding: 8px;
  background-color: #ffffff;
  border: 1px solid #d8ccae;
  border-radius: 10px;
}

.menu a {
  display: block;
  padding: 10px;
  border-radius: 6px;
  color: #2c2114;
}

.page {
  padding: 24px 20px;
}

/* dar safheye pahn, list-e baz-shode radifi mishavad */
@media (min-width: 700px) {
  .menu ul {
    display: flex;
    gap: 6px;
    padding: 6px;
  }
}

💡 نکته: سه property اینجا اولین‌بار به‌کار رفته‌اند: list-style: none گلوله‌های <ul> را برمی‌دارد تا منو دیگر فهرستِ نقطه‌دار به‌نظر نرسد، cursor: pointer روی <summary> نشانگرِ ماوس را دست می‌کند تا پیدا باشد کلیک‌کردنی است، و width: max-content دکمه را دقیقاً هم‌اندازهٔ متنش می‌کند نه تمامِ عرض.

یک دکمهٔ «منو» با یک قابِ نازکِ focus دورش که نشانِ رسیدنِ صفحه‌کلید است، و کنارش دو حالتِ باز و بستهٔ جعبهٔ بازشو با فلشِ چرخشی بین‌شان

🤖 با AI: از دستیار AI ات بپرس «چه فرقی هست بین دکمهٔ منو با <div> و با <summary> از نظرِ دسترس‌پذیری؟». جوابش را با چیزی که خودت همین فصل دیدی بسنج: <div> در مسیرِ Tab نیست و به Enter جواب نمی‌دهد، <summary> هست و می‌دهد. و همان‌جا در آزمایشگاه هر دو را با صفحه‌کلید امتحان کن — دیدن، از شنیدن مطمئن‌تر است.

نکتهٔ صادقانه: تنها کاری که این منو در دسکتاپ نمی‌کند این است که خودش از اول باز باشد؛ کاربر باید «منو» را بزند. اینکه در صفحهٔ بزرگ منو خودبه‌خود باز و افقی باشد و در موبایل جمع، به یک تکه رفتار نیاز دارد که فقط با JavaScript می‌آید — این را در ترم ۷ یاد می‌گیریم. ولی همین منوی امروزی، بدونِ یک خط کد، برای همه — با ماوس، با صفحه‌کلید، با screen reader — کار می‌کند، و این خودش یک برد است.

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

کلمه تلفظ به حروف فارسی یعنی چه
<details> دیتِیلز جعبهٔ بازشو که مرورگر خودش باز و بسته‌اش می‌کند، بدونِ کد
<summary> سامِری بخشِ همیشه‌دیدهٔ <details> که با کلیک یا صفحه‌کلید بازش می‌کند
focus فوکِس جایی از صفحه که صفحه‌کلید الان روی آن است؛ با یک قابِ نازک دیده می‌شود
outline اوت‌لاین همان قابِ focus؛ هیچ‌وقت بی‌جایگزین حذفش نکن

تمرین‌ها

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

در فصل بعد#

الان می‌توانی یک منوی بازشوی دسترس‌پذیر بدونِ کد بسازی. فصل بعد سراغِ چیزی می‌رویم که این روزها هر سایتی انتظارش را دارد: dark mode. یاد می‌گیری بفهمی کاربر تمِ روشن خواسته یا تیره (prefers-color-scheme)، و با همان custom property هایی که در ترم ۲ ساختی، کلِ سایت را با چند خط بین روشن و تیره جابه‌جا کنی — طوری که رنگ‌ها همیشه خوانا بمانند.

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

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