다시 함께하는 첫 번째 시간
소개
거의 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' 이벤트가 계속 실행되므로 이를 바로가기로 사용할 수 있습니다. 하지만 이 바로가기에는 몇 가지 문제가 있습니다.
먼저, 고급 터치 상호작용을 설계할 때는 주의해야 합니다. 사용자가 마우스를 사용하면 클릭 이벤트를 통해 응답하지만, 사용자가 화면을 터치하면 터치 이벤트와 클릭 이벤트가 모두 발생합니다. 한 번 클릭의 경우 이벤트 순서는 다음과 같습니다.
- touchstart
- touchmove
- touchend
- 마우스 오버
- mousemove
- mousedown
- mouseup
- 클릭
즉, touchstart와 같은 터치 이벤트를 처리하는 경우 해당 mousedown 또는 클릭 이벤트도 처리하지 않도록 해야 합니다. 터치 이벤트를 취소할 수 있는 경우 (이벤트 핸들러 내에서 preventDefault() 호출) 터치에 대한 마우스 이벤트가 생성되지 않습니다. 터치 핸들러의 가장 중요한 규칙 중 하나는 다음과 같습니다.
하지만 이로 인해 다른 기본 브라우저 동작 (예: 스크롤)도 방지됩니다. 일반적으로 핸들러에서 터치 이벤트를 완전히 처리하고 기본 작업을 사용 중지하고 싶을 것입니다. 일반적으로 모든 터치 이벤트를 처리하고 취소하거나 해당 이벤트에 대한 핸들러를 사용하지 않는 것이 좋습니다.
둘째, 사용자가 휴대기기에서 웹페이지의 요소를 탭할 때 모바일 상호작용을 위해 설계되지 않은 페이지는 touchstart 이벤트와 마우스 이벤트 (mousedown) 처리 사이에 최소 300밀리초의 지연이 발생합니다. Chrome을 사용하여 이 작업을 수행할 수 있습니다. Chrome 개발자 도구에서 '터치 이벤트 에뮬레이션'을 사용 설정하면 터치 인터페이스가 아닌 시스템에서 터치 인터페이스를 테스트할 수 있습니다.
이 지연은 브라우저가 사용자가 다른 동작(특히 두 번 탭하여 확대/축소)을 수행하는지 판단할 시간을 주기 위한 것입니다. 물론 손가락 터치에 즉각적으로 반응해야 하는 경우에는 문제가 될 수 있습니다. 이 지연이 자동으로 발생하는 시나리오를 제한하기 위한 작업이 진행 중입니다.
이 지연을 방지하는 가장 쉽고 첫 번째 방법은 페이지에 확대/축소가 필요하지 않다고 모바일 브라우저에 '알리는' 것입니다.이는 고정된 표시 영역을 사용하여 수행할 수 있습니다(예: 페이지에 삽입).
<meta name="viewport" content="width=device-width,user-scalable=no">
물론 이 방법이 항상 적절한 것은 아닙니다. 이 방법은 접근성 이유로 필요할 수 있는 핀치 줌을 사용 중지하므로, 사용하더라도 가급적 적게 사용하세요 (사용자 확장을 사용 중지하는 경우 애플리케이션에서 텍스트 가독성을 높이는 다른 방법을 제공하는 것이 좋습니다). 또한 터치를 지원하는 데스크톱 클래스 기기의 Chrome과 페이지에 확장 불가능한 표시 영역이 있는 모바일 플랫폼의 다른 브라우저의 경우 이 지연이 적용되지 않습니다.
#2: 터치로 mousemove 이벤트가 실행되지 않음
이 시점에서 터치 인터페이스의 마우스 이벤트 에뮬레이션은 일반적으로 mousemove 이벤트 에뮬레이션으로 확장되지 않는다는 점에 유의해야 합니다. 따라서 mousemove 이벤트를 사용하는 멋진 마우스 기반 컨트롤을 빌드하는 경우 touchmove 핸들러도 특별히 추가하지 않는 한 터치 기기에서 작동하지 않을 수 있습니다.
브라우저는 일반적으로 HTML 컨트롤의 터치 상호작용에 적절한 상호작용을 자동으로 구현합니다. 예를 들어 HTML5 범위 컨트롤은 터치 상호작용을 사용할 때 작동합니다. 하지만 자체 컨트롤을 구현한 경우 클릭 후 드래그 유형의 상호작용에서는 작동하지 않을 수 있습니다. 실제로 흔히 사용되는 일부 라이브러리 (예: jQueryUI)는 아직 이러한 방식으로 터치 상호작용을 기본적으로 지원하지 않습니다 (jQueryUI의 경우 이 문제에 대한 몇 가지 몽키 패치 수정이 있음). 이것은 터치와 함께 작동하도록 Web Audio Playground 애플리케이션을 업그레이드할 때 발생한 첫 번째 문제 중 하나였습니다. 슬라이더는 jQueryUI 기반이므로 클릭 및 드래그 상호작용과 함께 작동하지 않았습니다. HTML5 범위 컨트롤로 변경했더니 작동했습니다. 물론, 슬라이더를 업데이트하기 위해 touchmove 핸들러를 추가할 수도 있지만, 여기에는 한 가지 문제가 있습니다.
#3: Touchmove와 MouseMove는 동일하지 않음
일부 개발자가 빠지는 함정은 touchmove 및 mousemove 핸들러가 동일한 코드 경로를 호출하도록 하는 것입니다. 이러한 이벤트의 동작은 매우 유사하지만 미묘하게 다릅니다. 특히 터치 이벤트는 항상 터치가 시작된 요소를 타겟팅하는 반면 마우스 이벤트는 현재 마우스 커서 아래에 있는 요소를 타겟팅합니다. 이것이 마우스 오버 및 마우스 아웃 이벤트가 있지만 해당 터치 오버 및 터치 아웃 이벤트가 없는 이유입니다. 터치 엔드만 있습니다.
이 문제가 발생하는 가장 일반적인 경우는 사용자가 터치하기 시작한 요소를 삭제하거나 재배치하는 경우입니다. 예를 들어 맞춤 스크롤 동작을 지원하기 위해 전체 캐러셀에 터치 핸들러가 있는 이미지 캐러셀을 생각해 보세요. 사용 가능한 이미지가 변경되면 일부 <img> 요소를 삭제하고 다른 요소를 추가합니다. 사용자가 이러한 이미지 중 하나를 터치하기 시작한 후 이미지를 삭제하면 핸들러 (img 요소의 상위 요소에 있음)가 터치 이벤트 수신을 중지합니다 (더 이상 트리에 없는 타겟으로 전달되기 때문). 사용자가 손가락을 움직여 결국 삭제했더라도 손가락을 한곳에 대고 있는 것처럼 보입니다.
물론 터치가 활성 상태인 동안 터치 핸들러가 있는 요소 (또는 터치 핸들러가 있는 상위 요소)를 삭제하지 않으면 이 문제를 방지할 수 있습니다. 또는 정적 touchend/touchmove 핸들러를 등록하는 대신 touchstart 이벤트를 가져올 때까지 기다린 다음 touchmove/touchend/touchcancel 핸들러를 touchstart 이벤트의 대상에 추가하는 것이 가장 좋습니다 (종료/취소 시 삭제). 이렇게 하면 타겟 요소가 이동/삭제되더라도 터치 이벤트를 계속 수신할 수 있습니다. 여기에서 직접 테스트해 볼 수 있습니다. 빨간색 상자를 터치하고 누른 상태에서 Esc 키를 누르면 DOM에서 삭제됩니다.
#4: 터치 및 :hover
마우스 포인터 메타포는 커서 위치를 활성 선택과 분리했으며, 이를 통해 개발자는 마우스 오버 상태를 사용하여 사용자에게 관련이 있을 수 있는 정보를 숨기거나 표시할 수 있었습니다. 하지만 현재 대부분의 터치 인터페이스는 대상 위에서 손가락을 '가리키는' 동작을 감지하지 못합니다.따라서 가리키는 동작을 기반으로 의미상 중요한 정보 (예: '이 컨트롤은 무엇인가요?' 팝업)를 제공하는 것은 금물입니다. 단, 이 정보에 액세스할 수 있는 터치 친화적인 방법을 제공하는 경우는 예외입니다. 마우스 오버를 사용하여 사용자에게 정보를 전달하는 방법에 주의해야 합니다.
하지만 흥미롭게도 CSS :hover 의사 클래스는 경우에 따라 터치 인터페이스에 의해 트리거될 수 있습니다. 요소를 탭하면 손가락을 누르고 있는 동안 :active 상태가 되고 :hover 상태도 획득합니다. (Internet Explorer에서는 사용자의 손가락이 아래로 내려가 있는 동안에만 :hover가 적용됩니다. 다른 브라우저에서는 다음 탭 또는 마우스 이동까지 :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 없이도 마우스 오버 또는 클릭, 터치 탭 또는 키 누르기로 추가 정보를 전환할 수 있습니다. Web Audio Playground가 터치 인터페이스에서 잘 작동하도록 작업을 시작했을 때, 이러한 구조를 사용했기 때문에 팝업 메뉴가 이미 터치에서 잘 작동한다는 사실을 알고 기분 좋게 놀랐습니다.
위 방법은 마우스 포인터 기반 인터페이스와 터치 인터페이스에 적합합니다. 이는 마우스 오버 시 'title' 속성을 사용하는 것과 대조적입니다. 이 경우 요소가 활성화될 때 표시되지 않습니다.
<img src="/awesome.png" title="this doesn't show up in touch">
#5: 터치와 마우스의 정밀도
마우스는 현실과 개념적으로 분리되어 있지만, 기본 운영체제가 일반적으로 커서의 정확한 픽셀 정밀도를 추적하므로 매우 정확한 것으로 나타났습니다. 반면 모바일 개발자는 터치 스크린에서 손가락 터치가 정확하지 않다는 것을 알게 되었습니다. 이는 주로 화면과 접촉할 때 손가락의 표면적 크기 때문입니다 (일부는 손가락이 화면을 가리기 때문).
많은 개인과 기업이 손가락 기반 상호작용을 수용하는 애플리케이션과 사이트를 설계하는 방법에 관해 광범위한 사용자 연구를 수행했으며, 이 주제에 관한 많은 책이 작성되었습니다. 기본적인 조언은 패딩을 늘려 터치 영역의 크기를 늘리고 요소 간의 여백을 늘려 잘못된 탭의 가능성을 줄이는 것입니다. (패딩은 터치 및 클릭 이벤트의 히트 감지 처리에 포함되지만 여백은 포함되지 않습니다.) Web Audio Playground에서 수정해야 했던 주요 사항 중 하나는 연결 지점의 크기를 늘려 정확하게 터치하기 쉽게 만드는 것이었습니다.
터치 기반 인터페이스를 처리하는 많은 브라우저 공급업체는 사용자가 화면을 터치할 때 올바른 요소를 타겟팅하고 잘못된 클릭 가능성을 줄이기 위해 브라우저에 로직을 도입했습니다. 하지만 이는 일반적으로 클릭 이벤트만 수정하고 이동은 수정하지 않습니다 (Internet Explorer는 mousedown/mousemove/mouseup 이벤트도 수정하는 것으로 보임).
#6: 터치 핸들러를 포함하지 않으면 스크롤이 버벅거립니다.
또한 터치 핸들러를 필요한 요소로만 제한하는 것이 중요합니다. 터치 요소는 대역폭이 매우 높을 수 있으므로 스크롤 요소에서 터치 핸들러를 피하는 것이 중요합니다 (처리가 브라우저 최적화를 방해하여 빠르고 버벅거림 없는 터치 스크롤을 방해할 수 있기 때문입니다. 최신 브라우저는 GPU 스레드에서 스크롤하려고 하지만 각 터치 이벤트가 앱에서 처리될지 여부를 먼저 자바스크립트로 확인해야 하는 경우 이는 불가능합니다). 이 동작의 예시를 확인할 수 있습니다.
이 문제를 방지하기 위해 따라야 할 한 가지 지침은 UI의 작은 부분에서만 터치 이벤트를 처리하는 경우 터치 핸들러를 해당 부분에만 연결하는 것입니다 (예: 페이지의 <body>에 연결하지 않음). 즉, 터치 핸들러의 범위를 최대한 제한하세요.
#7: 멀티 터치
마지막으로 흥미로운 과제는 지금까지 '터치' 사용자 인터페이스라고 지칭해 왔지만, 실제로는 거의 모든 경우에 멀티터치를 지원한다는 점입니다. 즉, API는 한 번에 두 개 이상의 터치 입력을 제공합니다. 애플리케이션에서 터치를 지원하기 시작할 때 여러 터치가 애플리케이션에 미칠 수 있는 영향을 고려해야 합니다.
주로 마우스로 구동되는 앱을 빌드해 왔다면 최대 하나의 커서 포인트로 빌드하는 데 익숙할 것입니다. 시스템은 일반적으로 여러 마우스 커서를 지원하지 않습니다. 많은 애플리케이션의 경우 터치 이벤트를 단일 커서 인터페이스에 매핑하기만 하면 되지만, 데스크톱 터치 입력용으로 확인된 대부분의 하드웨어는 최소 2개의 동시 입력을 처리할 수 있으며 대부분의 새로운 하드웨어는 최소 5개의 동시 입력을 지원하는 것으로 보입니다. 화면 피아노 키보드를 개발하려면 당연히 여러 개의 동시 터치 입력을 지원할 수 있어야 합니다.
현재 구현된 W3C 터치 API에는 하드웨어에서 지원하는 터치 포인트 수를 결정하는 API가 없으므로 사용자가 원하는 터치 포인트 수를 가장 잘 추정해야 합니다. 물론 실제로 표시되는 터치 포인트 수에 주의를 기울이고 조정해야 합니다. 예를 들어 피아노 애플리케이션에서 터치 포인트가 2개 이상 표시되지 않는 경우 '코드' UI를 추가할 수 있습니다. PointerEvents API에는 기기의 기능을 확인하는 API가 있습니다.
보정 중
이 도움말이 마우스 상호작용과 함께 터치를 구현할 때 발생하는 일반적인 문제에 대한 지침을 제공했기를 바랍니다. 물론 다른 어떤 조언보다 중요한 것은 모바일, 태블릿, 마우스와 터치가 결합된 데스크톱 환경에서 앱을 테스트해야 한다는 것입니다. 터치+마우스 하드웨어가 없는 경우 Chrome의 '터치 이벤트 에뮬레이션'을 사용하여 다양한 시나리오를 테스트하세요.
터치 입력, 마우스 입력, 심지어 두 가지 상호작용 스타일을 동시에 사용하는 경우에도 잘 작동하는 매력적인 대화형 환경을 구축하는 것은 가능할 뿐만 아니라 다음 안내를 따르면 비교적 쉽습니다.