點燈坊

失くすものさえない今が強くなるチャンスよ

Creating Responsive Auto-hidden Navbar

Sam Xiao's Avatar 2022-01-08

Responsive auto-hidden Navbar is the essential component in every modern Web design. This can be done by only Alpine and TailwindCSS without any package.

Version

Alpine 3.9
TailwindCSS 3.0

Desktop

hide000

  • When scrolling down, the Navbar is hidden
  • When scrolling up, the Navbar is shown

Mobile

hide001

  • When scrolling down, the Navbar is hidden
  • When scrolling up, the Navbar is shown
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script src="https://unpkg.com/alpinejs" defer></script>
    <script src="https://cdn.tailwindcss.com"></script>
    <title>Navbar</title>
  </head>
  <body
    x-data="{ isShowNav: true, scrollY_: 0 }"
    @scroll.window="isShowNav = scrollY_ > scrollY; scrollY_ = scrollY"
  >
    <nav
      x-data="{ isShowMobileMenu: false }"
      class="fixed left-0 top-0 w-full bg-gray-800 transition duration-500"
      :class="isShowNav || '-translate-y-full'"
    >
      <!-- Desktop Navbar -->
      <div class="mx-auto max-w-7xl px-2 sm:px-4">
        <div class="flex h-16 items-center justify-between">
          <!-- Logo & menu -->
          <div class="flex items-center px-2 md:px-0">
            <!-- Logo -->
            <div class="shrink-0">
              <img
                class="block h-8 md:hidden"
                src="https://tailwindui.com/img/logos/workflow-mark-indigo-500.svg"
                alt="Workflow"
              />
              <img
                class="hidden h-8 md:block"
                src="https://tailwindui.com/img/logos/workflow-logo-indigo-500-mark-white-text.svg"
                alt="Workflow"
              />
            </div>
            <!-- Menu -->
            <div class="hidden md:ml-6 md:block">
              <div x-data="{ selected: 'archive' }" class="flex space-x-4">
                <a
                  href="#"
                  @click="selected = 'archive'"
                  class="rounded-md px-3 py-2 text-sm font-medium"
                  :class="selected === 'archive' ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'"
                  >Archive</a
                >
                <a
                  href="#"
                  @click="selected = 'series'"
                  class="rounded-md px-3 py-2 text-sm font-medium"
                  :class="selected === 'series' ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'"
                  >Series</a
                >
                <a
                  href="#"
                  @click="selected = 'tags'"
                  class="rounded-md px-3 py-2 text-sm font-medium"
                  :class="selected === 'tags' ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'"
                  >Tags</a
                >
                <a
                  href="#"
                  @click="selected = 'rss'"
                  class="rounded-md px-3 py-2 text-sm font-medium"
                  :class="selected === 'rss' ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'"
                  >RSS</a
                >
              </div>
            </div>
          </div>
          <!-- Search -->
          <div class="flex flex-1 justify-center px-2 md:ml-6 md:justify-end">
            <div class="w-full max-w-lg md:max-w-xs">
              <label for="search" class="sr-only">Search</label>
              <div class="relative">
                <!-- Search icon -->
                <div
                  class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3"
                >
                  <svg
                    class="h-5 w-5 text-gray-400"
                    xmlns="http://www.w3.org/2000/svg"
                    viewBox="0 0 20 20"
                    fill="currentColor"
                    aria-hidden="true"
                  >
                    <path
                      fill-rule="evenodd"
                      d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
                      clip-rule="evenodd"
                    />
                  </svg>
                </div>
                <!-- Search input -->
                <input
                  class="block w-full rounded-md border border-transparent bg-gray-700 py-2 pl-10 pr-3 leading-5 text-gray-300 placeholder-gray-400 focus:border-white focus:bg-white focus:text-gray-900 focus:outline-none focus:ring-white"
                  placeholder="Search"
                  type="search"
                  name="search"
                  id="search"
                />
              </div>
            </div>
          </div>
          <!-- Hamburger -->
          <div class="flex md:hidden">
            <!-- Hamburger button -->
            <button
              @click="isShowMobileMenu = !isShowMobileMenu"
              class="inline-flex items-center justify-center rounded-md p-2 text-gray-400 hover:bg-gray-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
              aria-controls="mobile-menu"
              aria-expanded="false"
            >
              <span class="sr-only">Hamburger</span>
              <!-- Hamburger icon-->
              <svg
                class="block h-6 w-6"
                xmlns="http://www.w3.org/2000/svg"
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
                aria-hidden="true"
              >
                <path
                  stroke-linecap="round"
                  stroke-linejoin="round"
                  stroke-width="2"
                  d="M4 6h16M4 12h16M4 18h16"
                />
              </svg>
            </button>
          </div>
        </div>
      </div>
      <!-- Mobile menu, show/hide based on isShowMobileMenu state. -->
      <div x-show="isShowMobileMenu" class="md:hidden">
        <div x-data="{ selected: 'archive' } " class="space-y-1 px-2 pt-2 pb-3">
          <a
            href="#"
            @click="selected = 'archive'"
            class="block rounded-md px-3 py-2 text-base font-medium"
            :class="selected === 'archive' ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'"
            >Archive</a
          >
          <a
            href="#"
            @click="selected = 'series'"
            class="block rounded-md px-3 py-2 text-base font-medium"
            :class="selected === 'series' ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'"
            >Series</a
          >
          <a
            href="#"
            @click="selected = 'tags'"
            class="block rounded-md px-3 py-2 text-base font-medium"
            :class="selected === 'tags' ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'"
            >Tags</a
          >
          <a
            href="#"
            @click="selected = 'rss'"
            class="block rounded-md px-3 py-2 text-base font-medium"
            :class="selected === 'rss' ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white'"
            >RSS</a
          >
        </div>
      </div>
    </nav>
    <main class="mt-16">
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
      <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores
        facilis fuga iure officiis suscipit? Adipisci dolorum explicabo iste
        praesentium quas sequi, sint. Dolor esse ex itaque laboriosam saepe
        suscipit tenetur.
      </p>
    </main>
  </body>
</html>

Line 10

<body
  x-data="{ isShowNav: true, scrollY_: 0 }"
  @scroll.window="isShowNav = scrollY_ > scrollY; scrollY_ = scrollY"
>
  • isShowNav : control showing Navbar or not

  • scrollY_ : old scrollY to compare for scrolling detection

  • scroll.window : since scroll event belongs to window, we have to add .window postfix on scroll event

Line 12

isShowNav = scrollY_ > scrollY
scrollY_ = scrollY
  • scrollY is window.scrollY, it returns the scroll bar offset from the top
  • If scrollY is larger than old scrollY_, it means scroll down. Otherwise, scroll up

Line 14

<nav
  x-data="{ isShowMobileMenu: false }"
  class="fixed left-0 top-0 w-full bg-gray-800 transition duration-500"
  :class="isShowNav || '-translate-y-full'"
>
  • -translate-y-full : move the whole Navbar outside of the page

  • transition duration-500 : move the whole Navbar with duration

Conclusion

  • With scrolling detection and CSS transform, we can make responsive auto-hidden Navabar by Alpine and TailwindCSS