طراحی وب

طراحی Header وب‌سایت؛ پیمایش، منو و رفتار Responsive

وظایف Header، Navigation معنایی، Disclosure، Skip Link و تفاوت Sticky و Fixed را بشناسید؛ همراه نمونه کامل منوی Responsive با مدیریت Focus.

1404/11/27 4 دقیقه مطالعه 1,852 بازدید

کاربر از یک نتیجه جست‌وجو وارد صفحه داخلی سایت می‌شود. Header باید کمک کند بفهمد کجاست، به بخش مرتبط برود و در صورت نیاز مسیر اصلی را پیدا کند. اگر Header فقط مجموعه‌ای از لوگو، دکمه و Icon باشد، این وظیفه روشن نمی‌شود. طراحی آن را با ساختار اطلاعات و کارهای پرتکرار شروع کنید؛ همه سایت‌ها به جست‌وجو، Mega Menu یا دکمه خرید در بالای صفحه نیاز ندارند.

جای لوگو، تعداد لینک‌ها و استفاده از Header ثابت قانون مشترک همه پروژه‌ها نیستند. یک فروشگاه بزرگ و سایت معرفی یک تیم، نیازهای متفاوتی دارند. قرارگرفتن لوگو در جای آشنا می‌تواند به تشخیص برند کمک کند، اما جایگاه به‌تنهایی تجربه مناسب را تضمین نمی‌کند. Header باید در صفحه داخلی، روی نمایشگر کوچک، با متن بلند و هنگام استفاده صفحه‌کلید هم قابل فهم بماند.

وظایف Header را محدود و اولویت‌بندی کنید

ابتدا بنویسید کدام کار باید از همه صفحه‌ها در دسترس باشد. ممکن است مرور خدمات، یافتن محصول، ورود به حساب یا تماس باشد. اگر هر درخواست داخلی تیم به Header اضافه شود، همه لینک‌ها هم‌وزن می‌شوند. اطلاعات کم‌تکرار می‌تواند در Footer یا صفحه مرتبط باشد. تصمیم حذف یا جابه‌جایی باید بر نقش آن در مسیر کاربر تکیه کند، نه صرفاً جا شدن در یک ردیف.

Navigation با اقدام اصلی فرق دارد. لینک «خدمات» به مرور اطلاعات می‌برد و دکمه «ثبت درخواست» شروع یک کار است. این تفاوت را در متن و طراحی نشان دهید، ولی برجسته‌کردن اقدام اصلی نباید آن را مبهم کند. «شروع کنید» ممکن است در زمینه‌ای روشن باشد، اما در صفحه‌ای دیگر مقصد را توضیح ندهد. اسم کنترل باید با کاری که بعد از انتخاب رخ می‌دهد هماهنگ باشد.

ساختار معنایی را از ظاهر جدا نکنید

راهنمای ساختار منو در W3C استفاده از Navigation معنایی و فهرست لینک‌ها را توضیح می‌دهد. nav برای مشخص‌کردن ناحیه پیمایش مفید است و در صورت وجود چند Navigation، نام‌های روشن به تفکیک آن‌ها کمک می‌کنند. یک div با رویداد کلیک جای لینک واقعی را نمی‌گیرد. مقصد لینک باید معتبر باشد و متن آن بدون حدس توضیح دهد کاربر به کجا می‌رود.

راهنمای ناحیه‌های صفحه نقش Header و محتوای اصلی را شرح می‌دهد. لوگوی تصویری که به خانه لینک می‌شود باید نام قابل فهم داشته باشد. اگر متن برند کنار تصویر قرار دارد، از تکرار بی‌دلیل نام برای ابزار کمکی جلوگیری کنید. برای یک Navigation معمول سایت، افزودن role="menu" الزام نیست؛ این Role قرارداد تعاملی دیگری دارد و نباید صرفاً به خاطر کلمه «منو» انتخاب شود.

Dropdown باید رفتار کامل داشته باشد

