본문 바로가기

UX/기술과 사용자 경험

페이지 뒤로가기

이드 소프트웨어의 역작, 둠 1 입니다.

시작하기 전에

우리는 지표(signal)들과 함께 살고 있습니다. 지표를 만들기도 하고 지표를 보고 이해를 합니다. 지표들 중에서 단연 쉽게 마주칠 수 있는 것은 표지판입니다. 운전을 할 때 좌회전이 가능한지에 대한 여부나 내가 어느 위치에 있는지 등 직관적인 정보를 해석할 수 있게 도움을 줍니다.

그런데 만약 이러한 정보들을 제공하는 지표가 잘못된 정보를 이해하도록 한다면 어떻게 될까요? 최악의 경우는 의도를 잘못 이해하고 이에 따라서 행동하게 될 것입니다. 예를 들자면 다음과 같은 경우가 있겠습니다. 'Doom 1'을 플레이하는 유저가 미로를 찾는 과정에서 왼쪽 길은 막다른 길인데 왼쪽으로 이동할 수 있다는 방향 지시 표를 보게 되는 상황과 같습니다. 유저는 왼쪽으로 이동을 해보고 막다른 길인 것을 확인하게 됩니다. 바로 확인하게 된다면 큰 손해를 보는 것은 아니지만 불필요한 동작을 수행하게 되고, 게임에서 제공하는 방향 지시 표에 대한 신뢰를 잃어갈 수 있습니다.

웹 브라우저 뒤로 가기

