tech.junha.kr

모바일에서 CSS hover 효과가 사라지지 않는 문제 해결

모바일 터치 후 호버 효과가 사라지지 않을 때

프론트엔드 개발하다 보면 한 번쯤은 겪는 문제다. 데스크톱에서는 멀쩡하게 작동하던 버튼이 모바일에서는 터치 후에도 호버 상태가 계속 유지되는 현상 말이다.

처음에는 "뭐지? 왜 버튼을 눌러도 색깔이 안 돌아와?" 하면서 당황했는데, 알고 보니 모바일과 데스크톱의 상호작용 방식이 근본적으로 다르기 때문이었다.

문제의 핵심

모바일에서는 "마우스를 올린다"는 개념 자체가 없다. 터치스크린에서는 터치하는 순간 hover 상태가 활성화되고, 다른 곳을 터치하기 전까지 그 상태가 유지된다. 그래서 버튼을 터치한 후 다른 영역을 터치하지 않으면 호버 효과가 계속 남아있게 된다.

최신 CSS 미디어 쿼리로 해결하기

예전에는 @media (max-width: 768px) 같은 방식으로 디바이스를 구분했지만, 요즘은 더 정확한 방법이 있다. hover와 pointer 미디어 쿼리를 조합하면 디바이스의 입력 방식을 정확히 구분할 수 있다.

/* 터치스크린 디바이스 - 스마트폰, 태블릿 */
@media (hover: none) and (pointer: coarse) {
  .btn-fade:active {
    background: #ff7d4d;
    transition: 200ms ease-in;
  }
}

/* 정밀한 포인팅 디바이스 - 마우스, 트랙패드 */
@media (hover: hover) and (pointer: fine) {
  .btn-fade:hover {
    background: #ff7d4d;
    transition: 300ms ease-in;
  }
}

터치스크린에서는 :hover 대신 :active를 사용하고, 터치 특성상 빠른 반응이 중요하니 애니메이션 시간도 조금 더 짧게 설정했다.

JavaScript로 터치 이벤트 처리하기

CSS만으로 해결되지 않는 복잡한 케이스라면 JavaScript의 터치 이벤트를 활용할 수 있다. 특히 터치 후 강제로 호버 상태를 제거해야 할 때 유용하다.

function setupTouchHandlers() {
  const buttons = document.querySelectorAll('.btn-fade');
  
  buttons.forEach(button => {
    button.addEventListener('touchend', function() {
      // 터치 종료 시 hover 클래스 제거
      this.classList.remove('hover-active');

      // 혹은 blur로 focus 해제
      this.blur();
    });
  });
}

2024년 트렌드: Container Queries 활용 (UPDATE)

최신 브라우저들이 Container Queries를 지원하기 시작하면서, 컴포넌트 단위로 더 세밀한 반응형 처리가 가능해졌다. 특히 디자인 시스템을 구축할 때 이런 방식이 점점 중요해지고 있다.

@container (hover: hover) {
  .button {
    &:hover {
      transform: scale(1.05);
    }
  }
}

실무에서 느낀 점

처음에는 "그냥 모바일에서는 호버 효과 빼면 되지 않나?" 생각했는데, 사용자 경험 관점에서는 각 플랫폼에 맞는 적절한 피드백을 제공하는 게 중요하다는 걸 깨달았다.

터치 디바이스에서는 :active 상태로 즉각적인 반응을, 마우스 환경에서는 :hover로 미리 보기를 제공하는 식으로 말이다. 결국 사용자가 어떤 디바이스를 쓰든 자연스러운 상호작용을 느낄 수 있도록 하는 게 목표다.

프론트엔드 개발이 단순해 보일 수 있지만, 이런 세부적인 차이들을 하나씩 해결해 나가다 보면 생각보다 깊이 있는 분야라는 걸 느끼게 된다. 특히 다양한 디바이스와 브라우저 환경을 모두 고려해야 하는 요즘에는 더욱 그렇다.