اگر زیرمنو لازم است، مشخص کنید کنترل بازکننده لینک است یا دکمه. Hover به‌تنهایی برای لمس و صفحه‌کلید کافی نیست. حالت باز و بسته، محل Focus و رفتار Escape باید روشن باشند. الگوی Disclosure Navigation در APG برای فهم این تفاوت مفید است. استفاده از aria-expanded به‌تنهایی محتوایی را پنهان نمی‌کند؛ State، Markup و نمایش باید هماهنگ شوند.

اگر عنوان دسته خودش صفحه دارد، تصمیم درباره کلیک و بازکردن زیرمنو را واضح کنید. یک کنترل که گاهی می‌رود و گاهی باز می‌کند، ممکن است گیج‌کننده باشد. همچنین بخش بسته نباید کنترل قابل Focus پنهان باقی بگذارد. در هنگام بستن، کاربری که داخل زیرمنو بوده باید به جای معناداری منتقل شود. این موضوع در تغییر Breakpoint هم دیده می‌شود؛ Resize فقط تغییر ظاهر نیست و می‌تواند وضعیت Focus را تحت تأثیر قرار دهد.

نسخه کوچک را با همان محتوا طراحی کنید

Navigation در نمایشگر کوچک می‌تواند جمع شود، ولی ترتیب، متن و مقصدها نباید بدون دلیل تغییر کنند. یک گزینه مهم را فقط برای خالی‌کردن فضا حذف نکنید. اگر نام‌ها بلندند، Wrap یا ساختار متفاوت را بررسی کنید. راهنمای Mobile-first انتخاب Breakpoint بر اساس محتوا را توضیح می‌دهد. عدد انتخابی نمونه پایین برای همان لینک‌های کوتاه است و معیار همه Headerها محسوب نمی‌شود.

یک منوی کوچک باز باید به فضای لازم دسترسی داشته باشد. اگر آن را Modal می‌کنید، قرارداد Focus و Scroll متفاوت خواهد بود. اگر فقط یک بخش در جریان صفحه باز می‌شود، نباید رفتار Modal را ناقص تقلید کنید. نمونه این مقاله یک Disclosure ساده در جریان صفحه است؛ Overlay، Trap Focus و Mega Menu ندارد. همین محدوده مشخص، خواننده را از برداشت اشتباه درباره قابلیت‌های نمونه دور می‌کند.

نمونه کامل: Header با Navigation جمع‌شونده

فایل زیر را با نام index.html ذخیره کنید و در مرورگر باز کنید. Library، تصویر، فونت یا Build لازم ندارد. سه لینک به بخش‌های واقعی همان فایل می‌روند. بدون JavaScript، Navigation باز و قابل استفاده است. با JavaScript، در عرض کوچک دکمه باز و بسته‌کردن نمایش داده می‌شود و در عرض بزرگ لینک‌ها دیده می‌شوند. Header این نمونه ثابت یا Sticky نیست تا رفتار پایه با پوشاندن محتوا مخلوط نشود.

