0Pricing
Tailwind CSS Academy · 课时

可折叠移动端侧边栏

使用 JavaScript 切换器、覆盖层背景和平滑的 translate 过渡效果,实现移动端滑入式抽屉侧边栏。

可折叠移动端侧边栏 是 CoddyKit 上的免费 Tailwind CSS Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Tailwind CSS Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Tailwind CSS Academy 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

What Is a Mobile Drawer Sidebar

A mobile drawer sidebar slides in from the left edge of the screen when a hamburger button is tapped, and slides out when dismissed. Unlike a desktop sidebar that is always visible, the mobile drawer is hidden off-screen by default using a CSS transform.

Three elements work together: the backdrop overlay that darkens the rest of the page, the sidebar panel that slides in, and the toggle button in the top bar that opens and closes the drawer.

<!-- Closed state: sidebar off-screen left -->
<aside id="drawer" class="fixed inset-y-0 left-0 w-72 bg-white z-50
                          -translate-x-full transition-transform duration-300">
  <!-- sidebar content -->
</aside>

<!-- Backdrop: hidden until drawer opens -->
<div id="backdrop" class="fixed inset-0 bg-black/50 z-40 hidden"></div>

The Open/Close JavaScript Toggle

The toggle works by removing the -translate-x-full class from the drawer and removing the hidden class from the backdrop. Closing reverses both operations.

A simple helper function openDrawer() and closeDrawer() keeps the logic clean. Add overflow-hidden to the body when the drawer is open to prevent scrolling the page content behind the overlay.

<script>
  const drawer = document.getElementById('drawer');
  const backdrop = document.getElementById('backdrop');

  function openDrawer() {
    drawer.classList.remove('-translate-x-full');
    backdrop.classList.remove('hidden');
    document.body.classList.add('overflow-hidden');
  }

  function closeDrawer() {
    drawer.classList.add('-translate-x-full');
    backdrop.classList.add('hidden');
    document.body.classList.remove('overflow-hidden');
  }

  // Clicking backdrop closes the drawer
  backdrop.addEventListener('click', closeDrawer);
</script>

Slide-In Transition With Tailwind

Tailwind's transition-transform duration-300 on the drawer panel creates a smooth slide animation when -translate-x-full is toggled. The duration-300 sets a 300ms ease transition, which feels snappy but not jarring.

You can customize the easing with ease-in-out and adjust the duration to duration-200 for a faster feel on simpler UIs. The key is that no custom CSS keyframes are needed — Tailwind's transition utilities handle it all.

<!-- Drawer with slide transition -->
<aside
  id="drawer"
  class="fixed inset-y-0 left-0 w-72 bg-gray-900 text-white z-50
         -translate-x-full transition-transform duration-300 ease-in-out
         flex flex-col">
  <!-- Header -->
  <div class="flex items-center justify-between px-5 py-4 border-b border-gray-800">
    <span class="font-bold text-white">Menu</span>
    <button onclick="closeDrawer()" class="text-gray-400 hover:text-white">
      <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
      </svg>
    </button>
  </div>
</aside>

Backdrop Overlay Styling

The backdrop overlay dims the content behind the open drawer, visually communicating that the drawer is a focused panel requiring attention. Use fixed inset-0 bg-black/50 z-40 so it covers the full viewport at a 50% opacity black color.

