터치 및 마우스

다시 함께하는 첫 번째 시간

소개

거의 30년 동안 데스크톱 컴퓨팅 환경은 키보드와 마우스 또는 트랙패드를 주요 사용자 입력 기기로 중심으로 사용해 왔습니다. 하지만 지난 10년 동안 스마트폰과 태블릿은 새로운 상호작용 패러다임인 터치를 도입했습니다. 터치 지원 Windows 8 머신이 도입되고 이제 멋진 터치 지원 Chromebook Pixel이 출시되면서 터치가 기대되는 데스크톱 환경의 일부가 되고 있습니다. 가장 큰 과제 중 하나는 터치 기기와 마우스 기기뿐만 아니라 사용자가 두 입력 방법을 동시에 사용하는 기기에서도 작동하는 환경을 구축하는 것입니다.

이 도움말에서는 터치 기능이 브라우저에 빌드되는 방식, 이 새로운 인터페이스 메커니즘을 기존 앱에 통합하는 방법, 터치가 마우스 입력과 원활하게 작동하는 방식을 설명합니다.

웹 플랫폼의 터치 상태

iPhone은 웹브라우저에 전용 터치 API가 내장된 최초의 인기 플랫폼이었습니다. 다른 여러 브라우저 공급업체에서 iOS 구현과 호환되도록 빌드된 유사한 API 인터페이스를 만들었습니다. 이러한 인터페이스는 현재 '터치 이벤트 버전 1' 사양에 설명되어 있습니다. 터치 이벤트는 데스크톱의 Chrome 및 Firefox, iOS의 Safari, Android의 Chrome 및 Android 브라우저, Blackberry 브라우저와 같은 다른 모바일 브라우저에서 지원됩니다.

제 동료인 보리스 스무스님이 터치 이벤트에 관한 HTML5Rocks 튜토리얼을 작성했습니다. 이 튜토리얼은 이전에 터치 이벤트를 살펴본 적이 없는 경우 시작하는 데 좋은 방법입니다. 사실 이전에 터치 이벤트를 사용해 본 적이 없다면 계속하기 전에 이 도움말을 읽어 보세요. 기다리겠습니다.

모두 완료되었다면, 이제 터치 이벤트에 관한 기본적인 지식을 쌓았으므로 터치 지원 상호작용을 작성할 때의 문제는 터치 상호작용이 마우스 (및 마우스 에뮬레이션 트랙패드 및 트랙볼) 이벤트와 상당히 다를 수 있다는 점입니다. 터치 인터페이스는 일반적으로 마우스를 에뮬레이션하려고 하지만 이 에뮬레이션은 완벽하지 않습니다. 두 상호작용 스타일을 모두 처리해야 하며 각 인터페이스를 개별적으로 지원해야 할 수도 있습니다.

가장 중요한 점: 사용자에게 터치와 마우스가 있을 수 있음

많은 개발자가 환경에서 터치 이벤트를 지원하는지 정적으로 감지하는 사이트를 빌드한 다음 마우스 이벤트가 아닌 터치 이벤트만 지원하면 된다고 가정합니다. 이는 잘못된 가정입니다. 터치 이벤트가 있다고 해서 사용자가 주로 해당 터치 입력 장치를 사용하고 있는 것은 아닙니다. 이제 Chromebook Pixel 및 일부 Windows 8 노트북과 같은 기기에서 마우스와 터치 입력 방식을 모두 지원하며, 가까운 시일 내에 더 많은 기기에서 지원될 예정입니다. 이러한 기기에서는 사용자가 마우스와 터치 스크린을 모두 사용하여 애플리케이션과 상호작용하는 것이 매우 자연스럽기 때문에 '터치를 지원'하는 것은 '마우스 지원이 필요하지 않음'과는 다릅니다. 문제를 "두 가지 다른 상호작용 스타일을 작성하고 그 스타일 간에 전환해야 한다"고 생각하기보다는 두 상호작용이 독립적으로 작동하는 방식을 고려해야 합니다. Chromebook Pixel에서는 트랙패드를 자주 사용하지만 화면을 터치하기도 합니다. 동일한 애플리케이션이나 페이지에서 그때그때 가장 자연스러운 방식으로 작업합니다. 반면에 일부 터치 스크린 노트북 사용자는 터치 스크린을 거의 사용하지 않습니다. 따라서 터치 입력이 있더라도 마우스 제어를 사용 중지하거나 방해해서는 안 됩니다.