웹 브라우저는 history(https://developer.mozilla.org/ko/docs/Web/API/History_API) 객체를 통해서 페이지 이동을 가능하게 합니다. 그런데 해당 객체는 페이지의 이동만을 지원하며, 내가 어느 위치에 존재하고 어떤 페이지 히스토리들이 저장되어 있는지 알 수 없습니다. 모바일 웹 페이지에 접근하는 방법은 크게 3가지가 있습니다.

 

1. 웹 브라우저에서 검색을 통해서 웹 페이지 링크를 찾고, 해당 링크를 통해 접속

2. URL(https://ko.wikipedia.org/wiki/URL) 입력 후 접속

3. 카카오톡, 문자 메시지 등 웹 브라우저가 아닌 공간에서 링크를 클릭해 접속

브라우저의 navigation status bar를 확인해보면 1, 2의 경우는 뒤로 가기가 가능하며 3은 불가능합니다.

 

웹 페이지 내부에서도 뒤로 가기 버튼이 존재한다면 어떻게 될까요? 모바일 웹 페이지들은 뒤로 가기 버튼을 통해 페이지 이동성을 강화하고 사용자 경험을 좋게 하기 위해서 많이 채용합니다. 그리고 보통 history 객체의 뒤로 가기 기능을 통해서 구현합니다.

 

<a href="javascript:history.back();" >
	<img src="" />
</a>

 

1, 2의 상황에 대해서 뒤로 가기 버튼은 브라우저의 내비게이션 바에서 제공하는 기능과 동일하게 사용자 경험을 해치지 않고 동작합니다. 그러나 3의 경우가 문제입니다. 브라우저의 내비게이션 바는 disabled 상태이기 때문입니다.

 

클릭을 하더라도 동작하지 않고 같은 페이지에 있는 것을 해결하기 위해 다음과 같은 방식들이 있습니다.

 

a. history.length

history 객체는 웹 페이지 기록들의 index에 대한 정보를 제공할 수 없기 때문에 history.length() === 0인 경우를 확인해 웹 페이지 서비스의 루트로 redirect 하게 처리하는 방식을 선택할 수 있습니다.

 

<a href="javascript:(if (history.length) { history.back(); } else { location.href = 'www.naver.com'; })" >
...

 

해당 방식은 얼핏 보기에는 3을 직관적이고 간편하게 해결한 것처럼 보이지만, history를 앞으로 쌓는 경우를 대응할 수 없습니다. 즉 브라우저가 아닌 다른 곳에서 링크를 통해 접속한 첫 상황은 완벽하게 동작하지만 해당 페이지에서 또 링크를 통해 이동한 이후 뒤로 가기를 수행한다면, 다시 돌아온 페이지는 history.length가 0이 아니기 때문에 서비스 루트 페이지로 이동을 하지 못하고 history.back()을 수행합니다. 그리고 그 수행 결과는 뒤 페이지가 없기 때문에 동작하지 않고 같은 페이지에 머무르게 됩니다.

 

b. document.referrer

referrer(https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Referer)는 웹 브라우저로 www(월드 와이드 웹)을 서핑할 때 하이퍼링크를 통해서 각각의 사이트로 방문 시 남는 흔적을 말합니다. 그래서 referrer는 현재 요청을 보낸 페이지의 절대 혹은 부분 주소를 포함하게 되는데, 링크를 타고 들어왔다면 해당 링크를 포함하고 있는 페이지의 주소를 인식할 수 있도록 사용할 수 있습니다. referrer를 확인해서 없는 경우 ""으로 값이 설정되며 이를 확인해 웹 페이지 서비스의 루트로 redirect 하게 처리하는 방식을 선택할 수 있습니다.

 

<a href="javascript:(if (document.referrer) history.back(); else { location.href = 'www.naver.com'; })" >
...

 

해당 방식은 3에 대해서 완벽하게 동작하지만 2와 3을 구분할 수 없습니다. referrer는 하이퍼링크를 통한 경우만 값이 남게 되어서, URL을 직접 입력한 경우 ""로 값이 설정됩니다.

 

c. location.href

history.back()을 실행하고 나서도 같은 페이지에 존재하는 경우 웹 페이지 서비스의 루트로 redirect 하게 처리하는 방식입니다.

 

<a href="javascript:(function () { var _href = location.href; history.back(); setTimeout(() => { if(_href === location.href) { location.href = 'www.naver.com'; } }, 3000); })();" >
...

 

history.back()의 경우 이전 페이지가 없는 경우(https://developer.mozilla.org/ko/docs/Web/API/History/back) 아무것도 하지 않습니다. 다만 이 행위가 비동기적으로 이루어지기 때문에 이러한 부분에 대해서 처리가 필요합니다. history.back(). then()이 있다면 method chain을 통해서 적용할 수 있겠지만 해당 기능을 지원하지 않아 불가능합니다. (해당 기능 관련해서 해답이 있다면 공유 부탁드리겠습니다.)

history.back()의 결과를 확인하는 부분은 window.onpopstate (https://developer.mozilla.org/ko/docs/Web/API/Window/popstate_event)를 통해서 확인할 수 있는데, 해당 event handler는 state.pop()가 일어난 경우만 확인이 가능해서 동작이 일어나지 않은 history.back()을 인지할 수 있는 방법이 없습니다. 비동기 처리에 대한 time delay를 처리하지 않으면 같은 페이지로 인식해서 서비스 루트 페이지로 이동하기 때문에 timeout이 필요합니다. 네트워크 상황과 현재 위치하는 페이지 사이즈에 따라 조금씩 다르지만 300ms ~ 2000ms 사이에 동작하는 것으로 보입니다. 이러한 처리는 인위적인 시간 지연을 필요로 하기 때문에 사용자가 페이지 대기를 하는 시간이 늘어나서 사용자 경험을 떨어뜨립니다.

다른 관점에서 바라보기

제가 공유드린 세 방식들은 이러한 이슈를 깔끔하게 처리하지 못합니다. 방식이 잘못되었다는 말씀을 드리기보다는, 다시 한번 사용자 관점에서 고민이 필요하다는 말씀을 드리고 싶습니다. 현재 이슈의 핵심은 '인지부조화'입니다. 브라우저의 뒤로 가기와 웹 페이지에서 제공하고 있는 뒤로 가기가 상충하고 있기 때문입니다. 인지부조화는 미국 심리학자 레온 페스팅거(Leon Festinger)가 저술한 [인지부조화 이론]에서 유래한 말로, 기존의 신념(브라우저의 뒤로 가기 기능)과 새로 인지한 증거(웹 페이지에서 제공하는 뒤로 가기)가 충돌되는 상황에서 가지는 정신적 불편함을 의미합니다. 인지부조화를 해소하기 위해 사용자 개인이 진행하는 패러다임은 개인의 자기 정당화이며 근본적인 해결책이 되지 못하기 때문에, 상충하고 있는 상황을 해소하는 것이 필요합니다.

 

뒤로 가기가 불가능한 상황이나 뒤로 가기가 의미 없는 상황에 대해서 상충하고 있는 뒤로 가기 기능을 다르게 동작하며 풀어가는 것이 아니라, 대립하지 않도록 우회하는 방식이 사용자 경험을 해치지 않을 수 있습니다.

 

<% if (!document.referrer) { %>
<a href="javascript:location.href = 'www.naver.com';" >
	<img src="" alt="main" />
</a>
<% } else { %>
<a href="javascript:history.back();" >
	<img src="" alt="back" />
</a>
<% } %>

 

1의 경우 referrer가 존재하기 때문에 뒤로 가기 버튼을 노출하고, 브라우저 내비게이션 기능과 합일하도록 기능합니다. 2, 3의 경우 referrer가 존재하지 않기 때문에 뒤로 가기 버튼을 노출하지 않고 메인으로 가는 (ex. 네이버로 치면 'N') 버튼을 노출하는 것으로 브라우저 내비게이션과 아예 다른 기능임을 사용자에게 은유적으로 제시할 수 있습니다.

 

referrer가 존재하지 않는 경우 홈 버튼을 노출합니다.
referrer가 존재하는 경우 뒤로가기 버튼을 노출합니다.

이러한 처리 방식은 게슈탈트 인지와 밀접하게 연관되어 있습니다. 게슈탈트(Gestalt)는 독일어로 형태나 모양을 의미하는 단어입니다. 게슈탈트 인지는 디자인한 밈(사용자의 행동을 의도하는 일련의 구성요소, 즉 텍스트 / 이미지 / 애니메이션 / 팝업 등 모든 것이 될 수 있습니다.)을 형태나 그 주변에 배치된 사물을 기준으로 판단하는 것을 뜻합니다. 사용자는 페이지에서 제공하는 구성요소를 만든 로직을 포함하고 있는 소스코드를 모두 알지 못하며, 오직 첫 인지에 따른 기능을 유추할 뿐입니다. 그렇기 때문에 뒤로 이동하는 것처럼 보이는 지표는 실제로 뒤로 가기를, 홈으로 이동하는 것처럼 보이는 지표는 실제로 홈으로 이동하게 해 줌으로써 인지 병목 현상을 해결해 줄 수 있습니다. 

남은 궁금증

제가 말씀드린 부분은 기술적 한계에서 생긴 부분을 우회하는 것의 일종입니다. 이러한 방법을 말씀드리면서도 제 자신도 근본적인 해결책이 아님을 느끼고 있습니다. 근본적인 해결책은 사실 "뒤로 가기가 불가능한 경우 뒤로 가기 버튼에 disabled 처리를 하기"가 아닐까 합니다. Web API에서 뒤로 가기 가능 여부(canBack)와 같은 기능을 제공하지 않기 때문에 해결책을 구현하지 못했다는 것이 너무 아쉽습니다.

 

왜 가능한 것일까요? 그리고 어떻게 가능하게 했을까요?

또한 Web API에서는 history 객체의 이동만 가능하며 어떤 history가 어디에 존재하는지 확인할 수 없는데 브라우저의 뒤로 가기 버튼을 길게 누르면, 어디에 존재하는지 알 수 있으며 이 기능은 history.back()을 정확히 지원한다는 사실이 너무 궁금하면서 제 자신을 괴롭게 합니다.

 

마음 한편에 담아둔 채로 이 두 기능을 sync 하는 그날까지 리서치를 해보겠습니다.

 

※ 잘못된 부분이나 궁금한 점 댓글로 작성해 주시면 최대한 답변하겠습니다. 읽어주셔서 감사합니다~