FE/react

[React] 모바일 웹 100vh 스크롤 버그 + tailwind 적용법

s0ojin 2023. 5. 8. 13:40

 

문제 상황


페이지에 height : 100vh 속성을 주었는데, 모바일에서 테스트해보니 스크롤이 생깁니다.
1vh는 스크린 높이의 1%이므로 100vh면 스크롤없이 스크린을 가득 채워야하는데, 모바일에서만 이런 문제가 생긴겁니다!!

 

문제 원인


찾아보니, 모바일에서는 상하단의 주소창과 네비바의 높이를 스크린 높이에 포함하기 때문에 여백이 생겨버린 것이었습니다.

브라우저별 상하단바의 높이를 고려해서 높이를 정하기는 너무너무너무너무 귀찮기때문에, 상하단바를 제외한 실제 내부 높이를 가져올 방법을 고려해야합니다.

 

 

해결 방법 1 : vh 재정의하기 (React에 적용하기)


JavaScript의 window.innerHeigh는 현재 뷰포인트의 높이를 가져올 수 있습니다. 이 속성을 이용해서, innerHeight * 0.01을 1vh로 사용자 정의 스타일을 이용하여 문제를 해결할 수 있습니다.

 

1. innerHeight으로 vh 재정의하기

유저가 접속하는 동시에 뷰포인트를 계산해주어야하기 때문에, 최상위 컴포넌트에서 innerHeight을 계산해서 vh를 재정의해야합니다. 따라서 App.tsx에서 아래 코드를 작성하면됩니다. 함수를 분리하고 싶다면 따로 파일을 만들고 App.tsx에서 import해서 사용해도됩니다.

export default function setScreenHeight() {
  const vh = window.innerHeight * 0.01;
  document.documentElement.style.setProperty('--vh', `${vh}px`);
}

 

import setScreenHeight from 'src/utils/mobileScreenSize/setScreenHeight';

function App() {
  //처음 렌더링할 때 기준 높이로 vh를 계산하게되기 때문에 중간에 화면사이즈가 바뀌면 실시간으로 적용되지 않음
  useEffect(() => {
    setMobileHeight();
    
    // resize 이벤트가 발생하면 다시 계산하도록 아래 코드 추가
    window.addEventListener('resize', setMobileHeight);
    return () => window.removeEventListener('resize', setMobileHeight);
  }, []);

  return (
    <>
      <BrowserRouter>
        <Header />
        <Modals />
        <RoutePage />
        <Navbar />
      </BrowserRouter>
      <ReactQueryDevtools />
    </>
  );
}

export default App;

 

2. 사용하기

모바일에서 100vh로 보여야하는 부분에 다음처럼 사용합니다. 참고로 var()는 사용자 지정 속성입니다. var(사용자지정 변수명 [, 대체값])인데, 자바스크립트로 --vh를 지정하고 있기때문에, 값이 지정되기 이전이라면 1vh를 사용하라고 var(--vh, 1vh)를 사용한겁니다.

height: calc(var(--vh, 1vh) * 100);

 

3. (추가)TailwindCSS에 적용하는 법

1번은 그대로 수행 후 height를 적용할 때 tailwind config에 새롭게 스타일을 지정하면 편합니다. 아래처럼 설정하면  h-real-screen, min-h-real-screen과 같이 사용할 수 있습니다. 

// tailwindcss.config.js

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
  theme: {
    extend: {
      height: {
        'real-screen': 'calc(var(--vh) * 100)',
      },
    },
    minHeight: {
      'real-screen': 'calc(var(--vh) * 100)',
    },
  },
  plugins: [],
};

 

해결 방법 2 : 새롭게 추가된 css 뷰포인트 단위


이 문제로 계속 서칭을 하다가 알게되었는데, css in 2022에 이 문제를 해결하기 위해 새로운 뷰포인트단위가 추가되었습니다. 하....오래 찾아보면서 대체 이런 w버그를 아직도 이렇게 고쳐야하는건가 하는 생각이 들었는데 역~시나 너무 좋은 속성이 이미 추가되어있네요...ㅎㅎㅎ 실제로 100vh대신 100dvh를 사용하니 모바일 크롭 앱과 사파리에서 매우 잘 작동하는 것을 확인했습니다. 그러나 최근 추가된 기능들은 늘 그렇듯 일부 브라우저 버전에서는 작동하지 않을 수 있습니다. 그래서 저도 이번에는 해당 단위들을 사용하는대신 기존의 방식을 따라 코드를 작성하였습니다. 다음 프로젝트 때는 해당 단위들을 사용할 수 있을 정도로 안정화가 되었으면 좋겠네요!

 

 

적용된 모습


개인적으로는 tailwindCSS 때문에 애를 좀 먹었는데...(tailwind는 postcss로 이 문제를 해결할 것을 권고하기 때문이다. postcss로 해보려다 시간 왕창쓰고 해결못하고 다시 돌아옴) 결론적으로는 내가 tailwindCSS에 익숙하지 않은 탓이었다. 그냥 단순하게 생각하고 적용하면 됐는데 왤케 돌아왔는지.....아무튼 너모 깔끔하고 뿌듯

 

References


https://css-tricks.com/the-trick-to-viewport-units-on-mobile/

https://web.dev/state-of-css-2022/