안타깝게도 사용자의 브라우저 환경에서 터치 입력을 지원하는지 여부를 알기는 어렵습니다. 이상적으로는 데스크톱 컴퓨터의 브라우저가 항상 터치 이벤트 지원을 나타내므로 언제든지 터치 스크린 디스플레이를 연결할 수 있습니다 (예: KVM을 통해 연결된 터치 스크린을 사용할 수 있는 경우). 이러한 이유로 애플리케이션은 터치와 마우스 간에 전환하려고 시도해서는 안 되며 둘 다 지원하면 됩니다.

마우스와 터치 동시 지원

#1 - 클릭 및 탭 - '자연스러운' 순서

첫 번째 문제는 터치 인터페이스가 일반적으로 마우스 클릭을 에뮬레이션하려고 한다는 점입니다. 터치 인터페이스는 이전에 마우스 이벤트와만 상호작용한 애플리케이션에서 작동해야 하기 때문입니다. 이를 바로가기로 사용할 수 있습니다. 사용자가 마우스로 클릭했든 화면에서 손가락으로 탭하든 "클릭" 이벤트가 계속 실행되기 때문입니다. 그러나 이 단축키에는 몇 가지 문제가 있습니다.

먼저 고급 터치 상호작용을 설계할 때는 주의해야 합니다. 사용자가 마우스를 사용하면 클릭 이벤트를 통해 응답하지만 사용자가 화면을 터치하면 터치 이벤트와 클릭 이벤트가 모두 발생합니다. 단일 클릭의 경우 이벤트 순서는 다음과 같습니다.

  1. touchstart
  2. touchmove
  3. touchend
  4. 마우스 오버
  5. mousemove
  6. mousedown
  7. mouseup
  8. 클릭

즉, touchstart와 같은 터치 이벤트를 처리하는 경우 해당하는 mousedown 또는 click 이벤트도 처리하지 않아야 합니다. 터치 이벤트를 취소할 수 있다면(이벤트 핸들러 내에서 preventDefault() 호출) 터치에 마우스 이벤트가 생성되지 않습니다. 터치 핸들러의 가장 중요한 규칙 중 하나는 다음과 같습니다.

그러나 이렇게 하면 스크롤과 같은 다른 기본 브라우저 동작도 방지됩니다. 일반적으로 터치 이벤트를 핸들러에서 완전히 처리하고 기본 작업을 사용 중지하려는 경우에도 마찬가지입니다. 일반적으로 모든 터치 이벤트를 처리하고 취소하거나 해당 이벤트의 핸들러를 사용하지 않는 것이 좋습니다.

둘째, 사용자가 휴대기기에서 웹페이지의 요소를 탭하면 모바일 상호작용용으로 설계되지 않은 페이지의 경우 터치 시작 이벤트와 마우스 이벤트 (mousedown) 처리 간에 300밀리초 이상의 지연이 발생합니다. Chrome을 사용하여 수행할 수 있습니다. Chrome 개발자 도구에서 '터치 이벤트 에뮬레이션'을 사용 설정하면 터치가 아닌 시스템에서 터치 인터페이스를 테스트하는 데 도움이 됩니다.

이 지연은 브라우저가 사용자가 다른 동작(특히 두 번 탭 확대/축소)을 실행하고 있는지 확인할 시간을 갖도록 하기 위한 것입니다. 물론 손가락 터치에 즉각적으로 반응해야 하는 경우에는 문제가 될 수 있습니다. 이러한 지연이 자동으로 발생하는 시나리오를 제한하기 위한 지속적인 작업이 진행되고 있습니다.

Android용 Chrome Android 브라우저 Android용 Opera Mobile) Android용 Firefox Safari iOS
확장 불가능한 표시 영역 지연 없음 300ms 300ms 지연 없음 300ms
뷰포트 없음 300ms 300ms 300ms 300ms 300ms

이 지연을 방지하는 첫 번째이자 가장 쉬운 방법은 모바일 브라우저에 페이지를 확대할 필요가 없다고 '알리는' 것입니다.이는 고정 표시 영역을 사용하여 할 수 있습니다(예: 페이지에 다음을 삽입).

<meta name="viewport" content="width=device-width,user-scalable=no">

