터치 및 마우스

처음으로 다시 만나게 됨

소개

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

이 도움말은 브라우저에 터치 기능이 내장되어 있는 방식, 이 새로운 인터페이스 메커니즘을 기존 앱에 통합하는 방법, 마우스 입력 시 터치가 원활하게 작동하는 방식을 이해하는 데 도움을 줍니다.

웹 플랫폼의 활용 현황

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

제 동료인 Boris Smus가 터치 이벤트에 관한 HTML5Rocks 튜토리얼을 작성했는데, 이는 터치 이벤트를 처음 접하는 분도 쉽게 시작할 수 있는 좋은 방법입니다. 실제로 이전에 터치 이벤트로 작업해 본 적이 없다면 계속하기 전에 지금 해당 도움말을 읽어보세요. 자, 기다릴게요.

모두 완료되었다면, 이제 터치 이벤트에 대한 기본적인 기초를 갖추었으므로 터치 지원 상호작용을 작성할 때의 과제는 터치 상호작용이 마우스 (및 마우스 에뮬레이션 트랙패드 및 트랙볼) 이벤트와 상당히 다를 수 있다는 것입니다. 터치 인터페이스는 일반적으로 마우스를 에뮬레이션하려고 하지만 에뮬레이션이 완벽하거나 완전하지는 않습니다. 실제로 두 가지 상호작용 스타일을 통해 작업해야 하며 각 인터페이스를 독립적으로 지원해야 할 수 있습니다.

가장 중요한 사항: 사용자가 터치와 마우스를 사용할 수 있음

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

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

마우스와 터치 함께 지원

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

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

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

  1. 터치시작
  2. 터치 동작
  3. Touchend
  4. 마우스 오버
  5. mousemove
  6. 마우스다운
  7. 마우스 업
  8. click

이는 물론, touchstart와 같은 터치 이벤트를 처리하는 경우 상응하는 마우스 다운 및 클릭 이벤트도 처리하지 않도록 해야 합니다. 터치 이벤트를 취소할 수 있으면 (이벤트 핸들러 내에서 preventDefault()를 호출함) 터치에 대한 마우스 이벤트가 생성되지 않습니다. 터치 핸들러의 가장 중요한 규칙 중 하나는 다음과 같습니다.

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

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

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

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

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

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

물론 항상 적절한 것은 아닙니다. 이 경우 손가락 모으기(핀치 확대/축소)가 비활성화되어 접근성을 이유로 필요할 수 있으므로 가급적 사용하지 않는 것이 좋습니다(사용자 크기 조정을 사용하지 않을 경우 애플리케이션에서 텍스트 가독성을 높일 수 있는 다른 방법을 제공해야 할 수 있음). 또한 터치를 지원하는 데스크톱 클래스 기기의 Chrome과 페이지에 확장할 수 없는 표시 영역이 있는 모바일 플랫폼의 기타 브라우저에서는 이러한 지연이 적용되지 않습니다.

#2: Mousemove 이벤트가 터치로 실행되지 않음

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

브라우저는 일반적으로 HTML 컨트롤에서의 터치 상호작용을 위한 적절한 상호작용을 자동으로 구현합니다. 따라서 예를 들어 HTML5 범위 컨트롤은 터치 상호작용을 사용할 때만 작동합니다. 그러나 자체 컨트롤을 구현했다면 클릭 앤 드래그 유형의 상호작용에서 작동하지 않을 가능성이 높습니다. 실제로 jQueryUI와 같이 일반적으로 사용되는 일부 라이브러리는 아직 이 방식으로 터치 상호작용을 기본적으로 지원하지 않습니다(jQueryUI의 경우 이 문제에 대한 여러 가지 원숭이 패치 수정이 있음). 이는 웹 오디오 플레이그라운드 애플리케이션을 터치와 연동하도록 업그레이드할 때 가장 먼저 겪은 문제 중 하나였습니다. 슬라이더는 jQueryUI 기반이었기 때문에 클릭 앤 드래그 상호작용에서는 작동하지 않았습니다. HTML5 범위 컨트롤로 바꾸면 제대로 작동했습니다. 또는 단순히 touchmove 핸들러를 추가하여 슬라이더를 업데이트할 수도 있지만, 여기에는 한 가지 문제가 있습니다.

#3: Touchmove와 MouseMove는 다른 것

