모바일 환경에서 뷰포트 높이, hover CSS로 최적화

JoonPark·2023년 12월 31일
0
post-thumbnail

서론

나는 바보다.
오늘 작성하는 이 벨로그 글을 똑같이 두번 썼고, 같은 방식으로 두번 다 날려먹었다.
블로그 글을 작성할 때마다 뭔가 각잡고 써야한다는 느낌을 지울 수 없었는데, 이왕 이렇게 된거 처음 블로그를 만들자고 마음먹었을 때처럼 그냥 간단히 느낀것만 쓰는게 좋겠다고 결론 내렸다.
한번 당하면 억울한 일이지만 두번 당하면 내가 바보라는 결론밖에 나지 않는다.
이제 진짜 간단하게만 작성해야지.

구글 DevTools에서는 "기기 툴바 전환"으로 pc에서도 모바일 환경과 유사하게 테스트를 해볼 수 있다.
하지만 pc테스트에서는 잘 동작하는데 실제 모바일에서는 의도대로 적용되지 않는 몇가지가 있는데, 그 중 뷰포트 높이 100vh 문제와 hover 유지 현상 대해 써보려 한다.

본론

기능 요구 사항

  • 컴포넌트에 100vh CSS 속성을 부여했을 때, 실제 모바일 환경에서 컴포넌트가 하단바에 묻히는 현상 해결
  • 컴포넌트에 :hover CSS 의사 클래스를 부여했을 때, 실제 모바일 환경에서 터치 이후 계속 :hover가 적용되는 현상 해결

1. 실제 모바일 환경에서 100vh가 하단바에 묻히는 현상 해결

  • 아래와 같은 상황을 말한다.

Next.js 프레임워크에서 window.innerHeight를 계산하는 것의 한계점

사실 구동 기기의 화면을 계산하여 높이 값을 주는 방법은 매우 효율적인 방법이다.
HTML, React 환경에서는 DOM을 구성해두고 js를 다운받아 적용한 이후에 최종적으로 렌더링하기에 문제가 전혀 없다.
하지만 나는 Next.js 프레임워크로 프로젝트를 구성했기 때문에 두가지 문제가 있다.

  1. Next.js에서 js로 레이아웃DOM을 조작하는 방식은 권장되지 않는다.
    Next.js에서는 DOM과 CSSOM을 미리 서버에서 렌더링하고 캐시를 해두며 이를 빠르게 유저에게 보여주는 Viewable 시점,
    이후 js가 모두 로드된 이후 상호작용이 가능해지며 웹 사이트로서 기능하는 Interactable 시점으로 로딩단계가 나누어진다.
    따라서 이미 보여진 레이아웃이 갑자기 1~2초 후에 움찔거리며 변경될 경우 사용자 입장에서 어색하게 느껴질 수 있으므로 좋은 UX 설계라고는 생각하지 않는다.

  2. Next.js에서 최상단 서비스 진입 페이지를 클라이언트 컴포넌트로 선언하는 것은 권장되지 않는다.
    뷰포트와 같은 전체 레이아웃을 변경하려면 필연적으로 최상단 layout.tsx 파일에 React hooks를 사용해야 하는데, 이는 보통 Meta Data와 같은 프로젝트 설정 코드와 충돌을 일으키게 된다. 물론 이것도 컴포넌트를 쪼개어 해결하는 방법도 있지만, 100vh와 같이 프로젝트 전체를 감싸는 프로바이더를 클라이언트 컴포넌트로 쓸거면... 왜 Next.js를 쓰시는지? 🤔

새로운 CSS 높이 속성 dvh, lvh, svh로 vh를 대체

결국 이 얘기를 블로그에 정리하고 싶어서 길고 긴 글을 작성했다. (간단하게 쓴다 했는데 또 쉽지가 않네)
새로운 CSS 속성으로 Next.js에서도 서버컴포넌트를 사용해 해결이 가능하게 되었고, 관련 내용을 아래 정리했다.
물론 새로운 CSS 속성들이 으레 그러하듯이, 도입을 미루거나 실험실 기능만으로 제공하는 브라우저들이 있다.

  1. DVH (Dynamic Viewport Height): dvh는 브라우저 UI 요소의 상태 변화에 따라 동적으로 뷰포트 높이를 조정합니다. 예를 들어, 스크롤을 내릴 때 주소 표시줄이 사라지거나 나타나면서 뷰포트 높이가 변하는 경우, dvh는 이러한 변화를 반영하여 뷰포트 높이를 조절합니다.

  2. SVH (Small Viewport Height): 이 단위는 브라우저 UI 요소가 최소화되었을 때의 뷰포트 높이를 기준으로 합니다. 예를 들어, 모바일 기기에서 주소 표시줄이 숨겨진 상태에서의 뷰포트 높이를 나타냅니다. 이 단위는 화면의 보이는 부분만을 고려하여 높이를 계산합니다.

  3. LVH (Large Viewport Height): lvh는 브라우저 UI 요소가 최대화되었을 때의 뷰포트 높이를 기준으로 합니다. 이는 주소 표시줄이나 기타 UI 요소들이 모두 보이는 상태에서의 뷰포트 높이를 나타냅니다. 주로 스크롤이 없는 페이지나 전체 화면 모드가 아닌 경우에 유용합니다.

2. :hover가 모바일 환경에서 터치 후 hover 지속되는 현상 해결

스와이퍼를 사용하다가 발견한 문제인데, 종종 발생할 수 있는 내용인 것을 처음 알게되었다.
보통 다른 버튼을 다시 터치하면 문제가 발생하지 않지만 swiper 특성상 터치도 가능하고 스와이프나 휠로도 버튼 클래스가 달라지니까 발생하는 오류인 것 같다.

미디어 쿼리 조건을 이용한 해결

다음과 같이 hover가 가능한 기기에만 적용되는 조건도 있었으나, 모바일도 호버가 되는 기기로 인식하는지 오류가 해결되지는 않았다.
대신, 마우스와 같은 정밀한 포인터(pointer: fine)와 손가락과 같은 덜 정밀한 포인터(pointer: coarse) 조건이 있어 이걸로 해결했다.

// 적용 안됨
@media (hover: hover) {
  /* 호버 가능한 기기에서 적용될 스타일 */
  .nav-button:hover {
    background-position: left center;
  }
}

// 적용됨!!
@media (pointer: fine) {
  /* 호버 가능한 기기에서 적용될 스타일 */
  .nav-button:hover {
    background-position: left center;
  }
}

결론

첫 글과 두번째 작성한 글은 기승전결에 따라 누가 봐도 이해하기 쉽도록 작성했으나, 이렇게 간단히 적는 것도 내가 다시 봤을 때 이해할 수 있는 수준은 된다고 생각한다.
그리고 이 글을 벌써 세번째 작성하면서 더 공부가 되었으니 오히려 좋아!
프론트엔드 개발자가 CSS를 잘 활용할 수 있다면 컴포넌트 설계 또한 효율적으로 할 수 있다는 점 또한 다시 느꼈다.

profile
FE Developer

0개의 댓글