
滑动门代码怎么写:用 CSS 实现基础滑动效果
网页里的“滑动门”通常指一块或两块面板沿水平方向移动,露出后面的内容。它可以用于卡片揭示、装饰性入口、简单的内容预览,也常被用来表现侧边栏或抽屉的进出。实现这类效果的核心并不复杂:让面板覆盖内容,再通过 CSS 的 transform 改变面板位置,并用 transition 平滑过渡。
不过,动画好看并不等于交互完整。纯 CSS 的悬停效果在触屏上没有稳定的触发方式;视觉上被门板盖住的内容,也不一定真的从辅助技术或页面脚本中隐藏。下面先说明适用范围,再用一个可运行的示例实现两扇门向两侧滑开的效果,并讨论键盘操作、移动端、动画偏好和安全边界。
一、滑动门适合什么场景
滑动门适合表达一个明确、短暂的视觉状态变化,例如:
- 鼠标悬停或键盘聚焦卡片时,显示一段补充说明。
- 点击一个控件后,揭示装饰性内容或轻量预览。
- 页面中的侧栏、抽屉或菜单从边缘滑入。
- 用两个面板的移动作为局部过渡,而不是整页切换动画。
如果内容是主要任务入口,或用户需要持续查看、编辑其中的数据,不要只把它藏在一个没有提示的动画后面。门板效果也不适合承载权限控制、隐私保护或真正的内容隔离:CSS 只能改变呈现方式,不能代替访问控制。
还要区分“滑动门效果”和传统的 CSS 滑动门背景技巧。后者曾常用于拼接不同尺寸的圆角背景;本文讨论的是面板随交互滑开的动效。两者名称相近,但解决的问题不同。
二、实现原理:定位、变换和过渡
一个基础滑动门可以拆成三层:
- 容器:作为定位参照,并用
overflow: hidden裁掉移出区域的门板。 - 内容:放在门板后面,显示被揭示的信息。
- 门板:绝对定位在容器上方,初始时各占一半;打开时分别向左、向右平移。
transform: translateX(...) 改变元素的视觉位置,不会像修改布局尺寸那样直接重排周围元素,适合这种移动效果。transition 则定义属性变化时的持续时间和缓动方式。下面的例子只过渡 transform,避免不必要地对所有属性做动画。
滑动距离要结合门板宽度理解。门板各占容器宽度的 50%,左门向左移动自身宽度,即 translateX(-100%);右门相应移动 translateX(100%)。这里百分比以各自门板的尺寸为基准,不是容器宽度。若门板不是半宽,或布局结构发生变化,移动距离也需要重新核对。
三、可运行示例:复选框控制两扇门
下面的完整示例只依赖 HTML 和 CSS。保存为 sliding-door.html 后用浏览器打开即可运行。点击复选框或它的标签,门板会打开或关闭;键盘用户可以聚焦复选框后按空格切换。示例中的复选框保持在可访问性树中,没有用 display: none 隐藏。
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CSS 滑动门示例</title>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 2rem;
font-family: system-ui, sans-serif;
background: #f3f5f8;
color: #182230;
}
.demo {
width: min(100%, 32rem);
margin: 2rem auto;
}
.door-control {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
clip-path: inset(50%);
}
.door-label {
display: inline-block;
margin-bottom: 0.75rem;
padding: 0.65rem 1rem;
border: 1px solid #52647a;
border-radius: 0.4rem;
background: #fff;
cursor: pointer;
}
.door-control:focus-visible + .door-label {
outline: 3px solid #1769aa;
outline-offset: 3px;
}
.doorway {
position: relative;
min-height: 14rem;
overflow: hidden;
border-radius: 0.75rem;
background: #dceeff;
isolation: isolate;
}
.revealed-content {
position: absolute;
inset: 0;
display: grid;
place-content: center;
padding: 1.5rem;
text-align: center;
}
.revealed-content h2 {
margin: 0 0 0.5rem;
}
.revealed-content p {
max-width: 24rem;
margin: 0;
line-height: 1.6;
}
.door {
position: absolute;
z-index: 1;
top: 0;
bottom: 0;
width: 50%;
background: #314b68;
transition: transform 450ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.door--left {
left: 0;
border-right: 1px solid rgb(255 255 255 / 35%);
}
.door--right {
right: 0;
border-left: 1px solid rgb(255 255 255 / 35%);
}
.door-control:checked ~ .doorway .door--left {
transform: translateX(-100%);
}
.door-control:checked ~ .doorway .door--right {
transform: translateX(100%);
}
@media (prefers-reduced-motion: reduce) {
.door {
transition: none;
}
}
</style>
</head>
<body>
<main class="demo">
<input class="door-control" type="checkbox" id="door-toggle">
<label class="door-label" for="door-toggle">切换滑动门</label>
<section class="doorway" aria-label="滑动门效果演示">
<div class="revealed-content">
<div>
<h2>门后的内容</h2>
<p>这里是一直存在的示例文字。复选框控制门板的视觉位置。</p>
</div>
</div>
<div class="door door--left" aria-hidden="true"></div>
<div class="door door--right" aria-hidden="true"></div>
</section>
</main>
</body>
</html>
四、逐段理解关键代码
1. 用同级选择器连接状态和门板
复选框的 checked 状态是开关。选择器 .door-control:checked ~ .doorway 表示:当这个复选框被选中时,选择它后面的同级 .doorway 中对应的门板。这里使用的是一般兄弟选择器 ~,因此状态控件和门板容器必须满足同级关系,且容器要出现在控件之后。
如果把门板容器移到复选框之前,或把它包进另一层与选择器不匹配的结构中,规则就不会生效。修改 HTML 结构时,先检查 DOM 层级,再检查选择器,而不是只改动画参数。
2. 让门板覆盖内容,但不参与布局
position: absolute 让两扇门相对 .doorway 定位。容器的 position: relative 建立定位上下文,inset: 0(示例中用 top、bottom 加左右定位)将门板贴合容器上下边缘。门板使用 z-index: 1,盖在内容之上;内容本身通过绝对定位铺满整个容器。
overflow: hidden 负责裁切移出容器的部分。没有它,移到容器外的门板仍可能显示在周围。isolation: isolate 建立局部堆叠上下文,减少该演示内部层级与外部元素意外交错的可能,但它不是安全隔离机制。
3. 用过渡控制速度和节奏
示例使用 transition: transform 450ms cubic-bezier(...)。450ms 是演示用的持续时间,不是浏览器限制或通用标准;实际数值应根据内容、运动距离和页面节奏调整。时间过长会拖慢操作反馈,过短则可能显得突兀。
缓动函数决定运动过程中的速度变化。也可以改成较直观的 ease 或 ease-in-out。如果只需要基础效果,优先选择容易理解、容易维护的参数,不必为了“更像真实门”而叠加多组复杂动画。
4. 处理减少动态效果偏好
prefers-reduced-motion: reduce 是浏览器提供的用户偏好媒体特性。示例检测到用户选择减少动态效果时,取消门板过渡,让状态仍可切换但不再播放滑动动画。它不是对动画时长的强制上限,也不会自动消除页面里其他动画;项目中应检查所有相关动效。
五、纯 CSS 方案的边界与交互选择
复选框方案的优点是无需 JavaScript,状态可由原生表单控件维护,键盘操作也有基本支持。但复选框表达的是“选中/未选中”,不一定适合所有交互语义。如果效果代表导航菜单展开、抽屉打开或某项内容显示,控件和状态名称应与实际功能一致。不要把所有视觉开关都机械地做成复选框。
当用户需要点击一个按钮来打开面板,并且页面需要同步管理 aria-expanded、焦点位置、关闭方式或多个互斥面板时,通常应使用真正的按钮配合少量 JavaScript 更新状态。CSS 负责动画,脚本负责交互状态,语义和状态会更清晰。单靠 CSS 选择器并不会自动更新按钮的 ARIA 属性,也不能自动把焦点移入弹出的面板。
此外,复选框示例里的文字始终存在于文档中。门板只是遮住了它,并没有让内容从屏幕阅读器、搜索索引或脚本中消失。由于示例内容只是文本,这一点可以接受;如果门后是不能在关闭时访问的交互控件,单纯覆盖可能导致用户焦点进入视觉上看不见的控件。此时需要根据实际交互管理隐藏状态、焦点和可访问性,而不是把遮挡误当作隐藏。
六、触屏与悬停:不要只依赖 hover
许多简单示例使用 :hover 触发开门,例如:
.doorway:hover .door--left {
transform: translateX(-100%);
}
.doorway:hover .door--right {
transform: translateX(100%);
}
这种写法适合纯装饰、非关键的桌面端预览,但不能作为唯一交互方式。触屏设备没有传统鼠标悬停;部分设备可能模拟悬停状态,具体表现取决于浏览器和输入方式。键盘用户也不会自然触发 :hover。如果要采用悬停,至少考虑键盘焦点状态,例如在适当的结构下使用 :focus-within,并提供可点击的控件,让触屏用户有明确入口。
:focus-within 表示元素自身或其后代获得焦点时匹配。它只有在容器内确实有可聚焦元素时才会体现键盘交互;给一个没有交互后代的纯展示容器加上它,并不能凭空制造键盘操作。还要避免鼠标离开后面板立刻关闭,导致用户难以把焦点移到刚显示的内容上。
七、常见错误与排查顺序
- 门板完全不动:检查状态控件是否被选中、选择器是否匹配,以及门板是否位于预期容器内。检查同级关系和类名拼写。
- 门板移动但露出容器外:检查容器是否有
overflow: hidden,以及是否存在祖先层级或变换造成的视觉范围变化。 - 只打开一扇门:确认两扇门都有各自的状态规则,且左右方向和初始定位没有写反。
- 移动距离不对:确认
translateX(100%)的百分比是按门板自身尺寸计算。门板宽度不再是 50% 时,原有假设可能不成立。 - 动画生硬或没有动画:确认
transition写在状态变化前后都会存在的门板上,而不是只写在:checked规则里。检查媒体查询是否因系统减少动态效果设置而关闭了过渡。 - 内容被门板挡住:检查层叠顺序和
z-index。同时确认门板背景是否不透明;半透明背景会让后面的内容透出来,这是视觉设计选择,不是定位错误。 - 手机上没有可用入口:不要把
:hover当作唯一触发方式,提供按钮、链接或其他适合触屏的控件。 - 隐藏内容仍能被访问:这是视觉遮挡与语义隐藏不同造成的。若关闭时应禁用内容,需要设计真正的展开/收起状态,并同步处理键盘焦点和辅助技术可见性。
八、参数限制与安全用途说明
CSS 对 transform 的具体表现受元素尺寸、定位上下文、裁切和浏览器渲染影响。示例中的半宽门板与百分比位移是建立在当前结构上的计算方式,并非所有布局都可直接照搬。容器尺寸变化通常会随百分比重新计算,但门板宽度、边框、间距或变换原点改变后,应重新验证实际移动距离。不同浏览器也可能在细节渲染上存在差异,尤其要测试窄屏和高缩放比例。
示例的 CSS 没有读取或提交用户数据,也不提供身份验证、授权、加密或访问控制。把敏感文本放在门板后面,不能保护它不被查看;文本仍可能出现在页面源代码、DOM、脚本可读内容或辅助技术的内容中。真正的权限判断和敏感数据保护必须在服务器端等可信边界执行,前端动画只负责表现。
同样,不要把动画参数当作安全参数。限制移动距离、禁用右键或遮住内容,都不能阻止有权限访问页面的人检查前端代码。若门板内包含链接或表单控件,还要确认关闭状态下的焦点和操作不会造成误触或不可见焦点。
九、如何把示例改成自己的组件
先保留最小结构:一个状态控件、一个定位容器、一层内容和两块门板。替换颜色、圆角和高度时,优先改 CSS 变量或对应样式;调整门板宽度后,再检查位移比例。需要只开单扇门时,删去另一扇门及对应规则即可。需要从上向下滑动时,使用 translateY(),同时将门板的定位与移动方向匹配。
上线前至少做四项检查:用鼠标点击状态控件;只用键盘完成聚焦和切换;在窄屏触控设备上确认有清楚的操作入口;开启系统减少动态效果设置后检查动效是否按预期减弱。若门后内容是重要功能,还应检查关闭状态下的屏幕阅读器访问顺序,以及是否需要改成带有明确展开状态的按钮组件。
总结
CSS 滑动门的基础做法是:容器裁切溢出内容,门板覆盖在内容上,状态变化时通过 transform 移动门板,并用 transition 让变化平滑。实现本身很短,真正需要仔细判断的是交互语义、触屏触发、键盘焦点、关闭状态下的内容可访问性,以及动画偏好。
把滑动门当作视觉效果,而不是内容保护手段;对于简单展示,纯 CSS 可以胜任。需要管理焦点、ARIA 状态、复杂展开逻辑或真正隐藏内容时,应使用语义合适的控件,并让 JavaScript 与 CSS 分别承担状态管理和视觉过渡。