몇몇 개발자들이 경험한 함정은 touchmove 및 mousemove 핸들러가 동일한 코드 경로를 호출하는 것입니다. 이 이벤트의 동작은 매우 가깝지만 미묘하게 다릅니다. 특히 터치 이벤트는 항상 터치가 시작된 요소를 타겟팅하는 반면 마우스 이벤트는 현재 마우스 커서 아래에 있는 요소를 타겟팅합니다. 이러한 이유로 마우스오버 및 마우스아웃 이벤트는 있지만 해당하는 터치오버 및 터치아웃 이벤트는 없습니다. touchend만 있습니다.

이 괴로움을 일으킬 수 있는 가장 일반적인 방법은 사용자가 터치하기 시작한 요소를 우연히 삭제 (또는 재배치)하는 것입니다. 예를 들어 맞춤 스크롤 동작을 지원하기 위해 전체 캐러셀에서 터치 핸들러가 있는 이미지 캐러셀을 상상해 보세요. 사용 가능한 이미지가 변경됨에 따라 일부 <img> 요소를 삭제하고 다른 요소를 추가합니다. 사용자가 이러한 이미지 중 하나를 터치하기 시작한 다음 이를 삭제하면 핸들러 (img 요소의 상위 항목에 있는)가 터치 이벤트 수신을 중단합니다 (더 이상 트리에 있지 않은 타겟으로 전달되기 때문). 사용자가 이동했다가 최종적으로 삭제했더라도 한 곳에서 손가락을 잡고 있는 것처럼 보일 것입니다.

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

#4: 터치 및 :마우스 오버

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

그러나 흥미롭게도 CSS :hover pseudoclass는 경우에 따라 터치 인터페이스에 의해 트리거될 수 있습니다. 요소를 탭하면 손가락이 내려가 있는 동안 :활성화되고 :hover 상태도 획득합니다. (Internet Explorer의 경우 :마우스 오버는 사용자가 손가락을 누르고 있는 동안에만 적용됩니다. 다른 브라우저에서는 다음 탭 또는 마우스가 움직일 때까지 :hover가 계속 적용됩니다.) 이는 터치 인터페이스에서 크게 보기 메뉴를 작동시키는 좋은 방법입니다. 요소를 활성 상태로 만들면 :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 없이 마우스 오버나 클릭, 터치 탭 또는 키 누름 시 추가 정보를 전환할 수 있습니다. 웹 오디오 플레이그라운드가 터치 인터페이스와 잘 연동되도록 작업을 시작하면서 크게 놀랐습니다. 이러한 구조를 사용한 적이 있었기 때문에 크게 팝아웃 메뉴가 터치했을 때 잘 작동했습니다.

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

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

#5: 터치와 마우스 정밀도 비교

마우스는 현실과 개념적으로 분리되어 있지만, 기본 운영체제가 일반적으로 커서의 정확한 픽셀 정밀도를 추적하기 때문에 마우스는 매우 정확합니다. 반면에 모바일 개발자는 터치 스크린에서 손가락 터치가 정확하지 않다는 것을 알게 되었습니다. 대부분은 화면에 닿을 때 손가락의 표면적 크기 때문에 (그리고 부분적으로는 손가락이 화면을 가리기 때문)입니다.

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

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

#6: 터치 핸들러를 억제하지 않으면 스크롤이 버벅거림

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

이 문제를 방지하기 위해 따라야 할 지침 중 하나는 UI의 작은 부분에서만 터치 이벤트를 처리하는 경우 터치 핸들러를 페이지의 <body>가 아닌 여기에만 연결하는 것입니다. 간단히 말하면 터치 핸들러의 범위를 최대한 제한합니다.

#7: 멀티터치

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

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

현재 구현된 W3C Touch API에는 하드웨어가 지원하는 터치 포인트 수를 결정하는 API가 없으므로 사용자가 원하는 터치 포인트 수에 대한 최선의 추정치를 사용하거나 실제로 접하고 조정하는 터치 포인트 수에 주의를 기울여야 합니다. 예를 들어 피아노 애플리케이션에서는 두 개 이상의 터치 포인트가 표시되지 않는 경우 일부 '코드' UI를 추가할 수 있습니다. PointerEvents API에는 기기의 기능을 확인하는 API가 있습니다.

보정

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

이러한 지침을 따르면 비교적 쉽게 빌드할 수 있을 뿐만 아니라 터치 입력, 마우스 입력, 심지어 두 가지 상호작용 스타일 모두에 잘 작동하는 매력적인 상호작용 환경을 구축할 수 있습니다.