물론 항상 적절한 것은 아닙니다. 접근성상의 이유로 필요할 수 있는 핀치 줌이 사용 중지되므로 가급적 사용하지 마세요. 사용자 크기 조정을 사용 중지하는 경우 애플리케이션에서 텍스트 가독성을 높이는 다른 방법을 제공하는 것이 좋습니다. 또한 터치를 지원하는 데스크톱 클래스 기기의 Chrome과 페이지에 확장할 수 없는 뷰포트가 있는 경우 모바일 플랫폼의 다른 브라우저에는 이 지연이 적용되지 않습니다.

#2: 터치로 마우스 이동 이벤트가 실행되지 않음

여기서 중요한 점은 터치 인터페이스에서 마우스 이벤트를 에뮬레이션하는 것이 일반적으로 mousemove 이벤트 에뮬레이션으로 확장되지 않는다는 것입니다. 따라서 mousemove 이벤트를 사용하는 멋진 마우스 기반 컨트롤을 빌드하는 경우 touchmove 핸들러도 구체적으로 추가하지 않는 한 터치 기기에서 작동하지 않을 수 있습니다.

브라우저는 일반적으로 HTML 컨트롤에서 터치 상호작용에 적절한 상호작용을 자동으로 구현합니다. 예를 들어 HTML5 범위 컨트롤은 터치 상호작용을 사용할 때만 작동합니다. 하지만 자체 컨트롤을 구현한 경우 클릭 및 드래그 유형 상호작용에서는 작동하지 않을 수 있습니다. 실제로 jQueryUI와 같이 일반적으로 사용되는 일부 라이브러리에서는 아직 이러한 방식으로 터치 상호작용을 지원하지 않습니다(jQueryUI의 경우 이 문제에 여러 가지 원키 패치 수정이 있음). 이것은 웹 오디오 플레이그라운드 애플리케이션을 터치를 지원하도록 업그레이드할 때 처음으로 겪은 문제 중 하나였습니다. 슬라이더는 jQueryUI 기반이기 때문에 클릭 및 드래그 상호작용에서 작동하지 않았습니다. HTML5 범위 컨트롤로 전환했는데 문제가 해결되었습니다. 물론 터치 이동 핸들러를 추가하여 슬라이더를 업데이트할 수도 있지만 한 가지 문제가 있습니다.

#3: Touchmove와 MouseMove는 다름

몇몇 개발자가 겪은 함정은 touchmove 핸들러와 마우스 이동 핸들러를 동일한 코드 경로로 호출하는 것입니다. 이러한 이벤트의 동작은 매우 유사하지만 미묘하게 다릅니다. 특히 터치 이벤트는 항상 터치가 시작된 요소를 타겟팅하는 반면 마우스 이벤트는 현재 마우스 커서 아래에 있는 요소를 타겟팅합니다. 이 때문에 mouseover 및 mouseout 이벤트가 있지만 상응하는 touchover 및 touchout 이벤트는 없으며 touchend만 있습니다.

이 문제가 발생하는 가장 일반적인 경우는 사용자가 터치하기 시작한 요소를 삭제하거나 재배치하는 경우입니다. 예를 들어 맞춤 스크롤 동작을 지원하기 위해 전체 캐러셀에 터치 핸들러가 있는 이미지 캐러셀을 생각해 보세요. 사용 가능한 이미지가 변경되면 일부 <img> 요소를 삭제하고 다른 요소를 추가합니다. 사용자가 이러한 이미지 중 하나를 터치하기 시작했는데 삭제하면 더 이상 트리에 없는 타겟에 전달되므로 터치 이벤트 핸들러(img 요소의 상위 요소에 있음)가 터치 이벤트 수신을 중지합니다. 따라서 사용자가 이동했다가 결국 삭제했더라도 한 지점에서 손가락을 계속 누르고 있는 것처럼 보입니다.

물론 터치가 활성화된 동안 터치 핸들러가 있거나 터치 핸들러가 있는 조상이 있는 요소를 삭제하지 않으면 이 문제를 방지할 수 있습니다. 또는 정적 touchend/touchmove 핸들러를 등록하는 대신 touchstart 이벤트가 수신될 때까지 기다린 다음 touchstart 이벤트의 타겟에 touchmove/touchend/touchcancel 핸들러를 추가하고 종료/취소 시 이를 삭제하는 것이 가장 좋습니다. 이렇게 하면 타겟 요소가 이동/삭제되더라도 터치에 대한 이벤트를 계속 수신할 수 있습니다. 여기에서 이 기능을 조금 사용해 볼 수 있습니다. 빨간색 상자를 터치하고 Esc 키를 누른 상태에서 빨간색 상자를 터치하면 DOM에서 삭제됩니다.

