You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于父元素转换:before伪元素的Material Design抽屉技术问询

实现单个元素的Material Design侧边抽屉(带伪元素Scrim)

嘿,我来帮你搞定这个需求!用单个元素+:before伪元素实现Material Design风格的侧边抽屉,同时让scrim和抽屉同步动画,核心就是利用父元素的状态类统一控制两者的样式变化。下面是完整的实现方案:

核心思路

  • 用主元素#app-bar-drawer作为抽屉本体,默认隐藏在视口左侧
  • 用它的:before伪元素创建全屏的scrim(背景暗层),默认透明不可交互
  • 给父元素添加一个open类,同时触发抽屉的滑入动画和scrim的淡入效果,实现同步动效

完整代码实现

HTML结构

超简洁,就单个抽屉元素,再配个触发按钮(可选):

<div id="app-bar-drawer" class="drawer">
  <!-- 抽屉内容放在这里,比如导航菜单 -->
  <ul>
    <li>首页</li>
    <li>我的收藏</li>
    <li>设置</li>
  </ul>
</div>

<button onclick="document.getElementById('app-bar-drawer').classList.toggle('open')">打开抽屉</button>

CSS样式

完全符合Material Design的规范,包括阴影、动效曲线:

#app-bar-drawer {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: 350px;
  max-width: 85%;
  background: #fff;
  z-index: 1200;
  /* Material Design标准阴影 */
  box-shadow: 
    0px 8px 10px -5px rgba(0, 0, 0, 0.2), 
    0px 16px 24px 2px rgba(0, 0, 0, 0.14), 
    0px 6px 30px 5px rgba(0, 0, 0, 0.12);
  opacity: 0;
  pointer-events: none;
  /* 默认把抽屉移出视口左侧 */
  transform: translateX(-100%);
  /* Material Design标准动效曲线 */
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* 创建scrim暗层:用伪元素实现,不需要额外DOM */
#app-bar-drawer:before {
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  /* 放在抽屉后面,避免遮挡抽屉内容 */
  z-index: -1;
  opacity: 0;
  pointer-events: none;
  /* 和抽屉用相同的动效曲线,保证同步 */
  transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* 抽屉打开状态:同时激活抽屉和scrim的动画 */
#app-bar-drawer.open {
  opacity: 1;
  pointer-events: auto;
  transform: translateX(0);
}

#app-bar-drawer.open:before {
  opacity: 1;
  pointer-events: auto; /* 允许点击scrim关闭抽屉 */
}

/* 可选:给抽屉内容加些样式,更贴近Material Design */
#app-bar-drawer ul {
  list-style: none;
  padding: 16px 0;
  margin: 0;
}

#app-bar-drawer li {
  padding: 12px 24px;
  cursor: pointer;
}

#app-bar-drawer li:hover {
  background-color: rgba(0, 0, 0, 0.04);
}

可选JS交互(点击Scrim关闭抽屉)

如果需要点击背景暗层关闭抽屉,只需加几行JS:

const drawer = document.getElementById('app-bar-drawer');
drawer.addEventListener('click', (e) => {
  // 点击的是scrim区域(即伪元素对应的父元素区域)时,关闭抽屉
  if (e.target === drawer) {
    drawer.classList.remove('open');
  }
});

关键细节说明

  1. 伪元素定位:scrim用fixed定位覆盖全屏,z-index: -1确保它在抽屉下方,不会影响抽屉内容的交互
  2. 同步动效:抽屉和scrim使用相同的transition参数,尤其是Material Design的缓动函数,保证动画节奏一致
  3. 状态控制:通过父元素的open类统一管理显示/隐藏,避免分别控制两个元素的状态,减少代码复杂度
  4. 响应式适配:抽屉宽度用max-width: 85%,在小屏幕上会自动适配,不会超出视口

内容的提问来源于stack exchange,提问作者yaakov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:37:55