텍스트 필드(input OR textarea)에 포커싱하여 키보드가 활성화된 상태일 때, 키보드 외 스크린 영역(viewport)에 대해 안드로이드와 iOS가 서로 다르게 처리하고 있습니다.
이 때문에 특히, iOS에서 position: fixed로 설정하여 화면의 상단이나 하단에 고정시켜놓은 요소있을 때 문제가 발생하게 되는데요. 이 문제에 대응하기 위해 적용한 인터랙션 코드를 공유해봅니다.
상단의 헤더와 하단의 확인 버튼이 안보인다.
<aside> ➡️ 문제가 발생하는 원인에 대해선 아래 게시물에 아주 자세히 설명되어있으니 참고해보시면 좋겠습니다. https://nuhends.tistory.com/2
</aside>
<aside> ✴️ 인터랙션의 레퍼런스로 모바일 네이버의 검색화면을 참고하였습니다. https://m.naver.com
</aside>
이 인터랙션은 위 문제를 근본적으로 해결하지는 않습니다. 포커싱 상태에서 fixed 요소는 여전히 비정상적으로 위치하게 됩니다.
하지만 키보드가 활성화된 상태에서 스크롤을 방지함으로써 UI 오류처럼 보이는 경우를 해결하며 하단에 submit을 위한 확인 버튼 등이 고정되어있을 경우 한 번의 스크롤 만으로 버튼에 접근할 수 있게 됩니다.
Before, After로 비교하며 인터랙션 적용 시 어떻게 처리되는지 자세히 알아보겠습니다.
Before
After
화면에 touchmove가 발생할 경우 포커스를 해제하여 키보드를 내린다.
스크롤 한 번으로 fixed 요소에 접근할 수 있게 된다.
텍스트 편집을 위해 touchmove가 발생할 경우를 고려하여, 포커싱된 요소 내에서 touchmove 이벤트가 발생할 경우엔 인터랙션이 적용되지 않게 처리했다.
const isIOS = !!navigator.userAgent.match(/iPhone|iPad|iPod/i); // iOS 감지 코드를 사용하세요.
let targetInput = null;
export const blurWhenTouchMove = (e) => {
if (!isIOS) return; // iOS가 아니면 종료
targetInput = e.target; // iOS일 경우 메서드를 받은 이벤트 타켓을 targetInput에 등록
window.addEventListener('touchmove', blurWhenTouchMoveHandler); // touchmove 이벤트 감지를 위해 핸들러 등록
};
const blurWhenTouchMoveHandler = (e) => {
if (!targetInput) return; // targetInput가 없는 경우(비정상적인 실행) 종료
if (e.target === targetInput) return; // 포커스 중인 인풋 내에서 touchmove가 일어날 경우(텍스트 편집 등..) 키보드를 유지하기 위해 종료
targetInput.blur(); // 인풋 외 영역에서 touchmove가 일어날 경우 포커스를 해제
targetInput = null; // 초기화
window.removeEventListener('touchmove', blurWhenTouchMoveHandler); // 초기화
return;
};
// 사용 시에는 input 또는 textarea의 onFocus에 blurWhenTouchMove를 적용해주면 됩니다.
// ex1.
<input
type="text"
placeholder="연결할 웹 주소를 입력해 주세요."
onFocus={blurWhenTouchMove}
/>
// ex2.
<input
type="search"
onFocus={(e) => {
blurWhenTouchMove(e);
...
}}
/>