글을 열심히 쓰고 저장을 눌렀는데 404가 뜨며 날아갔다 ㅠㅠ
모바일 웹을 개발하면서 겪었던 골치 아픈 2가지 크로스 브라우징 이슈와, 그밖에 고려해야 할 이슈에 대해
브라우저 자체 주소창과 네비게이션 바로 인한 뷰포트 높이 계산 문제
사파리와 삼성 인터넷은 브라우저 자체적으로 하단 네비게이션 바가 있다. 특별히 show/hide를 설정한 경우가 아니라면, 스크롤을 내리면 나타나고 올리면 사라진다.
문제는 이것들로 인해 뷰포트가 고정되지 않고 바뀐다는 것이다.
예를들어, 만약 높이를 100vh를 했을 경우, 네비게이션 바가 없을 때에는 정확히 레이아웃이 그려지지만, 네비게이션 바가 나타나면 네비게이션 바가 UI를 가리게 되는 문제가 발생한다.
dvh는 동적 뷰포트로, 뷰포트 높이가 변경될 때마다 변화를 자동으로 반영한다. 따라서 주소창이나 바텀 네비게이션 유무에 따른 UI 레이아웃 변경 대응이 가능하다.
svh는 주소창이나 네비게이션을 제외한 순수하게 UI 영역의 높이이다. 주소창이나 네비게이션이 나타날 것으로 예상되는 상황에서는 svh를 사용하는 것이 정확하다.
input을 선택했을 때 가상 키보드로 인해 UI가 밀리는 문제
모바일 사파리에서 input을 선택했더니 가상키보드로 인해 기존 UI 요소가 밀리는 문제가 발생했다. 타 브라우저에서는 일반적으로 가상키보드가 absolute하게 나타나는데, 사파리 모바일 웹에서는 마치 display block을 적용한 것 같이 자리를 차지 했다.
사파리는 가상 키보드가 올라올 때 뷰포트의 높이를 동적으로 조정해서, vh 단위를 사용하는 요소들이 재조정되면서 발생하는 문제이다. 이를 해결하려면,
html, body {
height: 100%;
min-height: 100vh; /* 고정된 최소 높이 설정 */
overflow: hidden;
}
html, body {
height: -webkit-fill-available; /* Safari 대응 */
}
사파리 등 특정 브라우저에서 적용되는 속성을 삽입한다.
3. 자바스크립트로 뷰포트를 동적으로 제어한다.
window.addEventListener('resize', () => {
if (window.innerHeight < 500) {
// 키보드가 올라왔을 때 실행할 코드
document.body.classList.add('keyboard-visible');
} else {
// 키보드가 내려갔을 때 실행할 코드
document.body.classList.remove('keyboard-visible');
}
});
resize 이벤트를 걸어서 뷰포트가 바뀔 때를 감지하고, 적절한 스타일을 적용한다.
3-1. focusin 이벤트 발생 시 위치를 제어한다.
document.querySelectorAll('input, textarea').forEach(element => {
element.addEventListener('focusin', () => {
setTimeout(() => {
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
}, 100);
});
});
3-2. 가상 키보드가 나타났을 때 위치를 제어한다. (아래 예시에서는 class 적용)
let originalHeight = window.innerHeight;
window.addEventListener('resize', () => {
if (window.innerHeight < originalHeight) {
// 가상 키보드가 올라온 상태
document.body.classList.add('keyboard-visible');
} else {
// 가상 키보드가 내려간 상태
document.body.classList.remove('keyboard-visible');
}
});
나의 경우에는 3-1번을 사용해서 해결했다. 만약 3-1번이 의도한대로 동작하지 않는다면, 먼저 아래 코드를 사용해서 의도한 바가 맞는지 확인한다.
window.addEventListener('focusin', () => {
setTimeout(()=> {
window.scrollTo(0,0)
}, 100);
})
기타
그외에도 사파리에서 모바일웹을 개발할 때 고려할 몇 가지 사항들을 찾아봤다.
1. 일부 속성들을 사용할 때에는 벤더 프리픽스를 사용한다.
* 벤더 프리픽스는 브라우저가 특정 css 속성을 이해하고 렌더링할 수 있도록 하는 접두사이며, 브라우저마다 다른 방식으로 구현된 css를 의도한대로 적용되게끔 한다. 이를 통해 같은 브라우저 간의 일관성 있고, 구버전 브라우저와도 호환성을 맞출 수 있다.
-webkit-: Chrome, Safari 등
-moz-: Mozilla Firefox
-ms-: Internet Explorer 및 Edge
-o-: Opera
벤더 프리픽스가 필요한 대표적인 속성들은 아래와 같다.
.container {
display: -webkit-flex; /* Safari */
display: flex;
-webkit-flex-direction: row;
flex-direction: row;
}
.item {
-webkit-flex-grow: 1; /* Safari */
flex-grow: 1;
-webkit-flex-shrink: 1; /* Safari */
flex-shrink: 1;
}
.grid-container {
display: -ms-grid; /* IE11 및 구버전 브라우저 */
display: grid; / 최신 브라우저 */
}
.sticky-element {
position: -webkit-sticky; /* Safari /
position: sticky;
}
input[type="text"],
select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
그 밖에, 사파리는 LocalStorage와 SessionStorage 용량을 약 5MB정도로 제한하고 있고, 각 탭간 Storage 공간을 공유하지 않기 때문에 주의할 필요가 있다.
ps. 원래 썼던 글이 날아가서 너무 슬프다. 내가 올린 글이 양질의 글은 아니지만,,,ㅠ 임시 저장을 꼭 해야겠다.