エラー概要
エラー概要参考記事はこちらをご覧ください
https://qiita.com/hibikikudo/items/2cb10536f4816d304f54
https://stackoverflow.com/questions/29001977/safari-in-ios8-is-scrolling-screen-when-fixed-elements-get-focus
簡単に画像で説明すると以下のような感じです
デフォルト
バグ発生時
Reactコンポーネントで解決した方法
※冒頭の参考記事を参考に
まずどうやって対処するかを言語化すると以下の3点
- inputエリアにフォーカスされた時にズレた高さ分下げる(useEffect, useRefを使用)
- ios端末だけの処理
- フォーカスが外れたら元に戻す
こうやって言語化してみるとなんか難しくないように感じるのですが、めちゃ手こずったのが事実笑
以下実装した処理(クラスなどは省いて関係ある部分のみ記載)
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
- absoluteを設定←これ忘れがち
- useRefでinput要素への参照を保持
- useEffectでメインの処理実装(クリーンアップを忘れずに)
- iosのみの処理にする
まとめ
参考記事のようにHTML&CSSで同じようなことが起こる記事はたくさん見かけたのですが、Reactで起こった記事があまりなかったので共有させてもらいました。
React学び始めた方や沼ってる方の参考になればなと思います!
あと、やり方は他にもあると思いますので、もっとこうしたほうがいい、こうした方が簡単だよ、みたいなことあれば教えてください