#4: 터치 및 마우스 오버

마우스 포인터 메타포는 커서 위치를 적극적인 선택과 구분하여 개발자가 마우스 오버 상태를 사용하여 사용자와 관련이 있을 수 있는 정보를 숨기거나 표시할 수 있도록 했습니다. 그러나 현재 대부분의 터치 인터페이스는 타겟 위로 손가락을 '마우스 오버'하는 것을 감지하지 않습니다. 따라서 이 정보에 액세스하는 터치 친화적인 방법을 제공하지 않는다면 마우스 오버를 기반으로 의미론적으로 중요한 정보 (예: '이 컨트롤이 무엇인가요?' 팝업)를 제공하는 것은 허용되지 않습니다. 마우스 오버를 사용하여 사용자에게 정보를 전달하는 방법에 주의해야 합니다.

하지만 흥미롭게도 CSS :hover 가상 클래스는 경우에 따라 터치 인터페이스에 의해 트리거될 수 있습니다. 요소를 탭하면 손가락이 아래에 있는 동안 :active가 되고 :hover 상태도 획득합니다. Internet Explorer의 경우 :마우스 오버 는 사용자가 손가락을 떼는 동안에만 작동합니다. 다른 브라우저에서는 다음번 탭하거나 마우스가 움직일 때까지 :마우스 오버가 계속 적용됩니다.) 이는 터치 인터페이스에서 팝아웃 메뉴가 작동하도록 하는 좋은 접근 방식입니다. 요소를 활성화하면 :hover 상태도 적용된다는 부작용이 있습니다. 예를 들면 다음과 같습니다.

<style>
img ~ .content {
  display:none;
}

img:hover ~ .content {
  display:block;
}
</style>

<img src="/awesome.png">
<div class="content">This is an awesome picture of me</div>

다른 요소를 탭하면 요소가 더 이상 활성 상태가 아니게 되며 마우스 포인터를 사용하여 요소 밖으로 이동한 것처럼 마우스 오버 상태가 사라집니다. 콘텐츠를 탭 스톱으로 만들기 위해 <a> 요소로 콘텐츠를 래핑하는 것이 좋습니다. 이렇게 하면 JavaScript가 필요 없이 사용자가 마우스 오버 또는 클릭, 터치 탭 또는 키 누르기로 추가 정보를 전환할 수 있습니다. Web Audio 플레이그라운드를 터치 인터페이스와 잘 작동하도록 만들기 시작하면서 팝아웃 메뉴가 이미 터치에서 잘 작동한다는 사실에 놀랐습니다. 이러한 구조를 사용했기 때문입니다.

위의 메서드는 마우스 포인터 기반 인터페이스와 터치 인터페이스에 모두 적합합니다. 이는 마우스 오버 시 'title' 속성을 사용하는 것과 대조됩니다. 이 속성은 요소가 활성화될 때 표시되지 않습니다.

<img src="/awesome.png" title="this doesn't show up in touch">

#5: 터치와 마우스의 정확성 비교

마우스는 현실과 개념적으로 분리되어 있지만, 기본 운영체제가 일반적으로 커서의 정확한 픽셀 정밀도를 추적하기 때문에 마우스가 매우 정확하다는 것이 밝혀졌습니다. 반면 모바일 개발자는 터치 스크린의 손가락 터치가 정확하지 않다는 사실을 알고 있습니다. 이는 주로 화면과 접촉할 때 손가락의 표면적 크기 때문입니다. 또한 손가락이 화면을 가리기 때문입니다.

많은 개인과 기업들이 손가락 기반 상호작용을 수용하는 애플리케이션과 사이트를 설계하는 방법에 관해 광범위한 사용자 연구를 진행했으며, 이 주제에 관한 수많은 책들이 저술되었습니다. 기본적인 조언은 패딩을 늘려 터치 영역의 크기를 늘리고, 요소 사이의 여백을 늘려 잘못된 탭 가능성을 줄이는 것입니다. (패딩은 터치 및 클릭 이벤트의 조회 감지 처리에 포함되지 않지만 여백은 포함됩니다.) 웹 오디오 플레이그라운드에서 수정해야 했던 주요 사항 중 하나는 연결 지점을 더 쉽게 정확하게 터치할 수 있도록 연결 지점의 크기를 늘리는 것이었습니다.