<!doctype html>
<html lang="fa" dir="rtl">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1">
  <title>نمونه Header</title>
  <style>
    * { box-sizing: border-box; }
    [hidden] { display: none !important; }
    body { margin: 0; font: 1rem/1.8 sans-serif; color: #172638; background: #f5f7fb; }
    a { color: #164d85; }
    .skip { position: absolute; inset-inline-start: 1rem; top: -10rem; padding: .7rem; background: white; z-index: 10; }
    .skip:focus { top: 1rem; }
    header { background: white; border-block-end: 1px solid #65788b; }
    .header-inner { max-inline-size: 70rem; margin-inline: auto; padding: 1rem;
      display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 1rem; }
    .brand { font-weight: bold; }
    ul { display: flex; flex-wrap: wrap; gap: .5rem; list-style: none; margin: 0; padding: 0; }
    nav a { display: block; padding: .55rem .8rem; }
    button { font: inherit; padding: .55rem .8rem; background: #164d85; color: white; border: 2px solid #164d85; }
    :is(a, button):focus-visible { outline: 3px solid #8a3500; outline-offset: 3px; }
    main { max-inline-size: 55rem; margin-inline: auto; padding: 1.5rem; }
    section { margin-block: 3rem; padding: 1rem; background: white; }
    @media (max-width: 51.99rem) { nav { inline-size: 100%; } nav ul { flex-direction: column; } }
  </style>
</head>
<body>
  <a class="skip" href="#main">رفتن به محتوای اصلی</a>
  <header id="header"><div class="header-inner">
    <a class="brand" href="#main">برند نمونه</a>
    <button id="toggle" type="button" aria-controls="navigation" aria-expanded="false" hidden>نمایش مسیرها</button>
    <nav id="navigation" aria-label="پیمایش اصلی"><ul>
      <li><a href="#services">خدمات</a></li><li><a href="#about">درباره تیم</a></li>
      <li><a href="#contact">تماس</a></li>
    </ul></nav>
  </div></header>
  <main id="main" tabindex="-1">
    <h1>Header با رفتار مشخص</h1>
    <p>لینک‌ها به بخش‌های موجود همین فایل می‌روند؛ این نمونه منوی Modal یا Sticky ندارد.</p>
    <section id="services" tabindex="-1"><h2>خدمات</h2><p>توضیح خدمات فرضی در این بخش قرار می‌گیرد.</p></section>
    <section id="about" tabindex="-1"><h2>درباره تیم</h2><p>نقش و سابقه واقعی تیم در نسخه محصول نمایش داده می‌شود.</p></section>
    <section id="contact" tabindex="-1"><h2>تماس</h2><p>این نمونه فرم تماس یا ارسال داده ندارد.</p></section>
  </main>
  <script>
    const header = document.getElementById('header');
    const toggle = document.getElementById('toggle');
    const nav = document.getElementById('navigation');
    const wide = matchMedia('(min-width: 52rem)');
    let open = false;
    function renderMenu() {
      const small = !wide.matches;
      const focusOnToggle = document.activeElement === toggle;
      toggle.hidden = !small;
      const hideNav = small && !open;
      if (hideNav && nav.contains(document.activeElement)) toggle.focus();
      nav.hidden = hideNav;
      toggle.setAttribute('aria-expanded', String(small && open));
      toggle.textContent = open && small ? 'بستن مسیرها' : 'نمایش مسیرها';
      if (!small && focusOnToggle) nav.querySelector('a').focus();
    }
    toggle.addEventListener('click', () => { open = !open; renderMenu(); });
    header.addEventListener('keydown', event => {
      if (event.key === 'Escape' && open && !wide.matches) {
        event.preventDefault(); open = false; renderMenu(); toggle.focus();
      }
    });
    nav.addEventListener('click', event => {
      const link = event.target.closest('a');
      if (!link || wide.matches) return;
      const target = document.getElementById(link.getAttribute('href').slice(1));
      if (!target) return;
      event.preventDefault(); open = false; renderMenu();
      target.focus(); target.scrollIntoView();
      history.replaceState(null, '', link.getAttribute('href'));
    });
    wide.addEventListener('change', () => { open = false; renderMenu(); });
    renderMenu();
  </script>
</body>
</html>

در این فایل، button وضعیت aria-expanded را اعلام می‌کند و aria-controls به nav موجود اشاره دارد. hidden هم نمایش و هم دسترسی معمول به بخش بسته را کنترل می‌کند. Escape در محدوده Header منوی کوچک را می‌بندد و Focus را به دکمه برمی‌گرداند. هنگام تغییر عرض، Focus کنترل پنهان‌شده مدیریت می‌شود. این نمونه یک مبنای آموزشی است؛ افزودن زیرمنو، جست‌وجو یا حساب کاربری نیاز به قراردادهای تازه دارد.

Skip Link مسیر تکراری را کوتاه می‌کند

کاربر صفحه‌کلید ممکن است در هر صفحه با همان لینک‌های Header مواجه شود. معیار Bypass Blocks درباره امکان عبور از بخش‌های تکراری توضیح می‌دهد. Skip Link در نمونه به محتوای اصلی می‌رود و هنگام Focus دیده می‌شود. پنهان‌کردن دائمی آن با display:none کار موردنظر را انجام نمی‌دهد؛ کنترل باید برای استفاده واقعی قابل دسترسی باشد.

مقصد Skip Link نیز باید درست باشد. اگر به یک شناسه ناموجود یا بخش تبلیغاتی اشاره کند، ظاهر لینک مسئله را حل نمی‌کند. نام و محل Main را در همه Templateهای سایت هماهنگ کنید. این هماهنگی در صفحه محصول، مقاله و تماس مهم است. در راهنمای Design System می‌توان قرارداد مشترک Header و استثناهای صفحه‌ها را ثبت کرد تا هر Template رفتار جدا نسازد.

Sticky و Fixed رفتار یکسان ندارند

مستند position تفاوت موقعیت‌های CSS را توضیح می‌دهد. Header ثابت از جریان معمول بیرون می‌رود و نیاز به جبران فضای محتوا دارد؛ Sticky به زمینه Scroll و شرایط Layout وابسته است. انتخاب آن‌ها را با نیاز دسترسی مداوم بسنجید. برای صفحه‌ای با Header بسیار بلند، اشغال بخش بزرگی از ارتفاع نمایشگر می‌تواند هزینه بیشتری از منفعت آن داشته باشد.

معیار Focus Not Obscured حداقل درباره پنهان‌نشدن کامل عنصر دارای Focus زیر محتوای ساخته‌شده سایت است. برای Header شناور، مقصد Anchor و کنترل‌های زیر آن را هم در نظر بگیرید. scroll-margin می‌تواند در قرارداد فاصله پیمایش مفید باشد، اما ارتفاع متغیر Header را نباید همیشه یک عدد ثابت فرض کرد.

جست‌وجو و حساب کاربری را فقط در صورت نیاز اضافه کنید

جست‌وجو در سایت بزرگ می‌تواند مسیر مهمی باشد، ولی در یک صفحه کوتاه ممکن است فقط کنترل اضافه بسازد. اگر وجود دارد، Label، محدوده جست‌وجو، نتیجه خالی و خطا را مشخص کنید. راهنمای Label کنترل‌ها برای این بخش مرتبط است. Icon ذره‌بین بدون نام کافی، قرارداد کامل فیلد و دکمه نیست. نتیجه باید به محتوای واقعی متصل باشد.

حساب کاربری، زبان و سبد خرید هم وضعیت دارند. تعداد سبد باید از داده معتبر بیاید و ورود موفق باید در رابط معلوم باشد. تغییر زبان باید به نسخه متناظر برسد؛ راهنمای سایت چندزبانه این رفتار را توضیح می‌دهد. اضافه‌کردن چند Icon کوچک در یک گوشه بدون نام، اولویت و وضعیت، فقط فضا را پر می‌کند. هر کنترل باید دلیل و مسیر ادامه داشته باشد.

تحویل Header را با حالت‌ها کامل کنید

برای تیم اجرا، حالت عادی، Focus، منوی باز، زبان دوم، عنوان بلند و عرض کوچک را ثبت کنید. مشخص کنید کدام کنترل‌ها همیشه حاضرند و کدام به وضعیت حساب یا صفحه وابسته‌اند. مقصدها و متن‌ها باید با ساختار واقعی سایت هماهنگ باشند. Header شفاف روی تصویر نیز برای هر پس‌زمینه خوانایی یکسان ندارد؛ اگر این انتخاب را دارید، حالت بدون تصویر یا تصویر متفاوت را هم در برنامه بررسی بگذارید.

معیار مناسب، یافتن مسیر و کامل‌کردن کار کاربر است. تعداد کمتر لینک‌ها همیشه بهتر نیست و Header پیچیده هم همیشه نامناسب نیست؛ نیاز اطلاعاتی محصول را مبنا قرار دهید. از یک ساختار معنایی روشن شروع کنید، رفتارها را کامل کنید و افکت‌های ظاهری را پس از آن انتخاب کنید. قرارداد پایدار Header در چند Template، برای کاربر و تیم نگهداری از یک طرح نمایشی تک‌صفحه‌ای مفیدتر است.

واکنش به این مقاله

اشتراک‌گذاری این مقاله:
دیدگاه‌ها 0
۰ / ۲۰۰۰

هنوز دیدگاهی ثبت نشده

اولین نفری باشید که نظر می‌دهد!