Safe area(CSS)-cover

Safe area(CSS)

IOS 모바일 환경에서 생기는 Safe Area 대처

Written by Given at2024.04.24

모바일 화면에서 화면 하단에 고정된 메뉴바를 필요로 하는 웹사이트를 만들던 중 아이폰 크롬 환경에서 하단 nav bar가 붕 떠있는 것 같은 문제가 있었다. postion:fixed;에 bottom:0;으로 고정했는데도 생기는 문제였다.

bottom:0; 인데 왜 밑에 있지를 못하니....왜 떠있어....

그 못생긴 공간을 너무 채우고 싶었고, ios bottom nav position, iphone bottom nav,,,, 등 구글링 해보았지만 원하는 답을 얻을 순 없었다.

그래서 같은 환경에 bottom menu를 가장 이상적인 방식으로 nav bar를 만든 사이트를 찾아 분석하자고 마음 먹었다.

bottom menu가 있는 사이트를 찾던 중 쿠팡 모바일 화면은 나와 같은 문제가 있었고 pala 라는 거래소 사이트는 화면 밑에 붙어있었지만 iphoneX부터 홈버튼이 사라지고 생긴 컨트롤영역에 메뉴가 중첩되어 있었다.

naverTV와 Youtube 모바일에 bottom menu가 스크롤 여부 상관없이 최하단에 위치하며 컨트롤영역과도 중첩되지 않게 공간을 만드는 것을 확인할 수 있었다.

어떻게 하는거야...!? 너무 하고 싶다.

가설을 세워볼 때 두 사이트 모두 os를 확인하고, 브라우저 환경을 확인하고, 스크롤 여부를 확인하는 이상한 로직으로 bottom menu를 만들지는 않았을 것이고 이는 스타일(CSS)의 영역이라고 판단하여 개발자도구를 열어 CSS를 뒤져보았다. 그리고 발견하였다.

.page .wrap { padding-bottom: calc( env(safe-area-inset-bottom) + var(--app-nudge-height) + var(--sub-header-height) ); }

뒤 변수들은 각 높이 값들을 넣은 것인데 앞에 env(safe-area-inset-bottom)은 알 수 없었다.

safe-area가 뭐지?

safe area란

TV에 처음 적용된 것으로 여러 해상도 비율을 가진 컨텐츠들을 모든 디바이스에서 노출할 수 있도록 만들어진 영역이다. 아이폰X 이후 홈버튼이 사라지고 노치로 변경되면서 화면 비율에 변경에 따라 컨텐츠들이 제대로 노출되지 않는 문제들을 해결하기 위해 위 개념이 도입된 모양이다.

// iOS 11.0 버전 constant(safe-area-inset-top) constant(safe-area-inset-right) constant(safe-area-inset-bottom) constant(safe-area-inset-left) // iOS 11.2 이상 env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)

env()는 모든 환경에서 지원하지는 않는다... https://caniuse.com/?search=env 이제 문제를 해결할 수 있다는 기대와 함께 적용을 해봤는데 아직 내 bottom menu는 떠있다..... 원인은 생각보다. 간단했다. meta tag를 바꿔주면 되었다. viewport-fit를 cover로 변경해주면 화면에 맞게 position을 잡아주었다. bottom이 bottom했다.

<meta name="viewport" content="initial-scale=1, viewport-fit=cover" />

react는 위 태그를 넣어주기만 하면 되고, next의 경우 14버젼은

import type { Viewport } from "next"; export const viewport: Viewport = { width: "device-width", initialScale: 1, maximumScale: 1, userScalable: false, // Also supported by less commonly used // interactiveWidget: 'resizes-visual', };

viewport를 따로 export 해주면 되고, 참고: https://nextjs.org/docs/app/api-reference/functions/generate-viewport

13버전은

export const metadata: Metadata = { title: "Create Next App", description: "Generated by create next app", viewport: "width=device-width, initial-scale=1, maximum-scale=1", // <-- now here };

이렇게 metadata에 추가해주면 되었다. https://dev.to/oler/resolving-viewport-duplication-in-nextjs-134-51lm

13,14 다름 https://nextjs.org/docs/app/api-reference/functions/generate-viewport#version-history