React 웹뷰로 기능을 만들다보니 디자인적으로 어려운참 많다.
특히나 IOS 와 안드로이드를 동시에 해결하려고 하다보니 보통은 안드로이드 기준에서는 잘되는데 IOS 에서는 안되는 경우가 너무나도 많았다. (그지 같은 사파리..)
이번에도 IOS 에서만 이상하게 동작하는 문제였는데
IOS 에서는 노치와 홈 네비게이터바 라는 개념이 있다. 노치는 화면 상단에 와이파이나 시간 개념처럼 나오는 상태창을 의미하고, 홈 네비게이터바는 하단에 바처럼 생긴 부분이고 핸드폰으로 보면 라운딩된 부분이다.
보통 화면 전체 크기를 잡을 때
height:'calc(var(--vh, 1vh) * 100)',
이런식으로 잡기 마련인데.. 문제는 사파리 웹뷰의 경우는 노치와 홈 네비게이터 바까지 영역이 침범해서 문제가 발생한다.
원래 AI 에게 문제를 물어보았으나 AI의 답변은
viewport-fit=auto (기본값)
브라우저가 자동으로 결정합니다
일반적으로 contain과 동일하게 동작
viewport-fit=contain
웹 콘텐츠가 안전 영역(safe area) 내에만 표시됩니다
노치나 홈 인디케이터가 있는 영역에는 콘텐츠가 표시되지 않습니다
화면 가장자리에 검은색 여백이 생길 수 있습니다
viewport-fit=cover
웹 콘텐츠가 화면 전체를 덮습니다
노치, 라운드 코너, 홈 인디케이터가 있는 영역까지 콘텐츠가 확장됩니다
이 설정을 사용할 때는 env(safe-area-inset-*) CSS 함수와 함께 사용해야 중요 콘텐츠가 가려지지 않습니다
이런 느낌이 답변을 주었다. view port 를 cover 로 변경하고,
env(safe-area-inset-top) /* 상단 안전 영역 (노치 등) */
env(safe-area-inset-right) /* 우측 안전 영역 */
env(safe-area-inset-bottom) /* 하단 안전 영역 (홈 인디케이터 등) */
env(safe-area-inset-left) /* 좌측 안전 영역 */
env 를 사용해서 해당 영역에 대한 높이를 조절하라.. 라는 것이였는데
테스트 해본 결과 내 아이폰에서는 이상하게 적용이 안되었다.
Top 으로 너무 올라가있거나 Bottom 으로 너무 내려가있거나.. 중간에 적당히 개념이 없는거 같은 느낌이였다.
AI에게 계속 문의 해보았으나, script 로 실시간으로 사이즈를 잡으라고 대답해줬는데
useEffect(() => {
// iOS 감지
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !(window as any).MSStream;
setIsNonIOS(!isIOS); // iOS가 아닌 경우 true 설정
appLog(`디바이스 감지: iOS=${isIOS}, 비iOS=${!isIOS}`);
// 즉시 실행 함수로 초기 높이 설정
const setInitialHeight = () => {
// 실제 가시 영역 높이로 --vh 변수 설정
const vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
// 강제 리사이즈 트리거
window.dispatchEvent(new Event('resize'));
// 로그 기록
appLog(`초기 높이 설정: ${window.innerHeight}px, vh: ${vh}px, 비iOS=${!isIOS}`);
};
// 초기 실행 및 연속 실행 (iOS의 지연 로딩을 위한 여러 번의 시도)
setInitialHeight();
// 연속적으로 여러 번 시도하여 정확한 크기를 얻음
const timers = [
setTimeout(setInitialHeight, 100),
setTimeout(setInitialHeight, 300),
setTimeout(setInitialHeight, 500)
];
// iOS에서만 추가 설정 실행
if (isIOS) {
// iOS에서 Safari UI를 강제로 표시하기 위한 트릭
const triggerScroll = () => {
window.scrollTo(0, 1);
setTimeout(() => {
window.scrollTo(0, 0);
// 스크롤 후 높이 재설정
const vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
}, 100);
};
// 로드 후 약간의 지연을 두고 실행
setTimeout(triggerScroll, 300);
}
// 컴포넌트 언마운트 시 타이머 정리
return () => {
timers.forEach(timer => clearTimeout(timer));
};
}, []);
이런 식으로 시작할때 설정해주라고 알려주고 있었다..
근데 이 부분도 뭔가 적용이 안되는 것이였다. 느낌상 시작하는 화면은 적절한 window.innterHeight 로 측정이 안되는거 같은 기분이 들었고. 일단 다시 초기 설정으로 돌아가기로 했다.
viewport-fit=cover
env(safe-area-inset-top) /* 상단 안전 영역 (노치 등) */
env(safe-area-inset-right) /* 우측 안전 영역 */
env(safe-area-inset-bottom) /* 하단 안전 영역 (홈 인디케이터 등) */
env(safe-area-inset-left) /* 좌측 안전 영역 */
이 기존 코딩은 다 빼버리고 원래대로 일단 돌아왔다.
그리고 설정은
viewport-fit=contain
이렇게 변경했다.
이렇게 변경하고 나서는 시작화면일때만 사이즈가 크게 나오고 움직이거나 터지 같은 액션을 가하면 내가 원하는 사이즈로 변경됐다. 아마 위에서 AI 가 알려준 Scrpit 가 동작은 하는거 같은데 초기 설정만 문제가 있었던거 같다.
그리고 여러가지 시도해보다가
const BackgroundContainer = styled('div')<ContainerProps>(({ isNonIOS }) => ({
width: '100%',
// iOS가 아닌 경우 100, iOS인 경우 99.5
height: `calc(var(--vh, 1vh) * ${isNonIOS ? 100 : 99.5})`,
overscrollBehavior: 'none',
}));
이런식으로 ios 일때만 height 를 99.5 로 수정해놨더니.. 신기하게 위의 script 가 시작부터 동작한다.
아마 기존의 사이즈가 100일때는 화면이 꽉잡아먹어서 해당 script 가 트리거를 하지 못한 모양이다.
아래는 해결 영상 첨부
뭔가 지잉 거리는거 같긴 한데 이정도면 기존에 비해서 아주 만족한다.
'REACT > TROUBLE SHOOTING' 카테고리의 다른 글
[React] TextArea 컴포넌트 외부 입력 (2) | 2025.02.06 |
---|---|
[React]TextArea Input 딜레이 처리 (0) | 2025.02.06 |
use state 변경 시 잔상이 남는 현상 (0) | 2025.02.05 |
Android Back Button 고찰 (0) | 2025.01.27 |
Android WebView Error: Unable to preventDefault inside passive event listener invocation. (0) | 2025.01.23 |