LoginSignup
1
2

More than 3 years have passed since last update.

タッチモニタもトラックパッドも有るデバイスにおける:hoverの件をDOM属性で解決する

Last updated at Posted at 2019-08-25

前置き

iPadProやMicrosoftSurfaceではタッチモニタでのクリックも、外部ポインタデバイスでのマウスオーバーも両方あるので、単一のコンポーネントに対して「どっちから使われてもいい感じに見えるように」とか言われたりします。
今回はjs側でクラス制御するのでなく、DOM属性を付与するアプローチで、オールドスクールなCSS書きの人と分業できるアプローチを紹介します

要点

  1. 適当な名前の data-* 属性を対象のコンポーネントのDOMに付与する(例えば data-touch)
  2. ontouchstartdata-touch を常にDOMに付ける
  3. onmouseleavedata-touch を常にDOMから剥がす
  4. :not([data-touch]):hover に対して、これまで通りの素朴なCSSを書く
  5. :not([data-touch]):active, [data-touch]:active にポインタクリック時やタップされてる時の状態をCSSで書く

以上

Demo

CodePen: Ignore (:hover) style at Touch device

両方のデバイスを受け付けてるSurfaceや、Chromeのモバイルシミュレーションモードでお試しください

ReactHooksを使った簡易なHOCの例

const TouchableContext = React.createContext({
  isTouch: false,
  handleTouchStart: e => {},
  handleMouseLeave: e => {}
});

const touchable = C => {
  return props => {
    const { onTouchStart, onMouseLeave, ...remain } = props;
    const [isTouch, setTouch] = React.useState(false);
    const handleTouchStart = e => {
      setTouch(true);
      if (onTouchStart) {
        onTouchStart(e);
      }
    };
    const handleMouseLeave = e => {
      setTouch(false);
      if (onMouseLeave) {
        onMouseLeave(e);
      }
    };
    const init = { isTouch, handleTouchStart, handleMouseLeave };
    return (
      <TouchableContext.Provider value={init}>
        <C
          onTouchStart={handleTouchStart}
          onMouseLeave={handleMouseLeave}
          data-touch={isTouch ? "" : null}
          {...remain}
        />
      </TouchableContext.Provider>
    );
  };
};

利用側はほぼ何もしなくてもタッチイベントで data-touch がDOMに付与されるので、コンポーネントの中身の実装に集中できますし、 useContext を使って const { isTouch } = useContext(Touchable); を参照することもできます。

const TextInput = touchable(props => <input type="text" {...props} />);
const Button = touchable(props => <button {...props} />);
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2