Range FX <mv-range-fx>
基于同一个无障碍模型的表现力滑块:拖动时轨道变成荡漾的波浪(wave),数值气泡弹出并随速度倾斜(bubble),刻度尺在固定指针下带惯性滚动(ruler),液体端帽被拉伸(fluid),或标签位于轨道内并在填充下反色(inline)。
工作原理
基于同一个无障碍模型的富表现力滑块:拖动时轨道变成起伏的波浪(wave),数值气泡弹出并随速度倾斜(bubble),标尺带惯性地在固定指针下滚动(ruler),液态端帽被拉伸(fluid),或者标签位于轨道内部并在填充部分之下反色(inline)。支持表单关联。
| 分类 | 基础元素 |
|---|---|
| 类型 | Web Component(<mv-range-fx>) |
| 状态 | 稳定版 |
| Keywords | slider, range, wave, bubble, ruler, fluid, inline-label, spring, velocity, form-associated |
When to use
- A showcase or creative tool needs a slider with personality, such as a rippling wave, tilting bubble or liquid cap
- A value is picked on a ruler that scrolls under a fixed needle, like a measurement or tuning control
- The label and value must live inside the track to save space
Avoid when
- Dual thumbs, ticks, labeled marks or a sober look for dense forms are needed → use Slider instead
- The fill should slosh like liquid with inertia, or the control should look like a vertical tank → use Slosh Slider instead
安装
node scripts/add.mjs range-fx --out ./src/marvelous通过 Marvelous UI MCP 服务器使用 AI 智能体:install_components({ slugs: ["range-fx"], target_dir: "<absolute path>/src/marvelous", framework: "react" })。
复制的文件(含依赖):tokens/tokens.css、core/base.css、core/canvas.js、core/dom.js、core/element.js、core/form.js、core/motion.js、core/observe.js、components/range-fx/range-fx.js、components/range-fx/range-fx.css。
用法
标准标记,可在此基础上通过属性、data-* 和 CSS 变量进行定制:
<form id="rfx-demo" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(17rem,1fr));gap:1.25rem;width:min(100%,46rem)">
<section style="display:grid;gap:.5rem;padding:1.125rem 1.25rem 1.25rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-xl);background:var(--mv-surface)">
<small style="color:var(--mv-fg-subtle);font-weight:500">wave</small>
<mv-range-fx variant="wave" label="Volume" name="volume" value="62" value-suffix="%"></mv-range-fx>
</section>
<section style="display:grid;gap:.5rem;padding:1.125rem 1.25rem 1.25rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-xl);background:var(--mv-surface)">
<small style="color:var(--mv-fg-subtle);font-weight:500">bubble</small>
<mv-range-fx variant="bubble" label="Monthly budget" name="budget" min="0" max="2000" step="50" value="850" value-prefix="$"></mv-range-fx>
</section>
<section style="grid-column:1/-1;display:grid;gap:.5rem;padding:1.125rem 1.25rem 1rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-xl);background:var(--mv-surface)">
<small style="color:var(--mv-fg-subtle);font-weight:500">ruler: flick the ruler and it settles on the nearest tick</small>
<mv-range-fx variant="ruler" label="Weight" name="weight" min="70" max="330" step="0.5" major="10" value="151.5" value-suffix=" lb"></mv-range-fx>
</section>
<section style="display:grid;gap:.625rem;padding:1.125rem 1.25rem 1.25rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-xl);background:var(--mv-surface)">
<small style="color:var(--mv-fg-subtle);font-weight:500">fluid</small>
<mv-range-fx variant="fluid" label="Brightness" name="brightness" value="70" value-suffix="%"></mv-range-fx>
</section>
<section style="display:grid;gap:.625rem;padding:1.125rem 1.25rem 1.25rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-xl);background:var(--mv-surface)">
<small style="color:var(--mv-fg-subtle);font-weight:500">inline</small>
<mv-range-fx variant="inline" label="Layer opacity" name="opacity" value="40" value-suffix="%"></mv-range-fx>
</section>
</form>
<script type="module">
document.getElementById("rfx-demo").addEventListener("submit", (e) => e.preventDefault());
</script>API
Attributes
| Name | 类型 | Default | Description |
|---|---|---|---|
variant | wave | bubble | ruler | fluid | inline | wave | Rendering and velocity-driven effect. |
min / max / step | number | 0 / 100 / 1 | Bounds and step (step decimals are respected, e.g. 0.5). |
value | number | Initial value, restored on form reset. | |
name | string | Form field name. | |
label | string | Visible label (above, or inside the track for fluid/inline) and accessible name. Otherwise use aria-label / aria-labelledby. | |
value-prefix / value-suffix | string | Text around the formatted value (Intl). | |
large-step | number | 10% of the range | Step for PageUp/PageDown and Shift+Arrow. |
major | number | 10 | ruler: a labeled major tick every N steps. |
stops | number | 10 | inline: number of intervals marked with dots (hidden under the text). |
disabled / readonly / required | boolean | Standard states. |
Properties
| Name | 类型 | Description |
|---|---|---|
value / valueAsNumber | string / number | Current value; setting it animates the slider. |
formatter | (value) => string | Custom formatting (display and aria-valuetext). |
form / labels / validity | Via ElementInternals. |
Methods
| Name | Description |
|---|---|
focus() | Focuses the slider. |
Events
| Name | Description |
|---|---|
mv-input | On every value change (drag, wheel, keyboard). detail: { value }. |
mv-change | End of interaction (release, ruler stop, key press). |
CSS classes
| Name | Description |
|---|---|
mv-range-fx-head / -label / -value | Label + value header. |
mv-range-fx-control | Focusable role="slider" element. |
mv-range-fx-thumb / -wave / -bubble / -needle / -scale / -fill / -cap / -bar / -stops / -text | Variant-specific parts. |
CSS variables
| Name | Default | Description |
|---|---|---|
--mv-range-fx-color | var(--mv-accent) | Color of the fill, wave and needle. |
--mv-range-fx-tick-gap | 10px | ruler: gap between two ticks. |
--mv-range-fx-bubble-bg / -fg | bubble: bubble colors. |
Accessibility
role="slider" on the control area, with aria-valuenow/min/max, a formatted aria-valuetext (prefix/suffix) and a name taken from the label. Keyboard: arrows (±step, reversed in RTL), Shift+Arrow and PageUp/PageDown (large step), Home/End. All decorations are aria-hidden. Reduced motion: springs, ripple and inertia are disabled and the value jumps into place. Forced colors: tracks in GrayText, the filled part and the needle in Highlight, the text over the fill in HighlightText. The ruler scale is a canvas drawn with the theme colors.