Comparison Table
A plan-versus-feature matrix built as a real table, with readable boolean cells.
6 個のフレームワーク初級
Two photographs stacked under a draggable wipe handle that also works from the keyboard.
<!--
Two photographs stacked, with the top one clipped to a movable edge. The edge
is the entire control - and a control you can only drag is a control a
keyboard user cannot touch. It is a real role="slider": arrow keys nudge,
Home/End jump to either extreme, and aria-valuenow reports where it is.
Both images keep their own alt text. They are two different pictures of the
same place, not one picture with a decoration on top.
-->
<div class="wipe" data-wipe>
<img class="wipe__image" src="/images/kitchen-after.jpg" alt="Kitchen after the renovation" />
<div class="wipe__clip" data-wipe-clip>
<img class="wipe__image" src="/images/kitchen-before.jpg" alt="Kitchen before the renovation" />
</div>
<span class="wipe__tag wipe__tag--before" aria-hidden="true">Before</span>
<span class="wipe__tag wipe__tag--after" aria-hidden="true">After</span>
<div
class="wipe__handle"
data-wipe-handle
role="slider"
tabindex="0"
aria-label="Reveal the before image"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="50"
aria-valuetext="50% before"
>
<span class="wipe__grip" aria-hidden="true"></span>
</div>
</div>
<script>
(function () {
document.querySelectorAll('[data-wipe]').forEach(function (root) {
var clip = root.querySelector('[data-wipe-clip]');
var handle = root.querySelector('[data-wipe-handle]');
var pos = 50;
function set(next) {
pos = Math.min(100, Math.max(0, next));
// inset() from the right: the before image keeps its left-hand slice.
clip.style.clipPath = 'inset(0 ' + (100 - pos) + '% 0 0)';
handle.style.left = pos + '%';
handle.setAttribute('aria-valuenow', String(Math.round(pos)));
handle.setAttribute('aria-valuetext', Math.round(pos) + '% before');
}
function fromPointer(event) {
var rect = root.getBoundingClientRect();
set(((event.clientX - rect.left) / rect.width) * 100);
}
// One pointer path covers mouse, touch and pen; the capture keeps the drag
// alive after the cursor leaves the frame, which a mousemove listener on
// the element alone would not.
root.addEventListener('pointerdown', function (event) {
root.setPointerCapture(event.pointerId);
fromPointer(event);
});
root.addEventListener('pointermove', function (event) {
if (root.hasPointerCapture(event.pointerId)) fromPointer(event);
});
handle.addEventListener('keydown', function (event) {
// Shift jumps in tens - 100 arrow presses to cross the image is not a
// keyboard equivalent of a drag, it is a punishment.
var step = event.shiftKey ? 10 : 1;
var next = null;
if (event.key === 'ArrowLeft' || event.key === 'ArrowDown') next = pos - step;
else if (event.key === 'ArrowRight' || event.key === 'ArrowUp') next = pos + step;
else if (event.key === 'Home') next = 0;
else if (event.key === 'End') next = 100;
if (next === null) return;
event.preventDefault();
set(next);
});
set(pos);
});
})();
</script>| Prop | 型 | デフォルト | 説明 |
|---|---|---|---|
before必須 | WipeImage | - | 「ビフォー」側に表示する画像。 |
after必須 | WipeImage | - | 「アフター」側に表示する画像。 |
defaultValue | number | 50 | 仕切りの位置。左端からの割合(%)で指定します。 |
ariaLabel | string | - | ボタンのアクセシブルな名前。アイコンのみのボタンでは必須です。 |
className | string | - | ルート要素にマージされる追加クラス。 |
The wipe is a `clip-path: inset()` on the top layer rather than a width change, because both layers stay full size and therefore pixel-aligned - resize one instead and the two photographs slide against each other as the edge moves. The handle is the reason this component is rated advanced: it is a real `role="slider"` with `aria-valuenow`, arrow keys, Shift for ten-percent jumps and Home/End, because a handle you can only drag is a handle a keyboard user cannot touch at all, and `role="slider"` without key handling is a promise the component does not keep. Pointer Events (plus `setPointerCapture`) cover mouse, touch and pen in one path and keep the drag alive when the cursor leaves the frame; `touch-action: none` is what stops a touch drag scrolling the page instead. Give both images real, different alt text - they are two pictures, not one with a decoration on top.