BeforeAfter 对比滑块
新粗野主义风格的图片滑动对比组件。用于直观比对同一张图在修改前 (Before) 与修改后 (After) 的视觉差异。基于原生 <input type="range"> 结合 CSS clip-path 遮罩构建,零依赖、触控友好。
预览
水平方向
垂直方向
提示:拖拽滑块的位置过渡尊重系统的「减少动态效果」设置。启用后分割线与裁剪区域将即时跟随,不再带有缓动动画。
安装
pnpm dlx brutx-vue@latest add before-after用法
<script setup>
import { BeforeAfter } from 'brutx-ui-vue'
const original = '/images/before.jpg'
const modified = '/images/after.jpg'
</script>
<template>
<BeforeAfter
:before="original"
:after="modified"
:default-value="50"
/>
</template>垂直方向
通过 orientation 属性切换分割线方向。默认 horizontal 为左右拖拽;设置为 vertical 时,分割线变为水平方向上下拖拽,裁剪从下到上进行(clip-path: inset(0 0 ...)),手柄图标自动旋转 90 度。
<BeforeAfter
:before="original"
:after="modified"
orientation="vertical"
:default-value="50"
/>浏览器兼容提示:垂直模式下分割线/手柄位置(
top: <value>%,值大靠下)与原生垂直 range 的 value 递增方向在 Chromium 中一致;WebKit(Safari)下垂直滑块的递增方向可能相反(向下拖 value 减小、分割线反而上移),orient属性在部分浏览器不被支持。跨浏览器场景建议实测验证。
变体
| 变体 | 说明 |
|---|---|
horizontal | 默认方向,左右拖拽分割线 |
vertical | 垂直方向,上下拖拽分割线,裁剪从下到上进行 |
API 参考
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
before必填 | string | — | 对比底层的 before 图片 URL。 |
详情 | |||
after必填 | string | — | 对比上层的 after 图片 URL。 |
详情 | |||
beforeAlt | string | undefined | undefined运行时回退: | 底层 before 图片的替代文本;未设置时使用本地化默认值。 |
详情声明类型string | undefined 默认值详情
来源packages/ui/src/components/before-after/BeforeAfter.vue | |||
afterAlt | string | undefined | undefined运行时回退: | 上层 after 图片的替代文本;未设置时使用本地化默认值。 |
详情声明类型string | undefined 默认值详情
来源packages/ui/src/components/before-after/BeforeAfter.vue | |||
modelValue | number | undefined | undefined | 当前分割位置百分比,支持 v-model;写入和交互值都会限制在 0 到 100。 |
详情声明类型number | undefined 默认值详情
来源packages/ui/src/components/before-after/BeforeAfter.vue | |||
defaultValue | number | undefined | 50 | 非受控模式的初始分割位置百分比;仅初始化时读取,默认 50。 |
详情声明类型number | undefined 默认值详情
来源packages/ui/src/components/before-after/BeforeAfter.vue | |||
disabled | boolean | undefined | false | 禁用原生范围滑块的拖动交互。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/before-after/BeforeAfter.vue | |||
orientation | "vertical" | "horizontal" | undefined | "horizontal" | 选择分割线方向;horizontal 显示竖直分割线,vertical 显示水平分割线。 |
详情声明类型"vertical" | "horizontal" | undefined 字面量
默认值详情
来源packages/ui/src/components/before-after/BeforeAfter.vue | |||
class | string | undefined | undefined | 追加到对比容器根元素的自定义 CSS 类。 |
详情声明类型string | undefined 默认值详情
来源packages/ui/src/components/before-after/BeforeAfter.vue | |||
iconSize | IconSize | undefined | "md" | 设置分割手柄图标尺寸。 |
详情声明类型IconSize | undefined 字面量
关联类型 IconSize 类型定义 — IconSizeexport type IconSize = NonNullable<VariantProps<typeof iconSizeVariants>['size']> 默认值详情
来源packages/ui/src/components/before-after/BeforeAfter.vue | |||
| 名称 | 签名或类型 | 说明 |
|---|---|---|
@update:modelValue | [value: number] | 拖动滑块导致位置改变时发出限制在 0 到 100 的新百分比。 |
详情声明类型[value: number] 来源packages/ui/src/components/before-after/BeforeAfter.vue | ||
可访问性
- 键盘操作:支持键盘方向键控制分割线位置;
disabled状态下禁用键盘交互 - 焦点指示:透明 range input 自身无可见焦点,键盘焦点态经
has-[:focus-visible]变体呈现在容器外环(ring-brutal-ring),Tab 聚焦时可感知当前位置 - 动效降级:组件尊重
prefers-reduced-motion系统设置。当用户启用"减少动态效果"时(通过useReducedMotion监听prefers-reduced-motion: reduce):- 移除滑块过渡:分割线、拖拽手柄以及
clip-path裁剪层不再应用过渡样式,拖动时位置变化即时生效,不带有缓动动画 - 交互能力保留:拖拽、键盘方向键、
disabled等行为完全不受影响,仅去除视觉过渡 - 实时响应:偏好切换后立即生效,无需重新挂载组件
- 该机制通过一个响应式的
motionTransition计算属性实现:在动效降级模式下返回空字符串,从而让相关元素跳过过渡样式
- 移除滑块过渡:分割线、拖拽手柄以及
常见问题
Q: 组件的技术方案是什么?
A: 本组件基于原生浏览器 <input type="range"> 结合 CSS 的 clip-path 遮罩构建,具有以下优势:
- 触控友好:在手机、平板等移动端设备上完美适配滑动手势
- 零依赖:不需要额外加载任何外部手势交互 JS 库,包体积近乎于零
- 完美排版:底层的
clip-path: inset(...)裁剪方式不会破坏图片的宽高比,确保布局在多端始终对齐 - 自适应比例:容器根据图片实际尺寸自动计算
aspect-ratio,无需手动指定比例。图片加载前使用默认比例(水平 16:9,垂直 9:16)作为占位