The backdrop sits at z-40 (below the drawer's z-50) so the drawer renders on top. Adding a fade-in transition with transition-opacity duration-300 makes the overlay appear more naturally.

<div
  id="backdrop"
  class="fixed inset-0 bg-black/50 z-40 hidden
         transition-opacity duration-300">
</div>

Drawer Navigation Links

Inside the drawer, navigation links use the same pattern as the desktop sidebar but can use slightly larger text since this is a touch interface: text-base instead of text-sm for better readability on mobile screens.

Add tap-highlight-color: transparent behavior by using active:bg-gray-800 to give immediate visual feedback when a link is tapped. The list is scrollable using flex-1 overflow-y-auto.

<nav class="flex-1 overflow-y-auto px-4 py-6 space-y-1">
  <a href="/" onclick="closeDrawer()"
     class="flex items-center gap-3 px-3 py-3 rounded-lg text-base font-medium
            bg-gray-800 text-white">
    Home
  </a>
  <a href="/features" onclick="closeDrawer()"
     class="flex items-center gap-3 px-3 py-3 rounded-lg text-base font-medium
            text-gray-300 hover:bg-gray-800 hover:text-white
            active:bg-gray-800 transition-colors">
    Features
  </a>
  <a href="/pricing" onclick="closeDrawer()"
     class="flex items-center gap-3 px-3 py-3 rounded-lg text-base font-medium
            text-gray-300 hover:bg-gray-800 hover:text-white
            active:bg-gray-800 transition-colors">
    Pricing
  </a>
</nav>

Hamburger Button in Top Bar

On mobile, the hamburger button lives in the top bar that replaces the sidebar. Use lg:hidden on this top bar so it only shows on small screens where the sidebar is hidden.

Give the button a comfortable touch target of at least 44×44px by using p-2 with a 24px icon (w-6 h-6), which totals the 44px recommended by Apple's HIG and Google's Material Design guidelines.

<header class="lg:hidden flex items-center justify-between px-4 py-3 bg-white border-b border-gray-200">
  <span class="font-bold text-gray-900">AppDash</span>
  <button
    onclick="openDrawer()"
    aria-label="Open navigation"
    class="p-2 text-gray-600 hover:bg-gray-100 active:bg-gray-200 rounded-lg">
    <svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
    </svg>
  </button>
</header>

Keyboard Escape to Close

Accessibility requires that overlay elements like drawers can be dismissed with the Escape key. Add a keydown listener to the document that checks for event.key === 'Escape' and calls closeDrawer().

This is a WCAG 2.1 requirement for all modal surfaces. Without Escape support, keyboard-only users are trapped inside the drawer.

<script>
  document.addEventListener('keydown', (event) => {
    if (event.key === 'Escape') {
      closeDrawer();
    }
  });
</script>

Right-Side Drawer Variant

Some UIs use a right-side drawer for filters, settings panels, or detail views rather than navigation. Replace left-0 with right-0 and change the closed transform from -translate-x-full to translate-x-full so the panel slides in from the right edge.

This is the same technique used for shopping cart sidebars, notification panels, and detail panes in single-page applications.

<!-- Right drawer -->
<aside
  id="right-drawer"
  class="fixed inset-y-0 right-0 w-80 bg-white shadow-xl z-50
         translate-x-full transition-transform duration-300 ease-in-out
         flex flex-col">
  <div class="flex items-center justify-between px-5 py-4 border-b border-gray-100">
    <h2 class="text-lg font-semibold text-gray-900">Filter Options</h2>
    <button onclick="closeRightDrawer()" class="p-1 text-gray-400 hover:text-gray-600 rounded">
      <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
      </svg>
    </button>
  </div>
  <div class="flex-1 overflow-y-auto p-5">
    <!-- Filter controls go here -->
  </div>
</aside>

Swipe-to-Close Hint Styling

On touch devices, users often expect to be able to swipe the drawer closed. While actual swipe detection requires JavaScript (Touch Events API), you can provide a visual hint by adding a drag handle at the top of the drawer — a short horizontal bar that signals swipeability.

Style it as a small rounded rectangle: mx-auto mt-2 w-10 h-1 rounded-full bg-gray-300. This is a common UX convention from native mobile apps adapted to the web.

<aside class="fixed inset-y-0 left-0 w-72 bg-gray-900 z-50 flex flex-col -translate-x-full transition-transform duration-300">
  <!-- Drag handle -->
  <div class="flex justify-center pt-3">
    <div class="w-10 h-1 rounded-full bg-gray-600"></div>
  </div>
  <!-- Header -->
  <div class="flex items-center justify-between px-5 py-4 mt-1 border-b border-gray-800">
    <span class="font-bold text-white">Menu</span>
    <button onclick="closeDrawer()" class="text-gray-400 hover:text-white">
      &times;
    </button>
  </div>
</aside>

Focus Trap for Accessibility

When the drawer is open, keyboard focus should be trapped inside it. This prevents Tab key navigation from reaching content hidden behind the overlay, which confuses screen reader users.

While implementing a full focus trap requires JavaScript (cycling through focusable elements with Tab and Shift+Tab), always ensure the close button is the first focusable element inside the drawer and receives autofocus or is programmatically focused when the drawer opens.

<script>
  function openDrawer() {
    const drawer = document.getElementById('drawer');
    const backdrop = document.getElementById('backdrop');
    drawer.classList.remove('-translate-x-full');
    backdrop.classList.remove('hidden');
    document.body.classList.add('overflow-hidden');

    // Move focus into drawer for accessibility
    const closeBtn = drawer.querySelector('button[data-close]');
    if (closeBtn) closeBtn.focus();
  }
</script>

<!-- Close button receives focus first -->
<button
  data-close
  onclick="closeDrawer()"
  class="text-gray-400 hover:text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-white rounded"
  aria-label="Close menu">
  <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
  </svg>
</button>

Complete Drawer Layout Assembly

A complete mobile drawer integrates all the pieces: a top bar with the hamburger button, the off-screen drawer panel with a close button and navigation links, and a backdrop overlay. The three pieces are independent HTML elements that JavaScript connects together.

On desktop (lg: breakpoint), hide the top bar with lg:hidden and show the persistent sidebar instead. This single mobile/desktop split is the foundation of every modern dashboard layout.

<!-- Top bar (mobile only) -->
<header class="lg:hidden sticky top-0 bg-white border-b border-gray-200 z-30 flex items-center justify-between px-4 py-3">
  <span class="font-bold">AppDash</span>
  <button onclick="openDrawer()" aria-label="Open menu" class="p-2 text-gray-600 hover:bg-gray-100 rounded-lg">
    <svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
    </svg>
  </button>
</header>

<!-- Backdrop -->
<div id="backdrop" class="hidden fixed inset-0 bg-black/50 z-40" onclick="closeDrawer()"></div>

<!-- Drawer panel -->
<aside id="drawer" class="fixed inset-y-0 left-0 w-72 bg-gray-900 text-white z-50 flex flex-col -translate-x-full transition-transform duration-300">
  <div class="flex items-center justify-between px-5 py-4 border-b border-gray-800">
    <span class="font-bold text-white">AppDash</span>
    <button data-close onclick="closeDrawer()" aria-label="Close menu" class="text-gray-400 hover:text-white">&times;</button>
  </div>
  <nav class="flex-1 overflow-y-auto px-4 py-6 space-y-1">
    <a href="/" class="block px-3 py-3 rounded-lg text-base font-medium bg-gray-800 text-white">Home</a>
    <a href="/features" class="block px-3 py-3 rounded-lg text-base font-medium text-gray-300 hover:bg-gray-800 hover:text-white">Features</a>
  </nav>
</aside>

Quick Check

Test your understanding of Tailwind CSS Mastery concepts from this lesson.

Lesson Recap

In this lesson you learned: the mobile drawer uses three elements — backdrop overlay, slide-in panel, and hamburger trigger; the slide animation toggles -translate-x-full with transition-transform duration-300; and accessibility requires Escape-key support, focus management into the drawer on open, and a clickable backdrop to close. Next up we style text inputs and textareas.

常见问题解答

「可折叠移动端侧边栏」课时是免费的吗?

是的 — 「可折叠移动端侧边栏」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Tailwind CSS Academy 课程的其余内容,请升级到 CoddyKit PRO。 Tailwind CSS Academy 课程共包含 4 节课。

「可折叠移动端侧边栏」这节课中我会学到什么?

使用 JavaScript 切换器、覆盖层背景和平滑的 translate 过渡效果,实现移动端滑入式抽屉侧边栏。 你通过在浏览器中直接运行的动手代码来练习 Tailwind CSS Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Tailwind CSS Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Tailwind CSS Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「可折叠移动端侧边栏」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Tailwind CSS Academy 课中编写并运行代码吗?

能。每节 Tailwind CSS Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 构建响应式导航栏
  2. 粘性与固定导航
  3. 垂直侧边栏布局
  4. 可折叠移动端侧边栏
← 返回 Tailwind CSS Academy