또한 터치 기반 인터페이스를 처리하는 많은 브라우저 공급업체는 사용자가 화면을 터치할 때 올바른 요소를 타겟팅하고 잘못된 클릭이 발생할 가능성을 줄이는 로직을 브라우저에 도입했습니다. 하지만 일반적으로는 이동이 아닌 클릭 이벤트만 수정합니다 (Internet Explorer에서도 마우스다운/마우스다운/마우스업 이벤트도 수정하는 것으로 보임).

#6: 터치 핸들러를 컨테이너에 포함하지 않으면 스크롤이 끊김

또한 터치 핸들러를 필요한 요소에만 한정하는 것도 중요합니다. 터치 요소는 대역폭이 매우 높을 수 있으므로 스크롤 요소에 터치 핸들러를 사용하지 않는 것이 중요합니다. 처리 과정에서 빠른 버벅거림이 없는 터치 스크롤을 위한 브라우저 최적화를 방해할 수 있기 때문입니다. 최신 브라우저는 GPU 스레드에서 스크롤하려고 시도하지만, 앱에서 각 터치 이벤트가 처리될지 먼저 JavaScript를 통해 확인해야 한다면 불가능합니다. 이 동작의 를 확인할 수 있습니다.

이 문제를 방지하기 위해 따라야 할 지침 중 하나는 UI의 작은 부분에서만 터치 이벤트를 처리하는 경우 터치 핸들러만 연결하는 것입니다 (페이지의 <body>와 같은 경우는 해당하지 않음). 즉, 터치 핸들러의 범위를 최대한 제한합니다.

#7: 멀티 터치

마지막으로 흥미로운 문제는 '터치' 사용자 인터페이스라고 했지만 거의 모든 경우 실제로는 멀티 터치를 지원한다는 점입니다. 즉, API는 한 번에 두 개 이상의 터치 입력을 제공합니다. 애플리케이션에서 터치를 지원하기 시작할 때는 여러 터치가 애플리케이션에 미치는 영향을 고려해야 합니다.

주로 마우스로 앱을 빌드해 왔다면 최대 1개의 커서 포인트로 빌드하는 데 익숙할 것입니다. 시스템은 일반적으로 여러 마우스 커서를 지원하지 않습니다. 많은 애플리케이션의 경우, 단순히 터치 이벤트를 단일 커서 인터페이스에 매핑하겠지만, 데스크톱 터치 입력에서 본 하드웨어는 대부분 최소 2개의 동시 입력을 처리할 수 있으며, 대부분의 새로운 하드웨어는 최소 5개의 동시 입력을 지원하는 것으로 보입니다. 물론 터치 피아노 키보드를 개발하는 경우 여러 개의 동시 터치 입력을 지원할 수 있어야 합니다.

현재 구현된 W3C Touch API에는 하드웨어가 지원하는 터치 포인트 수를 확인하는 API가 없으므로 사용자가 원하는 터치 포인트 수를 최대한 추정하거나 실제로 표시되는 터치 포인트 수를 확인하고 적응해야 합니다. 예를 들어 피아노 애플리케이션에서 터치 포인트가 2개를 초과하지 않는 경우 '코드' UI를 추가하는 것이 좋습니다. PointerEvents API에는 기기의 기능을 확인하는 API가 있습니다.

보정

이 도움말을 통해 마우스 상호작용과 함께 터치를 구현할 때 발생하는 일반적인 문제에 대한 안내를 얻으셨기를 바랍니다. 물론 다른 조언보다 더 중요한 것은 모바일, 태블릿, 마우스와 터치가 결합된 데스크톱 환경에서 앱을 테스트해야 한다는 것입니다. 터치+마우스 하드웨어가 없는 경우 Chrome의 '터치 이벤트 에뮬레이션'을 사용하여 다양한 시나리오를 테스트할 수 있습니다.

이러한 지침을 따르면서 터치 입력, 마우스 입력, 심지어 두 스타일의 상호작용이 동시에 원활하게 작동하는 매력적인 대화형 환경을 빌드할 수 있을 뿐만 아니라 비교적 쉽게 만들 수 있습니다.