در این نوشته می خوام ایجاد یک منوبار مثل منوبار مانایید رو آموزش بدم. برای یکی از پروژه های طراحی سایت میخواستم منویی طراحی کنم که وقتی کاربر موس رو روی لینکها میبره( hover کردن) یک خط متحرک زیر منو ها نمایش داده بشه. چالش پروژه این بود که تعداد آیتمهای داخل منو مشخص نبود و ممکن بود بعد از تحویل پروژه تغییر کنه پس استفاده از CSS به تنهایی چاره ساز نبود. اول از همه به سراغ افزونه lavalamp جی کوئری رفتم. بعد با خودم گفتم چرا باید برای یک قسمت کوچیک از پروژه از جی کوئری استفاده کنم؟ پس دست به کار شدم
کد های HTML
مثل همیشه با کد کذاری html شروع میکنیم. این بخش چیز خاصی نداره و فقط شامل کدهای استاندار html برای اینجاد یک منو ناوبری است.
<nav class="menu">
<ul class="menu__list">
<li class="menu__item"><a href="#" class="menu__link">Do you know</a></li>
<li class="menu__item"><a href="#" class="menu__link">About</a></li>
<li class="menu__item"><a href="#" class="menu__link">creative Agency</a></li>
<li class="menu__item"><a href="#" class="menu__link">Manaid?</a></li>
</ul>
</nav>
کدهای Css
چالش بعدی همینجاست. برای نشان دادن خط زیر منو باید از سودو کد before:: استفاده می کردم اما متاسفانه توسط جاوا اسکریپت نمیشه مستقیما به ویژگی ها سودوکدهای Css دسترسی داشت.
راه حل: تعریف دو متغیر در Css برای نگه داری عرض (width) و محل (position) خط زیر منو متناسب با لینک هاور شده است.
.menu__list {
--underline-width: 0; /* تعیین عرض اولیه */
--underline-offset-x: 0; /* تعیین موقعیت اولیه */
}
بعد از اون نوبت به استایل دهی به سودوکد before نگه دارنده لیست منو هاست. توجه داشته باشید که عرض و موقعیت (با استفاده از ویژگی translateX) خط زیر منو را توسط همان متغییرهایی که تعریف کردیم تعیین میکنیم. این متغیر ها در اصل واسطه ای برای تعیین ویژگی های سودو کد CSS توسط جاوا اسکریپت است.
.menu__list::before {
width: var(--underline-width); /* متغیر برای تعیین عرض خط*/
transform: translateX(var(--underline-offset-x)); /* متغیر برای تعیین موقعیت خط */
transition: transform 0.5s, width 0.5s;
}
کدهای Java Script
فقط سه گام دیگه مونده تا منوی ما کامل بشه؛ اول: باید چک کنیم کدوم آیتم منو در حالت انتخاب (Hover) قرار گرفته. دوم: موقعیت افقی اون آیتم و عرضش رو مشخص کنیم و سوم: مقادیر مورد نیاز را برای نگه دارنده لیست منوها (menu__list.) تعیین کنیم.
اول از همه باید منوی را در یک متغییر نگه داریم؛
const menu = document.querySelector('.menu__list');
بعد از اون باید یک رویداد (Event) mouseover برای اون تعریف کنیم
menu.addEventListener('mouseover', (event) => {
if (event.target.classList.contains('menu__link')) {
/* ...... */
}
});
داخل اون رویداد (Event) تعریف میکنیم که اگر آیتمی که موس روی اون رفته یکی از آیتمهای منو باشه عرض و موقعیت اون رو بگیر و در متغیرهای CSS که قبلا تعریف کردیم قرار بده:
menu.addEventListener('mouseover', (event) => {
if (event.target.classList.contains('menu__link')) {
menu.style.setProperty('--underline-width', `${event.target.offsetWidth}px`);
menu.style.setProperty('--underline-offset-x', `${event.target.offsetLeft}px`);
}
});
در آخر هم رویداد mouseleave ر و برای منو تعریف میکنیم که وقتی اجرا شد عرض خط زیر منو برابر با صفر بشه و در اصل دیگه نشون داده نشه
menu.addEventListener('mouseleave', () => {
menu.style.setProperty('--underline-width', '0')
});
جمع بندی:
نتیجه نهایی کار رو میتونی در پنل codepen ببینید
See the Pen
Attractive underline sliding menu by Manaid (@manaid)
on CodePen.