LoginSignup
1
2

iosあるある!「HTML&CSSでinputエリアにfocusした際、fixedが効かない問題」がReactコンポーネントでも発生したから解決する

Last updated at Posted at 2024-04-13

エラー概要

エラー概要参考記事はこちらをご覧ください
https://qiita.com/hibikikudo/items/2cb10536f4816d304f54
https://stackoverflow.com/questions/29001977/safari-in-ios8-is-scrolling-screen-when-fixed-elements-get-focus

簡単に画像で説明すると以下のような感じです

デフォルト

image_6487328.JPG
]

バグ発生時

image_6487327.JPG

Reactコンポーネントで解決した方法

※冒頭の参考記事を参考に

まずどうやって対処するかを言語化すると以下の3点

  1. inputエリアにフォーカスされた時にズレた高さ分下げる(useEffect, useRefを使用)
  2. ios端末だけの処理
  3. フォーカスが外れたら元に戻す

こうやって言語化してみるとなんか難しくないように感じるのですが、めちゃ手こずったのが事実笑

以下実装した処理(クラスなどは省いて関係ある部分のみ記載)

import { useEffect, useRef, useState } from 'react'
import { IoIosSend } from 'react-icons/io'
import { IconButton } from './iconButton'

type Props = {
  ....省略
}

export const MessageInput = (省略: Props) => {
  const inputRef = useRef<HTMLInputElement>(null)
  const [inputBottom, setInputBottom] = useState(0)

  useEffect(() => {
    const isIOS = /iPad|iPhone|iPod/.test(navigator.platform)
    if (!isIOS) {
      return // iOSデバイスではない場合は何もしない
    }

    const handleFocus = () => {
      const element = inputRef.current
      if (element) {
        const elementRect = element.getBoundingClientRect()
        const inputHeight = elementRect.height
        setInputBottom(inputHeight) // ここでinputの高さ分だけ下げる。
      }
    }

    const handleBlur = () => {
      setInputBottom(0) // フォーカスが外れたときは位置を元に戻す。
    }

    const currentInput = inputRef.current
    currentInput?.addEventListener('focus', handleFocus)
    currentInput?.addEventListener('blur', handleBlur)

    // クリーンアップ
    return () => {
      currentInput?.removeEventListener('focus', handleFocus)
      currentInput?.removeEventListener('blur', handleBlur)
    }
  }, [])

  return (
    <div className="absolute" style={{ bottom: ${inputBottom}px }} }}>
      <div className="">
        <div className="">
          <div className="">
            <input
              ref={inputRef}
              type="text"
              placeholder=""
              className="value={}"
            />
            <IconButton icon={<IoIosSend />} />
          </div>
        </div>
      </div>
    </div>
  )
}

Point

  1. absoluteを設定←これ忘れがち
  2. useRefでinput要素への参照を保持
  3. useEffectでメインの処理実装(クリーンアップを忘れずに)
  4. iosのみの処理にする

まとめ

参考記事のようにHTML&CSSで同じようなことが起こる記事はたくさん見かけたのですが、Reactで起こった記事があまりなかったので共有させてもらいました。

React学び始めた方や沼ってる方の参考になればなと思います!
あと、やり方は他にもあると思いますので、もっとこうしたほうがいい、こうした方が簡単だよ、みたいなことあれば教えてください

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