スライダー
トラックに沿ってハンドルをドラッグし、値または値の範囲を選びます。連続的にも、刻みごとにも選べます。
- カテゴリ
- 選択
- トークン
comp.slider- レベル
- 基礎
- 使用先
- Slider field
- Web
tanrei-sliderschedule - SwiftUI
TanreiSliderschedule - Jetpack Compose
TanreiSliderschedule - Flutter
TanreiSliderschedule - React Native
Sliderschedule
生成元 docs/status/status.json, specs/slider.spec.json
連続、刻みと目盛り、範囲
プレイグラウンド
スライダーは min から max(既定は 0 から 100)の間で 1 つの値を選びます。range を付けるとハンドルが 2 つになり、startValue から value までの範囲を選びます。step が 0 なら連続的に動き、0 より大きければ min に step の整数倍を足した値に吸着します。
スライダーはラベルを描きません。label は支援技術に向けた名前で、目に見えるラベルは利用者側でスライダーの隣に同じ言葉で置きます。範囲を選ぶスライダーでは、始点側のハンドルにも startLabel が必要です。
値の変化は 2 つのイベントで伝わります。input はドラッグ中に値が変わるたびに発火し、change は変更が終わったとき、つまり押していた指やポインターが離れたとき、またはキーや支援技術で値を変えたときに 1 回だけ発火します。利用者側のコードで値を設定したときは、どちらも発火しません。名前はプラットフォームごとに違い、Compose では onValueChange と onValueChangeFinished、Flutter では onChanged と onChangeEnd、React Native では onValueChange と onSlidingComplete、SwiftUI ではバインディングと onCommit です。
スライダーのハンドルを丸くした改訂と、そのリングを太くした見直しで変わったのは見た目だけなので、以下の例はどれも現在の仕様に沿っています。Web は現在の見た目で描きます。SwiftUI、Compose、Flutter、React Native は追従待ちで、追従するまでは以前の見た目、つまり塗りつぶしの丸いハンドル、ハンドルの縁で切れるトラック、どのサイズでも同じ大きさの目盛りの点で描きます。
<!-- スライダーはラベルを描きません。目に見えるラベルは、同じ言葉で隣に置きます。 -->
<tanrei-slider name="volume" label="音量" value="40" value-indicator="active"></tanrei-slider>
<!-- 刻みごとに動き、刻みの位置に点を描きます。 -->
<tanrei-slider label="明るさ" value="30" step="10" stops></tanrei-slider>
<!-- 範囲は、同じ name で start-value、value の順に送信されます。 -->
<tanrei-slider name="price" range min="0" max="500" step="10" start-value="100" value="300"
label="上限価格" start-label="下限価格"></tanrei-slider>
<script type="module">
import '@tanrei/web/components/slider';
const volume = document.querySelector('[name="volume"]');
// 要素は input と change を発火する前に、自分の value を更新します。
volume.addEventListener('input', () => preview(volume.value));
volume.addEventListener('change', () => save(volume.value));
</script>import { Slider } from '@tanrei/react';
<Slider
label="音量"
value={volume}
valueIndicator="active"
onInput={(e) => setVolume(e.currentTarget.value)}
onChange={(e) => save(e.detail.value)}
/>
<Slider
range
min={0}
max={500}
step={10}
startValue={minPrice}
value={maxPrice}
label="上限価格"
startLabel="下限価格"
onInput={(e) => setPrices(e.currentTarget.startValue, e.currentTarget.value)}
/>import Tanrei
// 値が変わるたびにバインディングへ書き込み、変更が終わると onCommit を呼びます。
TanreiSlider("音量", value: $volume, in: 0...100, onCommit: save)
TanreiSlider("明るさ", value: $brightness, in: 0...100, step: 10)
// 範囲は、バインディングが ClosedRange のイニシャライザーです。lowerBound が始点側のハンドルです。
TanreiSlider("上限価格", startLabel: "下限価格", value: $prices, in: 0...500, step: 10)import io.github.chnotchy.tanrei.components.TanreiSlider
// 状態ホイスティング:onValueChange で受け取った値を value に反映します。
TanreiSlider(
value = volume,
onValueChange = { volume = it },
contentDescription = "音量",
onValueChangeFinished = ::save, // foundation のものと違い、値を受け取ります
)
// step は刻みの大きさです。Material の steps のような刻みの数ではありません。
TanreiSlider(value = brightness, onValueChange = { brightness = it }, step = 10f, contentDescription = "明るさ")
// 範囲は、value が ClosedFloatingPointRange のオーバーロードです。
TanreiSlider(
value = prices,
onValueChange = { prices = it },
valueRange = 0f..500f,
step = 10f,
contentDescription = "上限価格",
startContentDescription = "下限価格",
)import 'package:tanrei/tanrei.dart';
TanreiSlider(
value: volume,
onChanged: (double value) => setState(() => volume = value), // null で無効になります
onChangeEnd: save,
semanticLabel: '音量',
);
// step は刻みの大きさです。Material の divisions のような刻みの数ではありません。
TanreiSlider(value: brightness, step: 10, onChanged: (double value) => setState(() => brightness = value), semanticLabel: '明るさ');
TanreiSlider.range(
start: minPrice,
end: maxPrice,
max: 500,
step: 10,
onChanged: (double start, double end) => setState(() {
minPrice = start;
maxPrice = end;
}),
semanticLabel: '上限価格',
startSemanticLabel: '下限価格',
);import { Slider } from '@tanrei/react-native';
<Slider value={volume} onValueChange={setVolume} onSlidingComplete={save} accessibilityLabel="音量" />
<Slider value={brightness} step={10} stops onValueChange={setBrightness} accessibilityLabel="明るさ" />
// 範囲:どちらのコールバックも (value, startValue) を受け取ります。
<Slider
range
minimumValue={0}
maximumValue={500}
step={10}
startValue={minPrice}
value={maxPrice}
onValueChange={(value, startValue) => setPrices(startValue, value)}
accessibilityLabel="上限価格"
startAccessibilityLabel="下限価格"
/>サイズ、中央起点、値の表示、縦向き、無効状態
既定のシステムでは、ハンドルはリング形です。サーフェスの色で塗った直径 20 の円を、アクティブトラックと同じ色の輪郭線が囲みます。輪郭線は太さ 3 で、円の縁の内側に描くので、ハンドルの大きさは変わりません。内側にはサーフェスの色の直径 14 の円が残り、輪郭線を太くすれば、その円が小さくなります。トラックとアクティブトラックはハンドルの下まで伸びてその中心で出会うので、アクティブトラックはリングで終わる 1 本の線に見えます。ハンドルはどのサイズでも 20 で、トラックの太さは 4、6、8 です。
目盛りの点と、移動範囲の端を示す点は、トラックの半分の太さです。small、medium、large でそれぞれ 2、3、4 になります。値の表示はリングの上端の少し上に、リングの中心に揃えて出ます。無効状態では、リングは塗りを保ち、輪郭線はアクティブトラックと一緒に薄くなります。
デザインシステムは、同じトークンでハンドルを別の形に描けます。輪郭線を 0 にすれば塗りだけのハンドルになり、トラックとハンドルの間に隙間を取れば、トラックはハンドルの手前で止まり、そこで丸くなります。m3-like は、この方法で Material の縦長のバーを描きます。
構成要素
構成要素
continuous の上に描いています。| パーツ | 説明 |
|---|---|
1 track | The line the handle travels along: the whole range from min to max. Drawn in the track color where it is not active. |
2 active-track | The part of the track from the origin to the value, or between the two handles of a range, drawn over the track. |
3 handle | The part the person drags, one per value: in Tanrei a circle (its width along the track equals its height across it) with a fill and an outline of its own, a narrow upright bar where a system says so. |
4 handle-outline · 任意 | The ring drawn over the handle's fill, inside its edge, so the handle keeps its size however wide the ring is: a wider ring leaves a smaller disc of fill. None where its width is 0. |
5 container | The round state layer centered on a handle, moving with it. It carries hover, focus and press and is invisible at rest. |
6 stop-indicator · 任意 | A dot on the track's midline, half the track's thickness across in Tanrei: at an end of the handle's travel that lies on the track, and at every step while stops is true. |
7 value-indicator · 任意 | A small label beside a handle that shows its value while the handle is pressed or focused, or always. |
8 focus-ring | Gap-then-ring indicator around the handle that has keyboard focus. |
寸法
寸法
| 長さ | トークン | 値(px) |
|---|---|---|
handle height | tanrei.comp.slider.handle.height.small | 20 |
container size | tanrei.comp.slider.container.size | 40 |
continuous の上に描いています。プロパティ
| プロパティ | 型 | 既定値 | 説明 |
|---|---|---|---|
size | small | medium | large | "small" | The track's weight and the stop dots' size (and, where a system says so, the handle's height). Small is the everyday slider; medium and large give a prominent control (a volume or brightness slider) more weight. The hit area always meets the minimum target. A design system may add values. |
orientation | horizontal | vertical | "horizontal" | Horizontal runs from the inline start (min) to the inline end (max); vertical runs from the bottom (min) to the top (max). |
value | number | 0 | The value of the only handle, or of a range's end handle. |
startValue | number | 0 | The value of a range's start handle. Ignored while range is false. |
range | boolean | false | Draws two handles, choosing the range from startValue to value (a price filter). |
min | number | 0 | The lowest value, at the track's start. |
max | number | 100 | The highest value, at the track's end. |
step | number | 0 | 0 is continuous. Above 0 the slider is discrete: its values are min plus whole multiples of step, up to max. |
origin | number | null | Where the active track starts. Null starts it at min. A value inside the range makes a centered slider (a balance control) whose active track grows toward either side. Ignored while range is true. |
stops | boolean | false | Draws a stop dot at every value a discrete slider can take. Meant for a few steps; ignored while step is 0. |
valueIndicator | none | active | always | "none" | Whether a handle shows its value beside it: never, while it is pressed or has keyboard focus, or all the time. |
disabled | boolean | false | Prevents interaction and removes the handles from the focus order. |
label | string | "" | Names the slider (a range's end handle) for assistive technology. Never drawn: a visible label is the product's text next to the slider, in the same words. Required. |
startLabel | string | "" | Names a range's start handle ("Minimum price"). Required while range is true. |
valueText | string | "" | The value as words ("40 %", "3 stars"), spoken and shown by the value indicator in place of the number. For a range, the end handle's. |
startValueText | string | "" | The start handle's valueText, for a range. |
イベント
| イベント | 説明 |
|---|---|
input | The person changed a value; carries value and, for a range, startValue. Emitted for every change during a drag, not when the product sets a value. |
change | The person finished changing a value (the press ended, or a key or assistive-technology adjustment was made); carries value and, for a range, startValue. Always after the input it follows. |
状態
振る舞い
EARS 記法による要件です。各プラットフォームの実装は、この ID に対応するテストで検証されます。要件の原文は仕様ファイルのものをそのまま掲載しています。
| ID | 要件 |
|---|---|
SLD-1 | THE slider SHALL keep value (and, while range is true, startValue) between min and max; WHILE step is greater than 0 it SHALL take only min plus whole multiples of step that do not exceed max, snapping to the nearest, and WHILE step is 0 any value between min and max. |
SLD-2 | WHEN the person presses the slider by pointer or touch — the track, a handle, or the space around them — THE slider SHALL move the handle nearer the press (for a range whose handles meet, the one that can move toward the press) to the value under it and, WHILE the press moves, SHALL make the handle follow it along the track, clamped to the handle's range and snapped to step; it SHALL emit input once for each value change and, WHEN the press ends with a value other than the one it started with, change once after the last input. On touch the handle SHALL move once the press has travelled along the track by the platform's touch slop, or when a press that did not move ends; a press that first travels across the track by the slop SHALL be left to an enclosing scroll view and SHALL change nothing. |
SLD-3 | WHILE a handle has keyboard focus THE slider SHALL increase its value by one keyboard step with Right Arrow or Up Arrow and decrease it with Left Arrow or Down Arrow (Right and Left swapped in a right-to-left horizontal slider), by ten keyboard steps with Page Up and Page Down, and set it to the lowest and highest value it can take with Home and End; the keyboard step is step, or one hundredth of max − min while step is 0. Each key press that changes the value SHALL emit input and then change once; a key press that changes nothing SHALL emit nothing. |
SLD-4 | WHEN assistive technology increments or decrements a handle (a vertical swipe on an adjustable element, the platform's increment and decrement actions) THE slider SHALL change its value by one keyboard step, and WHEN it sets a value directly where the platform allows that THE slider SHALL clamp and snap it; either SHALL emit input and then change once. |
SLD-5 | WHILE range is true THE slider SHALL draw a start handle at startValue and an end handle at value, SHALL stop each handle at the other's value so that the two may meet but never cross, and SHALL make each handle its own Tab stop, the start handle first, and its own element for assistive technology. |
SLD-6 | WHILE range is false THE slider SHALL draw the active track between origin (min while origin is null, and origin clamped to the range) and value, on whichever side of origin value lies; WHILE range is true it SHALL draw the active track between startValue and value. |
SLD-7 | THE slider SHALL be as long along its axis as its layout gives it and, across it, as thick as the larger of comp.slider.container.size and comp.slider.handle.height.small for size small (and so on for each size); it SHALL extend its hit area across its axis to sys.target.touch for touch input and sys.target.pointer for fine pointers without changing that size (a platform that cannot tell the input type SHALL use sys.target.touch), the whole slider being the hit area, and a handle drawn smaller than the target SHALL NOT make the hit area smaller. It SHALL draw the track comp.slider.track.thickness.small thick for size small (and so on), centered across the axis and inset from each end of the slider by half of comp.slider.container.size, so that a handle and its state layer stay inside the slider at min and max; a handle's center SHALL travel between the two points half the track's thickness in from the track's ends, concentric with its rounded ends. |
SLD-8 | THE slider SHALL draw the track in comp.slider.standard.track.color and the active track over it in comp.slider.standard.active-track.color. WHILE comp.slider.track.gap is 0 the track and the active track SHALL run under each handle and meet at its center, so that nothing lies between the active track and the handle; WHILE it is above 0 they SHALL stop that far from each side of each handle, measured from the handle's edge. The pieces SHALL be rounded by comp.slider.track.shape.small for size small (and so on), clamped to half the thickness, at the track's two ends and, WHILE comp.slider.track.gap is above 0, beside a handle; they SHALL be square where two pieces meet (under a handle while the gap is 0, and at an origin inside the travel). It SHALL draw each handle centered on the track's midline, comp.slider.standard.handle.width along the axis and comp.slider.handle.height.small across it for size small (and so on), rounded by comp.slider.handle.shape clamped to half its smaller side, painted as SLD-24 says, above the tracks — each part from the tokens of the state SLD-11 names. |
SLD-9 | THE slider SHALL draw a dot of comp.slider.stop-indicator.size.small for size small (and so on) centered on the track's midline at each end of the handles' travel that lies on the track rather than on the active track, and WHILE stops is true and step is greater than 0 also at every value the slider can take; a dot SHALL be drawn in comp.slider.standard.stop-indicator.color where it lies on the track and in comp.slider.standard.active-stop-indicator.color where it lies on the active track, SHALL NOT be drawn where a handle or its track gap covers it, and a size of 0 SHALL draw none. |
SLD-10 | THE slider SHALL draw each handle's container, a shape of comp.slider.container.size on each side with corners comp.slider.container.shape, centered on the handle and moving with it, filled with comp.slider.standard.container.color from the handle's state, behind the handle and above the tracks; it may extend beyond the track without affecting layout, and a size of 0 SHALL draw none. |
SLD-11 | WHILE a handle is hovered, keyboard-focused or pressed THE slider SHALL render that handle and its container from the component tokens of that handle's highest-precedence active state, with precedence pressed over focused over hovered, and the tracks, stop dots and opacity from the highest-precedence state of any of its handles; a handle is hovered while a fine pointer is over the slider and that handle is the one a press there would move; focus gained by pointer or touch SHALL NOT select the focused state. WHEN the colors change between states THE slider SHALL animate them over comp.slider.motion.state-duration with comp.slider.motion.state-easing, and at once where motion is reduced. |
SLD-12 | WHEN a handle receives keyboard focus THE slider SHALL show the focus ring around that handle without animation; focus gained by pointer or touch SHALL NOT show it. |
SLD-13 | WHEN the slider is pressed by pointer or touch THE slider SHALL show the pressed state of the handle the press moves without delay, SHALL keep it for as long as the press lasts, and SHALL keep it visible for at least sys.motion.duration.press-hold, even when the press ends sooner. |
SLD-14 | WHILE pressed THE slider SHALL answer as sys.behavior.pressed-feedback names: overlay applies the pressed tokens to the whole container at once; ripple grows the pressed state layer from the point of contact (from the center for keyboard activation); dim applies the pressed opacity to the whole control and draws no state layer; none draws no answer to the press. Under ripple and dim only the container color stays with the state under the press; handle, tracks, stop dots, opacity and shape still come from the pressed tokens. Under none every part stays with the state under the press. The ripple grows over comp.slider.motion.feedback-duration with comp.slider.motion.state-easing, fades over comp.slider.motion.state-duration with comp.slider.motion.state-easing once the press has ended and press-hold has passed, and appears whole where motion is reduced. The slider's point of contact is the pressed handle's center, because the handle moves to the press. |
SLD-15 | THE slider SHALL ease its container, handle and track corners by sys.shape.corner-smoothing (0 is a quarter circle, 0.6 the iOS continuous corner; a platform with only the OS curve draws it for any amount above 0) and show its keyboard focus as sys.behavior.focus-style names (ring or glow); a platform that cannot draw a choice SHALL fall back to the first value and state that in its README. |
SLD-16 | WHEN a value changes by a key, by assistive technology, by a press on the track that did not drag, or because the product set it, THE slider SHALL move the handle and the active track to it over comp.slider.motion.value-duration with comp.slider.motion.value-easing; WHILE a press drags a handle, the handle SHALL follow the press without delay; WHERE motion is reduced every change SHALL be shown at once. WHEN the product sets value or startValue THE slider SHALL NOT emit input or change. |
SLD-17 | WHILE valueIndicator is always, or valueIndicator is active and a handle is pressed or has keyboard focus, THE slider SHALL draw that handle's value indicator comp.slider.value-indicator.offset beyond the handle's outer edge across the axis — above the handle in a horizontal slider, at its inline start in a vertical one; for a round handle beyond the top of its circle, outline included, which lies half of comp.slider.handle.height.small from the track's midline for size small (and so on) — with its center on the handle's center along the axis, shifted along the axis only as far as it must to stay inside the window: the handle's value text on one line in comp.slider.value-indicator.label.typescale and comp.slider.value-indicator.label.color, centered in a container of comp.slider.value-indicator.container.color at least comp.slider.value-indicator.container.height high and as wide as the text plus comp.slider.value-indicator.container.padding-inline on each side but never narrower than it is high, rounded by comp.slider.value-indicator.container.shape. The value indicator SHALL be drawn above neighbouring content and above the handle and its container, without affecting layout or being clipped by the slider, SHALL take no focus and no input (a read overlay), SHALL be hidden from assistive technology, and SHALL fade in and out over comp.slider.motion.state-duration with comp.slider.motion.state-easing, at once where motion is reduced. |
SLD-18 | THE slider SHALL give each handle a value text: valueText for the only handle and a range's end handle, startValueText for a range's start handle; or, while that is empty, what the product's own function writes for that handle's value, WHERE the product gave the slider such a function in the platform's idiom; or, with neither, the value formatted as a number in the platform's locale with as many fraction digits as the keyboard step has, at most two; the value indicator SHALL show it and assistive technology SHALL read it as the handle's value. THE slider SHALL ask the function again at every change of a value and WHEN the function itself changes, SHALL take an empty answer as no answer, and SHALL announce nothing for a change of the words alone. |
SLD-19 | THE slider SHALL expose each handle as a slider (the adjustable trait on Apple platforms) named by label, or by startLabel for a range's start handle, with its value, its value text, the lowest and highest value it can take (for a range, bounded by the other handle), its orientation and its disabled state; the tracks, stop dots, container and value indicator SHALL be hidden from assistive technology. WHILE a handle's label (label, or startLabel for a range's start handle) is not empty THE slider SHALL expose it as that handle's accessible name, over a name the product gives the slider on the element (aria-label or aria-labelledby). WHILE label is empty and the product gives the slider a name of its own on the element — aria-label, or aria-labelledby naming an element — THE slider SHALL expose that name on each handle whose own label is empty. WHILE label is empty and the product gives it none, or range is true and startLabel is empty, THE slider SHALL still render, and in debug builds report that a handle has no accessible name: one name of the product's does not tell a range's two handles apart. |
SLD-20 | WHILE disabled is true THE slider SHALL NOT change a value or emit input or change, SHALL NOT be focusable, SHALL show no value indicator, SHALL expose the disabled state to assistive technology, and SHALL render its container, handles, tracks, stop dots and opacity from the disabled component tokens. |
SLD-21 | WHILE orientation is vertical THE slider SHALL run its track from the bottom (min) to the top (max), be as tall as its layout gives it, and lay out every part SLD-7 to SLD-17 name turned a quarter turn; WHEN the layout direction is right-to-left THE slider SHALL run a horizontal track from the right (min) to the left (max), mirroring the active track, the stop dots and the arrow keys (SLD-3), and SHALL NOT mirror a vertical slider. WHILE a value indicator is drawn in a right-to-left layout THE slider SHALL keep it centred on its handle and shift it along the axis only as far as it must to stay inside the window, away from whichever edge of the window it would cross, as in left-to-right (SLD-17): the shift is physical and is not mirrored. |
SLD-22 | IF value, startValue or origin lies outside min and max, or off a step, THE slider SHALL draw and expose it clamped and snapped without emitting input or change; IF startValue is greater than value while range is true THE slider SHALL draw both handles at value; IF max is not greater than min THE slider SHALL draw its handles at the track's start and take no input; IF step is below 0 THE slider SHALL treat it as 0. In debug builds it SHALL report each of these. |
SLD-23 | WHEN size names a value that the active design system does not have, or orientation or valueIndicator a value the component does not define, THE slider SHALL render with the default value (small, horizontal, none), and in debug builds report the unknown value. |
SLD-24 | THE slider SHALL fill the whole shape of each handle with comp.slider.standard.handle.color and draw the handle's outline over the fill, comp.slider.handle-outline.width wide inside the handle's edge, in comp.slider.standard.handle-outline.color, so that the outline never changes the handle's width or height and a width of 0 draws none; it SHALL raise the handle by comp.slider.standard.handle.elevation. The parts under a handle (the tracks where they meet, a stop dot, the container) SHALL show through it only as far as its fill is translucent. |
SLD-25 | THE slider SHALL take its layout direction from where it is used — the direction of the nearest ancestor that sets one, and the platform's own where none does — and SHALL have no direction setting of its own; WHEN that direction changes while the slider is shown THE slider SHALL draw itself for the new direction at once, without a motion of its own, keeping its values and its focus, each value indicator placed again by the new direction. |
SLD-26 | THE slider SHALL lay out a handle's value text in its value indicator as text of its own direction, isolated from the text around it: each takes the base direction of its first strong character, or the layout direction where it has none, so that a left-to-right word, a number with its sign or unit, a telephone number and an address keep their own order in a right-to-left layout and reorder nothing beside them; THE slider SHALL still place the indicator and align its lines by the layout direction, not by the text's own. |
SLD-27 | WHERE the platform has ARIA attributes (the web), WHEN the product sets an aria- attribute on the host, by the attribute or by the ARIA property that reflects it, THE slider SHALL move it to the data-aria- attribute of the same name, so that the host is no second node with its name, description or state, and SHALL expose it on the element that carries its role (every handle carries them) — an id reference by the elements it names in the host's tree or a tree around it, an error message as part of the description while the slider is invalid — except those the slider owns (aria-disabled), which it SHALL move and not expose. WHEN the product removes the aria- attribute or its data-aria- twin, or sets the ARIA property that reflects it (ariaLabel, ariaDescribedByElements…) to null, THE slider SHALL take it off that element. WHEN the product sets an aria- attribute the slider owns THE slider SHALL report it in debug builds. |
プラットフォーム別の名前対応
パリティは API が同一であることを意味しません。同じ契約を、各プラットフォームの流儀で表現します。
| 仕様 | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
|---|---|---|---|---|---|
| コンポーネント | tanrei-slider | TanreiSlider | TanreiSlider | TanreiSlider | Slider |
size · プロパティ | size | size | size | size | size |
orientation · プロパティ | orientation | orientation | orientation | orientation | orientation |
value · プロパティ | value | value | value | value | value |
startValue · プロパティ | startValue | value | value | start | startValue |
range · プロパティ | range | value | value | range | range |
min · プロパティ | min | bounds | valueRange | min | minimumValue |
max · プロパティ | max | bounds | valueRange | max | maximumValue |
step · プロパティ | step | step | step | step | step |
origin · プロパティ | origin | origin | origin | origin | origin |
stops · プロパティ | stops | showsStops | showStops | showStops | stops |
valueIndicator · プロパティ | valueIndicator | valueIndicator | valueIndicator | valueIndicator | valueIndicator |
disabled · プロパティ | disabled | disabled | enabled | onChanged | disabled |
label · プロパティ | label | label | contentDescription | semanticLabel | accessibilityLabel |
startLabel · プロパティ | startLabel | startLabel | startContentDescription | startSemanticLabel | startAccessibilityLabel |
valueText · プロパティ | valueText | valueText | stateDescription | semanticValue | valueText |
startValueText · プロパティ | startValueText | startValueText | startStateDescription | startSemanticValue | startValueText |
input · イベント | input | value | onValueChange | onChanged | onValueChange |
change · イベント | change | onCommit | onValueChangeFinished | onChangeEnd | onSlidingComplete |
| 備考 | Attributes are kebab-case (start-value, value-indicator, start-label, value-text, start-value-text). Each handle is an element with role="slider" and its aria-value attributes, aria-orientation and aria-label in the shadow root (not ElementInternals, which axe cannot see). Not <input type="range">: it has one handle, no gap, no stop dots, and its parts cannot be styled alike in every engine. The handle's outline is its box's border with box-sizing: border-box, over its background (the fill), so it keeps its width and height (SLD-24); while track.gap is 0 the two pieces of the tracks meet at the handle's center under it (SLD-8). Form-associated: it takes name and submits value (a range submits startValue, then value, under the same name), and it sets its own value and startValue before firing input and change, as a native control does. Snapshot harness: the stages of SLD-7. The product's function for a value's words (SLD-18) is formatValue, a property and never an attribute: ((value: number) => string) | null, null by default; it is asked for each handle at every change of a value and when the property itself is set. | Slider idiom: TanreiSlider(_ label:, value: Binding<Double>, in bounds: ClosedRange<Double> = 0...100, step:); a range is the initializer whose value is a Binding<ClosedRange<Double>> (lower bound startValue, upper bound value) and which also takes startLabel. Every change writes the binding, which is the input event. onCommit is Tanrei's own parameter, called when a change is finished (SLD-2, SLD-3, SLD-4), as the text field's is; SwiftUI's onEditingChanged reports a drag's start and end, not a change. SwiftUI's own Slider is not used: its track and handle cannot take the tokens. Each handle is an adjustable element (.accessibilityAdjustableAction, .accessibilityValue); disabled follows .disabled(_:). Lagging: ships an earlier form of the slider — a solid round handle, tracks cut at the handle's edge (square there while track.gap is 0), one stop-dot size for every size. It does not draw yet: the handle's fill and outline (SLD-24), the tracks meeting under the handle while track.gap is 0 (SLD-8), the stop dot per size (SLD-9) and the value indicator's placement over a round handle (SLD-17). Not built on this platform yet: the product's function for a value's words (SLD-18) is a format: ((Double) -> String)? = nil parameter. Not built on this platform yet: the stage color a fixture's surface names, which the continuous-on-container-highest fixture draws on. | Compose idiom (as Slider and RangeSlider): TanreiSlider(value: Float, onValueChange, modifier, enabled, valueRange: ClosedFloatingPointRange<Float> = 0f..100f, step: Float = 0f, onValueChangeFinished, …); a range is the overload whose value is a ClosedFloatingPointRange<Float> (start and end) and which also takes startContentDescription and startStateDescription. step is a size, not Material's count of steps. State hoisting: the caller moves value from onValueChange. enabled is the inverse flag. Each handle has Compose's slider semantics (progressBarRangeInfo and setProgress), with stateDescription as its value text. Lagging: ships an earlier form of the slider — a solid round handle with its shape clipped out of the tracks, one stop-dot size for every size. It does not draw yet: the handle's fill and outline (SLD-24), the tracks meeting under the handle while track.gap is 0 (SLD-8), the stop dot per size (SLD-9) and the value indicator's placement over a round handle (SLD-17). Not built on this platform yet: the product's function for a value's words (SLD-18) is a format: ((Float) -> String)? = null parameter. Not built on this platform yet: the stage color a fixture's surface names, which the continuous-on-container-highest fixture draws on. | Flutter idiom (as Slider): TanreiSlider(value:, onChanged:, onChangeEnd:, min: 0, max: 100, step: 0, …), with step a size rather than Material's divisions; a range is the named constructor TanreiSlider.range(start:, end:, onChanged: (start, end) {…}, …), since Flutter's RangeValues belongs to Material. A null onChanged disables it. orientation is Flutter's Axis. Each handle is a Semantics(slider: true, value:, increasedValue:, decreasedValue:, onIncrease:, onDecrease:) node; the widgets library draws everything else. Lagging: ships an earlier form of the slider — a solid round handle, tracks cut at the handle's edge and rounded there (a notch between the round end and the handle), one stop-dot size for every size. It does not draw yet: the handle's fill and outline (SLD-24), the tracks meeting under the handle while track.gap is 0 (SLD-8), the stop dot per size (SLD-9) and the value indicator's placement over a round handle (SLD-17). Not built on this platform yet: the product's function for a value's words (SLD-18) is format: String Function(double)?. Not built on this platform yet: the stage color a fixture's surface names, which the continuous-on-container-highest fixture draws on. | Controlled, in the community slider's idiom (value, minimumValue, maximumValue, step, onValueChange, onSlidingComplete), without depending on it: React Native has no slider in its core. A range adds range and startValue, and both callbacks receive (value, startValue). Each handle is a view with accessibilityRole="adjustable", accessibilityValue ({ min, max, now, text }) and the increment and decrement accessibility actions; the drag is a the touch responder props (onStartShouldSetResponder and the rest) that yields to an enclosing ScrollView as SLD-2 says. The arrow keys work where a hardware keyboard is attached, as the tabs row's do. Lagging: ships an earlier form of the slider — a solid round handle, tracks cut at the handle's edge and rounded there (a notch between the round end and the handle), one stop-dot size for every size. It does not draw yet: the handle's fill and outline (SLD-24), the tracks meeting under the handle while track.gap is 0 (SLD-8), the stop dot per size (SLD-9) and the value indicator's placement over a round handle (SLD-17). Not built on this platform yet: the product's function for a value's words (SLD-18) is a formatValue prop, (value: number) => string. Not built on this platform yet: the stage color a fixture's surface names, which the continuous-on-container-highest fixture draws on. |
トークン
| トークン | 参照先 | 解決値(ライト) |
|---|---|---|
--tanrei-comp-slider-container-shape | sys.shape.corner.full | 9999px |
--tanrei-comp-slider-container-size | — | 40px |
--tanrei-comp-slider-disabled-opacity | — | 1 |
--tanrei-comp-slider-focused-opacity | — | 1 |
--tanrei-comp-slider-handle-outline-width | — | 3px |
--tanrei-comp-slider-handle-height-large | — | 20px |
--tanrei-comp-slider-handle-height-medium | — | 20px |
--tanrei-comp-slider-handle-height-small | — | 20px |
--tanrei-comp-slider-handle-shape | sys.shape.corner.full | 9999px |
--tanrei-comp-slider-hovered-opacity | — | 1 |
--tanrei-comp-slider-motion-feedback-duration | sys.motion.role.feedback | 450ms |
--tanrei-comp-slider-motion-state-duration | sys.motion.role.state.compact | 200ms |
--tanrei-comp-slider-motion-state-easing | sys.motion.easing.state | cubic-bezier(0.2, 0, 0, 1) |
--tanrei-comp-slider-motion-value-duration | sys.motion.role.selection.travel | 250ms |
--tanrei-comp-slider-motion-value-easing | sys.motion.easing.spatial | cubic-bezier(0.2, 0, 0, 1) |
--tanrei-comp-slider-pressed-opacity | — | 1 |
--tanrei-comp-slider-standard-active-stop-indicator-color | sys.color.on-primary | |
--tanrei-comp-slider-standard-active-track-color | sys.color.primary | |
--tanrei-comp-slider-standard-container-color | — | |
--tanrei-comp-slider-standard-disabled-active-stop-indicator-color | — | |
--tanrei-comp-slider-standard-disabled-active-track-color | — | |
--tanrei-comp-slider-standard-disabled-container-color | — | |
--tanrei-comp-slider-standard-disabled-handle-outline-color | — | |
--tanrei-comp-slider-standard-disabled-handle-color | — | |
--tanrei-comp-slider-standard-disabled-handle-elevation | — | |
--tanrei-comp-slider-standard-disabled-handle-width | — | 20px |
--tanrei-comp-slider-standard-disabled-state-layer-color | — | |
--tanrei-comp-slider-standard-disabled-stop-indicator-color | — | |
--tanrei-comp-slider-standard-disabled-track-color | — | |
--tanrei-comp-slider-standard-focused-active-stop-indicator-color | — | |
--tanrei-comp-slider-standard-focused-active-track-color | — | |
--tanrei-comp-slider-standard-focused-container-color | — | |
--tanrei-comp-slider-standard-focused-handle-outline-color | — | |
--tanrei-comp-slider-standard-focused-handle-color | — | |
--tanrei-comp-slider-standard-focused-handle-elevation | — | |
--tanrei-comp-slider-standard-focused-handle-width | — | 20px |
--tanrei-comp-slider-standard-focused-state-layer-color | — | |
--tanrei-comp-slider-standard-focused-stop-indicator-color | — | |
--tanrei-comp-slider-standard-focused-track-color | — | |
--tanrei-comp-slider-standard-handle-outline-color | sys.color.primary | |
--tanrei-comp-slider-standard-handle-color | sys.color.surface | |
--tanrei-comp-slider-standard-handle-elevation | sys.elevation.level0 | |
--tanrei-comp-slider-standard-handle-width | — | 20px |
--tanrei-comp-slider-standard-hovered-active-stop-indicator-color | — | |
--tanrei-comp-slider-standard-hovered-active-track-color | — | |
--tanrei-comp-slider-standard-hovered-container-color | — | |
--tanrei-comp-slider-standard-hovered-handle-outline-color | — | |
--tanrei-comp-slider-standard-hovered-handle-color | — | |
--tanrei-comp-slider-standard-hovered-handle-elevation | — | |
--tanrei-comp-slider-standard-hovered-handle-width | — | 20px |
--tanrei-comp-slider-standard-hovered-state-layer-color | — | |
--tanrei-comp-slider-standard-hovered-stop-indicator-color | — | |
--tanrei-comp-slider-standard-hovered-track-color | — | |
--tanrei-comp-slider-standard-pressed-active-stop-indicator-color | — | |
--tanrei-comp-slider-standard-pressed-active-track-color | — | |
--tanrei-comp-slider-standard-pressed-container-color | — | |
--tanrei-comp-slider-standard-pressed-handle-outline-color | — | |
--tanrei-comp-slider-standard-pressed-handle-color | — | |
--tanrei-comp-slider-standard-pressed-handle-elevation | — | |
--tanrei-comp-slider-standard-pressed-handle-width | — | 20px |
--tanrei-comp-slider-standard-pressed-state-layer-color | — | |
--tanrei-comp-slider-standard-pressed-stop-indicator-color | — | |
--tanrei-comp-slider-standard-pressed-track-color | — | |
--tanrei-comp-slider-standard-state-layer-color | comp.slider.standard.handle-outline.color | |
--tanrei-comp-slider-standard-stop-indicator-color | sys.color.on-surface-variant | |
--tanrei-comp-slider-standard-track-color | sys.color.surface-variant | |
--tanrei-comp-slider-stop-indicator-size-large | — | 4px |
--tanrei-comp-slider-stop-indicator-size-medium | — | 3px |
--tanrei-comp-slider-stop-indicator-size-small | — | 2px |
--tanrei-comp-slider-track-gap | sys.space.space0 | 0px |
--tanrei-comp-slider-track-shape-large | sys.shape.corner.full | 9999px |
--tanrei-comp-slider-track-shape-medium | sys.shape.corner.full | 9999px |
--tanrei-comp-slider-track-shape-small | sys.shape.corner.full | 9999px |
--tanrei-comp-slider-track-thickness-large | — | 8px |
--tanrei-comp-slider-track-thickness-medium | — | 6px |
--tanrei-comp-slider-track-thickness-small | — | 4px |
--tanrei-comp-slider-value-indicator-container-color | sys.color.inverse-surface | |
--tanrei-comp-slider-value-indicator-container-height | — | 24px |
--tanrei-comp-slider-value-indicator-container-padding-inline | sys.space.space100 | 8px |
--tanrei-comp-slider-value-indicator-container-shape | sys.shape.corner.small | 6px |
--tanrei-comp-slider-value-indicator-label-color | sys.color.inverse-on-surface | |
--tanrei-comp-slider-value-indicator-offset | sys.space.space100 | 8px |
--tanrei-comp-slider-value-indicator-label-typescale | sys.typescale.label-small | 500 12px/1.3333 |
フィクスチャ
基準となる描画パターンです。全プラットフォームが同じ ID でスナップショットを撮り、結果を比較できるようにしています。
size: small (9)
continuous
value: 40 label: Volume continuous-on-container-highest
value: 40 label: Volume discrete-stops
value: 30 step: 10 stops: true label: Brightness range
value: 60 startValue: 20 range: true label: Maximum price startLabel: Minimum price centered
value: 20 min: -50 max: 50 origin: 0 label: Balance value-indicator
value: 40 valueIndicator: always label: Volume vertical
orientation: vertical value: 60 label: Volume disabled
value: 40 disabled: true label: Volume disabled-stops
value: 60 step: 20 stops: true disabled: true label: Brightness size: medium (1)
medium
size: medium value: 40 label: Volume size: large (1)
large
size: large value: 40 label: Volume 生成元 specs/slider.spec.json, tokens/comp/slider.tokens.json, design/tokens/
感覚で値を決め、動かしながらその効果を確かめたいときに使います。音量、明るさ、写真の露出、地図の検索半径などです。範囲を選ぶスライダーは、価格のように下限と上限のある絞り込みに向いています。
位置よりも正確な数字が大事な値、たとえば金額や個数には、テキストフィールドを使うか、スライダーの隣にテキストフィールドを置いてどちらでも入力できるようにします。「低・中・高」のように名前の付いた選択肢が数個しかないなら、ラジオボタンで一つひとつに名前を見せます。セグメントボタンを提供するシステムなら、セグメントボタンも使えます。
- 連続(
stepが 0)は、minとmaxの間の好きな値を取ります。途中の値にも意味があり、効果がすぐに見えるときに使います。 - 刻み(
stepが 0 より大きい)は、minにstepの整数倍を足した値に吸着します。星の数、ポイント単位の文字サイズ、10% 刻みの割合など、区切りのよい値だけが意味を持つときに使います。 stopsを付けると、刻みのスライダーが取りうる値すべてに点を描きます。刻みが少なく、数えられるくらいのときに使います。刻みが多いと点が詰まってトラックが見づらくなるので、付けません。
矢印キーは 1 刻みずつ動かします。連続のスライダーでは範囲の 100 分の 1 ずつです。Page Up と Page Down はその 10 倍ずつ動かします。
range を付けると、startValue から value までの 2 つのハンドルを描きます。2 つのハンドルは重なることはあっても、入れ替わることはありません。それぞれが Tab で止まる位置になり、スクリーンリーダーからはそれぞれ独立したコントロールとして扱われ、そのハンドルがまだ動ける範囲も読み上げられます。両方のハンドルに名前を付けます。startLabel(「下限価格」)と label(「上限価格」)です。
origin は、アクティブトラックがどこから伸びるかを決めます。空なら min から伸びます。範囲の途中の値、たとえば -50 から 50 のバランス調整で 0 を指定すると、アクティブトラックはそこから左右どちらへも伸びます。トラックの両端には目盛りの点が残るので、両方の限界が見えたままです。
valueIndicator を設定すると、ハンドルの横に小さなラベルで値を表示します。
| 値 | 表示するとき | 用途 |
|---|---|---|
none(既定) |
表示しない | 効果が画面のほかの場所に表れるスライダー。音量、明るさなど |
active |
ハンドルを押している間と、キーボードフォーカスがある間 | 指でハンドルが隠れても、動かしながら数値を読みたい値 |
always |
常に表示する | 常に読める必要があるが、スライダーの隣に自分でテキストを置く余地がない値 |
表示は、横向きのスライダーではハンドルの上に、縦向きではハンドルの先頭側に出ます。valueText があればそれを、なければプラットフォームのロケールで書式化した数値を、キーボードの 1 刻みと同じ桁数(最大で小数第 2 位まで)で表示します。これは値を見せるためだけのもので、フォーカスも入力も受け取りません。スクリーンリーダーは、この表示ではなくハンドルから値を読みます。
数字だけでは意味が伝わりにくいときは、valueText に今の値を表す言葉を設定します。「40%」「星 3 つ」「300 ドル」などです。値の表示にも、スクリーンリーダーの読み上げにも、数字の代わりにこの言葉が使われます。範囲では、始点側のハンドルに startValueText を使います。値が変わるたびに更新してください。
1 回だけ書いた言葉は、最初のドラッグのあと、実際の値と合わなくなります。そのためスライダーは、値からその言葉を作る関数を 1 つ、1 回だけ受け取ることもできます。スライダーは、値が変わるたびに、ハンドルごとにこの関数を呼びます。valueText と startValueText を設定していれば、そちらが優先されます。Web では formatValue で、プロパティであり、属性はありません。ほかのプラットフォームはまだ実装していません。
const yen = new Intl.NumberFormat('ja-JP', { style: 'currency', currency: 'JPY' });
document.querySelector('[name="price"]').formatValue = (value) => yen.format(value);使われている場所は、スライダーフィールドです。フィールドとスライダーを 1 つのコンポーネントにしたもので、この言葉をラベルの行の末尾に描きます。スライダーに、描かれるラベル、補足、エラーが必要なときに使います。
small はふだん使いのスライダーです。medium と large はトラックが太くなり、メディア画面の音量や明るさのように目立たせたいコントロールに向いています。どのサイズでも、最小ターゲットは満たします。
縦向きのスライダーは、書字方向にかかわらず下(min)から上(max)へ伸びます。横向きのスライダーは行頭から伸びるので、右から左のレイアウトでは min が右側になります。
- スライダーの隣に、
labelと同じ言葉で目に見えるラベルを置きます。 - ドラッグ中は効果をその場で見せ、保存は
inputのたびではなくchangeで行います。 - スライダーの取りうる値がどれも意味のある値になるように、
min、max、stepを選びます。 - 数字だけでは何の数か分からないときは、
valueTextに単位を含めます。
- 日付や金額など、正確に指定する必要がある値にスライダーを使わない。
- オンとオフしかない設定にスライダーを使わない。スイッチを使います。
- 刻みの多いスライダーに目盛りの点を描かない。
- スライダーをツールバーに入れない。ツールバーがフォーカスの移動に使う矢印キーを、スライダーも必要とします。
- ロール
slider- ラベル付け
- label names the slider, or a range's end handle; startLabel names a range's start handle. Neither is drawn: a visible label is the product's text beside the slider, in the same words. valueText replaces the spoken number ("40 %", "3 stars"). The tracks, stop dots, state layer and value indicator are decorative.
- 最小ターゲット
- 見た目のサイズが小さくても、ヒット領域は最小ターゲットサイズを満たします。 minimum 32px · pointer 44px · spacing 8px · touch 48px
キーボード操作
| キー | 動作 |
|---|---|
| Tab / Shift+Tab | Moves focus to the handle, and for a range to the start handle, then the end handle. |
| Right Arrow / Up Arrow | Increases the focused handle's value by one keyboard step (Right Arrow decreases it in a right-to-left horizontal slider). |
| Left Arrow / Down Arrow | Decreases the value by one keyboard step (Left Arrow increases it in a right-to-left horizontal slider). |
| Page Up / Page Down | Increases or decreases the value by ten keyboard steps. |
| Home / End | Sets the value to the lowest or highest the handle can take. |
備考
- Each handle is one slider for assistive technology: role slider with aria-valuemin, aria-valuemax, aria-valuenow, aria-valuetext and aria-orientation on the web; the adjustable trait with an accessibility value on Apple platforms (a vertical swipe increments and decrements); a range with a current value and the set-progress action on Android; a slider semantics node with increase and decrease actions in Flutter; role adjustable with accessibilityValue and increment and decrement actions in React Native.
- A range is two sliders, the WAI-ARIA multi-thumb pattern: each handle's lowest and highest value is bounded by the other handle, so a screen reader announces the range each can still reach.
- The value is read from the handle and the active track. The handle must be told apart from each thing it lies on — the track, the active track and the surface behind the slider — by its outline (comp.slider.standard.handle-outline.color, where comp.slider.handle-outline.width is above 0) or by its fill (comp.slider.standard.handle.color), at 3:1 or more; comp.slider.standard.active-track.color must stay at least 3:1 against the track and the surface. In the default system the outline carries it against the track and the surface, and the fill against the active track. A faint track keeps its end visible by the stop dot at the end of the travel (SLD-9).
- The handle may be drawn smaller than the minimum target (20 against 48 in the default system): the whole slider takes the press across its axis at the target's size (SLD-7), so every handle keeps its whole target, a range's two handles included, and no target is reported larger than the area that takes the press.
- Text size does not change the slider: it has no text of its own except the value indicator, which grows with the text.
- How a state looks is a value decision of the active design system; components read the state's tokens and never compute the effect themselves.
生成元 specs/slider.spec.json, tokens/sys/measure.tokens.json
- 各ハンドルは、支援技術からはスライダーとして扱われます。名前は
label(範囲の始点側はstartLabel)で、値、値のテキスト、取りうる最小値と最大値、向き、無効状態を伝えます。Apple のプラットフォームでは調整可能な要素になり、上下のスワイプで 1 刻みずつ動きます。 - 範囲は 2 つのスライダーです(WAI-ARIA のマルチサム・パターン)。各ハンドルの限界はもう一方のハンドルで区切られるので、スクリーンリーダーはそのハンドルがまだ動ける範囲を読み上げます。
- トラック、目盛りの点、ステートレイヤー、値の表示は、支援技術から隠します。
- 各ハンドルが Tab で止まる位置になり、始点側のハンドルが先です。矢印キーで 1 刻み、Page Up と Page Down で 10 刻み、Home と End で最小値と最大値へ動きます。右から左のレイアウトの横向きのスライダーでは、右矢印と左矢印の向きが入れ替わります。
- スクリーンリーダーの増減のアクションでは 1 刻みずつ動きます。プラットフォームが値の直接指定を許す場合は、その値を範囲内に収め、刻みに合わせます。
- スライダーのどこを押しても、近いほうのハンドルがそこへ動き、そのままドラッグで追従します。タッチでは、最初にトラックと直交する方向へ動いた操作は周りのスクロールビューに任せるので、スクロールしようとした指をスライダーが奪うことはありません。
- スライダー全体がヒット領域で、トラックと直交する方向に最小ターゲットまで広がります。ハンドルは最小ターゲットより小さく描かれますが、それでヒット領域が小さくなることはないので、範囲を選ぶスライダーの 2 つのハンドルも、それぞれターゲット全体を持ちます。
- フォーカスインジケーターは、キーボードフォーカスのあるハンドルの周りにだけ表示します。
- 既定のシステムでは、ハンドルは、重なるどの部分とも 3:1 以上で見分けられます。トラックとページに対しては輪郭線で、アクティブトラックに対しては塗りで見分けます。アクティブトラックはトラックとページに対して 3:1 以上を保ち、薄いトラックでも、目盛りの点で端が見えます。
- 無効なスライダーはフォーカスを受け取らず、値の表示も出さず、無効状態を伝えます。
- 文字サイズを変えて大きくなるのは値の表示だけです。
labelやstartLabelがない場合、値、始点の値、起点が範囲外か刻みから外れている場合、始点の値が終点の値より大きい場合、maxがminより大きくない場合、刻みが負の場合、サイズ・向き・値の表示に知らない値が指定された場合は、デバッグビルドで報告します。
プラットフォームごとの既知の制約:
- Web では、各ハンドルのスライダーのロールを
ElementInternalsではなくシャドウルートの中の要素に付けます。ElementInternalsで設定したセマンティクスは axe-core から見えないためです。<input type="range">も使いません。ハンドルが 1 つしかなく、パーツの見た目をどのエンジンでもそろえることができないためです。 - Web:支援技術は、ブラウザーが送る矢印キーを通じて ARIA のスライダーを動かします。そのため、値を直接設定することはできません。
- Web:値の表示はトップレイヤーにありません。
overflow: hiddenの祖先要素には切り取られ、後に置かれたz-indexが 1 より大きい配置済みの兄弟要素には覆われます。 - SwiftUI では、ハンドルの最小値と最大値、向きを伝えられません。また macOS では、ハンドルは支援技術にとってスライダーになりません。
- SwiftUI はタッチとポインターを区別できません。iOS では iPad のポインターも含めてすべての押下をタッチとして、macOS ではすべての押下をポインターとして扱います。iOS 18 より前では、タッチのドラッグは SwiftUI のジェスチャーになるため、スライダーを囲むスクロールビューが操作を引き継げないことがあります。
- SwiftUI:値の表示は、ウィンドウではなくスライダーの内側に収まるように置かれ、スライダーより後に描かれるビューに覆われることがあります。
- SwiftUI:シミュレーターは自動操作中にキーボードフォーカスを渡さないため、キー操作は規則としてテストしているだけで、実際のキーボードではまだ確かめていません。
- Compose のスライダーのセマンティクスには向きがないため、ハンドルの向きは伝わりません。
- Flutter では、ハンドルの最小値と最大値、向きを伝えられず、値を直接設定するアクションもありません。
- Flutter は、どのロケールでも小数点に
.を使って数値を書きます。問題になる場合はvalueTextを設定してください。 - Flutter:ヒット領域がトラックと交わる方向に広がるのは、スライダーの親がスライダーより大きい場合だけです。親がスライダーとちょうど同じ大きさだと、広がった分は切り取られます。
- React Native には、値を直接設定するアクションも向きのプロパティもないため、どちらも伝わりません。
- React Native では、矢印キーはタブの列と同じく、ハードウェアキーボードをつないだときだけ働きます。
- React Native は、すべての押下をタッチとして扱います。マウスやスタイラスで押しても、動かすか離すまでハンドルは動きません。
- React Native は値の表示をオーバーレイ層ではなくスライダーの中に描きます。そのため、ウィンドウではなくスライダーの内側に収まり、スライダーより後に描かれるビューに覆われることがあります。
- React Native:レイアウト、ドラッグとスクロールビューへの譲り方、調整可能なハンドルは、実機ではまだ確かめていません。
- SwiftUI、Compose、Flutter、React Native は、まだ以前の見た目で描きます。塗りつぶしのハンドル、どのサイズでも同じ大きさの目盛りの点、そしてハンドルの下で出会うのではなくハンドルのところで切れるトラックです。切れ目の描き方もプラットフォームによって異なり、SwiftUI は四角く切り、Flutter と React Native は丸めて切れ込みを残し、Compose はハンドルの形で切り抜きます。
cupertinoのライトスキームでは、白いハンドルが白いページの上で 1.0:1 になり、値を示すパーツに必要な 3:1 に届きません。Apple の描き方にならって輪郭線はなく、影と、隣にある色付きのアクティブトラックで見分けます。ハンドルとページのコントラストを確かめる不変条件はありません。この 1.0:1 は参考として残す計測値で、模倣プリセットには Tanrei のアクセシビリティ基準を適用しません。またcupertinoでは、トラックの両端も含めて目盛りの点を描きません。m3-likeでは、スライダーは Material が公開している寸法から、縦長のバーのハンドルで描かれます。この値は、忠実度の参照データではまだ確かめていません。m3-expressive-likeでは、Material が太いトラックの中に描くアイコンを置く場所がありません(mimicry-gaps 台帳slider-inset-icon)。アイコンはスライダーの横に置いてください。
- すべてのスライダーに、プロダクトの言語で
labelを付け、範囲ならstartLabelも付けます。同じ言葉を、目に見えるラベルとして隣に置きます。 - 数字だけでは分かりにくいときは
valueTextを設定し、値に合わせて更新します。 - 変更の結果は見える場所に表し、変更を反映できなかったときはテキストで知らせます。スライダーが読み上げるのは自分の値だけです。
cupertinoでは、ハンドルが白く、トラックの端に目盛りの点もないので、できれば真っ白なサーフェスの上にスライダーを置かないようにします。- 塗りつぶしのカードのような、最も高いコンテナのトーンの面の上では、非アクティブなトラックはほぼ同じトーンなので見えにくくなります。そうした面の上に置くときは、レイヤーで
comp.slider.standard.track.colorをより強いロールに付け替えます。値は、それでもハンドルとアクティブトラックが示します。 - Web でフォームと一緒に値を送るときは、スライダーに
nameを付けます。