일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- activeElement
- 자바스
- EC2 HTTPS로 연결
- net::R_SSL_PROTOCOL_ERROR
- 모두의시간
- 퍼듀대학교
- K-SW SQUARE
- 자바스크립트 렉시컬스코프
- 모던 자바스크립트 Deep Dive
- ios 크로스브라우징
- refetchOnWindowFocus
- 로현 청춘의개발
- 자바스크립트 null 병합
- 자바스크립트
- 자바스크립트 논리합 연산자
- Purdue university
- 자바스크립트 옵셔널 체이닝
- touchmove 이벤트
- active blur
- 자바스크립트 호이스팅
- 리액트 쿼리
- 자바스크립트 스코프 체인
- 사파리 가상키보드
- AWS 로드밸런서
- 자바스크립트 변수 호이스팅
- Kafka
- 자바스크립트 중첩함수
- React Query
- but requested an insecure XMLHttpRequest endpoint 'http://~~’. This request has been blocked; the content must be served over HTTPS.
- 리액트 가상키보드
- Today
- Total
개발 여행자, 현
iOS 15 대응 - 사파리 가상키보드 이슈 (feat. 크로스 브라우징) 본문
모두의 시간 서비스 QA 과정을 거치면서 발견한 크로스 브라우징 문제를 해결했던 경험을 작성한다.
iOS15 버전이 릴리즈 된 이후에 사파리 브라우저에서만 발생하는 '크로스브라우징' 이슈인 만큼 자세히 기록하고자 한다.
1. 이슈 발생
모두의시간 서비스에서 방을 생성하는 과정에서 input창에 정보를 입력해야 되는 부분이 있다.
input 창을 클릭하면 하단에서 키보드가 올라오는데, 키보드 창이 올라온 상황에서 스크롤을 아래로 내리면 검은 빈공간이 표시된다.
서비스 사용에는 문제가 없지만, 사용자의 경험을 헤칠 수 있는 문제가 있기에 이를 해결하고자 했다.
파악한 이슈는 다음과 같다.
- 키보드를 열기전 : 화면의 높이
- 키보드를 열었을 때 : 화면의 높이 + 키보드의 높이
키보드가 나오기 전에는 document가 존재할 수 있는 영역은 화면의 높이 만큼이다.
하지만 사용자가 정보를 입력하기 위해 Input 창을 클릭하면, 키보드가 올라오고 document를 키보드 높이만큼 그대로 밀어 올린다. 동시에 키보드 뒤쪽에는 가상의 영역이 생성된다.
일반적으로 페이지에 손가락을 대고 움직이면 화면이 스크롤 된다. 이는 정확히는 html태그가 스크롤 된다고 생각하면 된다.
iOS 운영체제는 사파리 운영체제에서 키보드 창을 열었을 때 키보드 뒤쪽에 가상의 영역을 생성한다. 그래서 키보드가 열린 상태에서 스크롤을 하게되면 html태그가 먼저 스크롤 되는 것이 아니라, 먼저 document가 키보드 뒤쪽의 가상영역으로 스크롤 되는 것이다. 스크롤이 되다가 document가 키보드 뒤쪽의 가상영역의 하단에 닿게 되면 그때부터 내부의 html태그가 스크롤 된다.
2. 어떻게 해결했나?
그래서 내가 생각했던 방법은 2가지가 있었다.
- 페이지의 높이가 screen의 높이(height: 100%)로 고정이 되어있고 내부에서 스크롤 되도록 하는 방식
- 키보드가 활성화 된 상태에서 스크롤 이벤트가 발생하면 blur 처리로 키보드를 비활성화 시키는 방식
1번과 2번 중에 고민을 했는데, 1번의 장점은 키보드가 올라온 상태에서도 스크롤이 가능하다는 것이었다.
하지만 현재 입력하고 있는 Input 창에서 다른 곳으로 스크롤을 하는 것이 불필요하다고 생각했다. 정보를 입력할 때 하단이나 상단의 정보를 참고하면서 작성해야 되는 경우이면 1번으로 진행했겠지만, 오히려 다른 곳을 클릭했을 때, 혹은 스크롤을 할 때 키보드 또한 비활성화 하는 게 사용경험이 높을 것이라고 생각했다.
그래서 스크롤을 할 때 키보드를 비활성화 할 수 있다는 장점이 있는 2번을 선택했다.
2번의 단점은 키보드가 활성화 된 상태에서 스크롤이 불가능하다는 것인데, 현재 모두의시간 서비스에서는 불필요하기에 2번으로 진행했다.
처음 간단하게 생각했던 개발방향의 큰 그림은 다음과 같다.
1) Input창이 활성화(focus) 된 것을 인지
2) 활성화 된 상태에서 스크롤(scroll) 이벤트 발생 인지
3) Input창 비활성화
처음 작성한 코드는 아래와 같다.
const useInputScroll = (ref: React.RefObject<HTMLInputElement>) => {
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
const handleScroll = (e: { target: any }) => {
if (
document.activeElement == ref.current ||
ref.current?.contains(e.target)
) {
(document.activeElement as HTMLElement).blur();
}
};
};
activeElement를 사용해 input 태그가 focus 되어있는 것을 판별해 blur 처리 하였다.
금방 해결할 수 있겠다고 생각한 것도 잠시...
처음 기획한 방향으로 구현을 해보니, 키보드가 올라올 때 발생하는 스크롤 이벤트도 인식을 해버렸다
1) Input창이 활성화(focus) 된 것을 인지
2) 활성화 된 상태에서 스크롤(scroll) 이벤트 발생 인지
3) Input창 비활성
사용자가 Input 창을 클릭하는 순간 1번과 2번이 동시에 실행되어, 곧바로 Input 창이 비활성화 되는 문제가 발생했다.
그래서 scroll 이벤트가 아닌 'click' 이벤트로 변경해보았지만, click 이벤트는 터치를 할 때 발생하는 이벤트였다.
데스크탑으로 따지면 마우스를 '클'릭하는 순간이 아니라 '클릭' 하는 순간, 즉 손을 떼는 순간에 발생하는 이벤트여서
Input 창을 클릭하는 순간 위와 같은 문제인 1번과 2번이 동시에 인식되어 키보드가 곧바로 사라졌다.
그래서 모바일 기기에서의 터치 이벤트에 대해 자세히 학습했다.
다음으로 든 생각은 그럼 input 창이 활성화된 상태에서 click 이벤트가 발생되면 키보드를 비활성화 시켜야겠다고 생각했는데
모바일 환경에서 스크롤을 할 때는 터치를 한 상태에서 손가락을 움직이기에 한템포 늦게 실행되었다.
모바일 환경에서는 touchstart -> touchmove -> touchend 발생한다는 것을 알게되었고
touchmove(터치한 상태로 움직이는 행위)를 인식하는 방향으로 수정했다.
3. 최종 수정사항
import React, { useEffect } from 'react';
const useInputScroll = (ref: React.RefObject<HTMLInputElement>) => {
useEffect(() => {
window.addEventListener('touchmove', handleScroll);
return () => {
window.removeEventListener('touchmove', handleScroll);
};
}, []);
const handleScroll = (e: { target: any }) => {
if (
document.activeElement == ref.current ||
ref.current?.contains(e.target)
) {
(document.activeElement as HTMLElement).blur();
}
};
};
export default useInputScroll;
리액트에서 ref를 설정할 수 있는 useRef를 이용하여, Input 태그에 적용하고 훅으로 넘기는 코드를 작성했다.
touchmove 이벤트가 감지되면 handleScroll 함수가 실행되고,
document.activeElement를 통해 현재 전달받은 ref가 focus 되어있는지 판별했다.
focus 되어있는 상황에서 touchmove 이벤트가 감지되면
document.activeElement.blur() 이벤트를 호출하여 focus를 unfocus 되도록 하는 코드이다.
영상을 보면 해결하고자 했던 방향대로 잘 수정되었다.
방생성 페이지와 마찬가지로 로그인 페이지에서도 같은 오류가 있어서 Hook으로 작성했다.
이슈를 해결하면서 크로스 브라우징 문제는 언제 어디서나 존재할 수 있으니, 꼼꼼한 QA가 필수라는 것을 깨달았고 focus, blur, input, 마우스 핸들링 이벤트 등에 대해 학습할 수 있었다.
크로스 브라우징 이슈를 1순위로 생각하며, 어떠한 브라우저와 핸드폰으로 접속하여도 같은 경험을 제공하는 것이 우선이라는 생각이 들었다. 또한 지속적으로 모니터링 하면서, 조금이라도 사용경험을 개선할 수 있는 것은 계속해서 수정할 예정이다.
'대외활동 > DND 8기' 카테고리의 다른 글
React-Query : refetchOnWindowFocus 이슈 해결과정 (feat. API 재호출) (0) | 2023.08.14 |
---|---|
[모두의시간] React-Query 도입기 (0) | 2023.08.14 |
[JS] Date 객체 크로스 브라우징 이슈 해결과정 (feat. iOS 15.4.1) (0) | 2023.07.25 |
[DND 8기] IT연합동아리 DND 활동후기 (Front-end) (0) | 2023.07.21 |