『UX/UI의 10가지 심리학 법칙』과 프론트엔드 코드 예시

Namu CHO
23 min readJun 24, 2024

--

어쩌면 당연하게 느껴지는 법칙들을 자세히 들여다볼 수 있었던 기회였다.

들어가며

개발자가 웬 디자인 책을 읽나?

프론트엔드 개발자로서 개발자 경력을 시작하면서 받았던 스트레스 중 하나는 공부할 것이 너무 많다는 것이었다.

단지 개발만 하는 것 뿐만 아니라,

디자이너가 요구하는 디자인에 대한 피드백을 제공하고 더 나아가 더 좋은 대안을 제시할 수 있어야 한다고 생각했기 때문이다.

따라서 마음 한 구석엔 디자인과 관련한 시간 투자 및 공부에 대한 마음에 대한 부채감이 늘있었기 때문에 이번 기회에 디자인관련 책을 읽게 되었다.

핵심 내용

1. 제이콥의 법칙

사용자는 웹사이트가 익숙한 방식으로 동작하기를 기대한다.

  • 사용자는 자신에게 익숙한 제품을 통해 구축한 기대치를 그와 비슷해 보이는 다른 제품에도 투영한다.
  • 기존의 멘탈 모델을 활용하면 사용자가 새 모델을 익히지 않아도 바로 작업에 돌입할 수 있는 뛰어난 사용자 경험이 완성된다.
  • 변화를 꾀할 때는, 사용자에게 익숙한 모델을 한시적으로 이용할 권한을 부여해서 멘탈 모델의 부조화를 최소화하라.

제이콥의 법칙에 관해 내가 할 수 있는 최선의 조언은 처음에는 일반적인 패턴과 관례를 따르고, 가능할 경우 디자인 시스템 같은 도구를 이용하다가, 이치에 맞는 새 아이디어가 떠오를 때만 과감히 벗어나라는 것이다.

예시) 폼 form

사용자는 텍스트 인풋, 라디오 버튼, 체크박스 등의 동작방식에 익숙해져있기 때문에 어디에서 폼을 보더라도 해당 요소들이 익숙한 동작방식과 같은 방식으로 동작하기를 바란다.

예를 들어 인풋 박스 안을 클릭하면 포커스가 잡히고 글자를 타이핑할 수 있고, 인풋 외부 영역을 클릭하면 글자를 타이핑 할 수 없도록 동작하기를 바란다.

여기서 더 나은 사용자 경험을 위해 라벨을 클릭해도 해당 인풋요소가 클릭되도록 처리해주는 것이 좋다.

    <!-- option 1: label 태그로 input 태그를 감싼다. -->
<label>
text 1 input
<input type="text" placeholder="text 1" />
</label>

<!-- option 2: label 태그에 for attribute를 이용하여 input을 매핑한다. -->
<label for="text2">text 2 input</label>
<input id="text2" type="text" placeholder="text 2" />

2. 피츠의 법칙

크기와 위치 배치를 잘하자.

  • 터치 대상의 크기는 사용자가 정확하게 선택할 수있을 정도로 충분히 커야 한다.
  • 터치 대상 사이에 충분한 거리를 확보해야 한다.
  • 터치 대상은 인터페이스상에서 쉽게 도달할 수 있는 영역에 배치해야 한다.

예시)

a태그로 링크를 만들 경우 해당 글자를 정확히 클릭해야만 링크를 건 페이지로 이동할 수 있다.

하지만 글자를 정확히 클릭해야만 하는 것은 사용자 경험에 좋지 않다.

그렇기 때문에 클릭 영역을 확장해주는 것이 더 좋은 사용자 경험에 도움이 된다.

출처: https://stackoverflow.com/questions/11078509/how-to-increase-the-clickable-area-of-a-a-tag-button
a {
display: inline-block;
padding: 2em; /* 클릭 영역을 확장해준다. */
margin: -2em; /* 패딩을 확장한 만큼 다른 요소들과의 거리를 조정해준다. */
}

3. 밀러의 법칙

사람은 최대 7 (+-2)개의 항목밖에 저장하지 못한다.

  • 사용자가 쉽게 처리하고 이해하고 기억할 수 있게 콘텐츠 덩어리를 작게 나눠 정리하자
  • 단기 기억 용량은 사람에 따라, 그리고 기존 지식과 상황적 맥락에 따라 달라진다는 것을 기억하자.
  • ‘마법의 숫자 7’을 내세워 불필요한 디자인 제약을 정당화하지 마라.

예시) 전화번호 표시

긴 전화 번호를 전부 나열하는 것보다, 중간에 끊어서 표기함으로써 사용자의 가독성을 높일 수 있다.

위 그림처럼 번호 중간에 -을 추가하는 간단한 코드 예시이다.


<label for="phone">전화번호:</label>
<input type="text" id="phone" maxlength="9" placeholder="XXXX-XXXX" />
const phoneInput = document.getElementById("phone");

phoneInput.addEventListener("keyup", function (e) {
let value = e.target.value.replace(/-/g, "");

if (value.length > 4) {
value = value.slice(0, 4) + "-" + value.slice(4);
}

e.target.value = value;
});

4. 힉의 법칙

너무 많은 옵션은 의사결정에 방해가 된다.

  • 의사결정 시간을 줄이는 데 반응 시간이 중요한 경우에는 선택지 개수를 최소화하라.
  • 정신적 노력을 줄이려면 복잡한 작업을 잘게 나눠라.
  • 추천 선택지를 강조해서 사용자의 부담을 줄여라.
  • 추상적이라고 느껴질 정도로 단순화하지 않도록 주의 하라

예시) 너무 많은 리모콘의 버튼들, 주료 사용하는 버튼만 남겨두고 나머지 버튼들은 모두 가렸다.

웹사이트에서도 아코디언 UI를 이용하여

사용 가능한 옵션을 모두 보여주지 않고 중요 메뉴들만 보여줄 수 있다.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Accordion UI</title>
<style>
.accordion {
width: 100%;
max-width: 600px;
margin: auto;
}

.accordion-item {
border-bottom: 1px solid #ccc;
}

.accordion-item input {
display: none;
}

.accordion-item label {
display: block;
padding: 15px;
background-color: #f1f1f1;
cursor: pointer;
font-weight: bold;
}

.accordion-item .content {
display: none;
padding: 15px;
background-color: #fff;
}

.accordion-item input:checked ~ .content {
display: block;
}
</style>
</head>
<body>
<div class="accordion">
<div class="accordion-item">
<input type="checkbox" id="accordion-item-1">
<label for="accordion-item-1">Section 1</label>
<div class="content">
<p>This is the content of section 1.</p>
</div>
</div>
<div class="accordion-item">
<input type="checkbox" id="accordion-item-2">
<label for="accordion-item-2">Section 2</label>
<div class="content">
<p>This is the content of section 2.</p>
</div>
</div>
<div class="accordion-item">
<input type="checkbox" id="accordion-item-3">
<label for="accordion-item-3">Section 3</label>
<div class="content">
<p>This is the content of section 3.</p>
</div>
</div>
</div>
</body>
</html>

5. 포스텔의 법칙

자신에게는 엄격하게, 남들에겐 너그럽게.

사용자가 아주 바보같은 실수를 할 수 있음을 인정하고 대비하자.

  • 사용자가 어떤 동작이나 입력을 하든, 공감하는 태도로 유연하고 관대하게 대처하라.
  • 인터페이스의 안정성과 접근성을 보장하되, 입력, 접근성, 성능 면에서 만반의 준비를 하자.
  • 다양한 가능성에 대해 잘 예측하고 대비할수록 디자인 회복탄력성은 좋아진다.
  • 사용자의 가변적인 입력을 수용해서 기계가 이해할 수 있는 방식으로 해석하라. 입력의 한계를 정의하고 각 사용자에게 명확한 피드백을 제공하라.

예시) 가장 간단하고 대표적인 예시로는 반응형 UI 대응이 있다.

반응형 UI를 도입함으로써 사용자가 하나의 디바이스를 사용하는 것이 아닌 다양한 디바이스를 통해 웹사이트에 접근하는 시나리오를 고려하고 대응할 수 있다.

또 다른 대표적인 예시로는 accessibility를 고려한 서비스들이 있다.

최근에 우리나라의 지하철 노선도가 모든 이들에게 더 보기 쉬울 수 있게 위치를 상단에서 하단으로 배치하였고, 글자크기를 키웠다고 한다.

사용자의 실수를 방지하기 위해 도움이 될 수 있는 코드 예시 중 하나는 인풋 태그에 accept attribute를 이용하여 원하는 확장자 형식의 파일만 입력을 받는 예시가 있다.

<!--.jpg, .jpeg, .png 형식의 파일만 받고 싶을 경우-->
<form>
<label for="imageUpload">이미지 파일을 선택하세요:</label>
<input type="file" id="imageUpload" name="imageUpload"
accept=".jpg, .jpeg, .png">
<button type="submit">업로드</button>
</form>

6. 피크엔드 법칙

가장 강렬한 경험(특히 부정적)과 가장 마지막 순간의 감정이 사용자의 판단에 중요하게 적용한다.

  • 사용자 여정 중 가장 강렬한 순간과 마지막 순간을 세심하게 신경 쓰자.
  • 제품이 사용자에게 가장 큰 도움을 주는 순간, 혹은 가장 중요하게 여겨지는 순간, 가장 큰 즐거움을 주는 순간 등을 알아내라.
  • 사람들은 긍정적인 순간보다 부정적인 순간을 더 생생하게 기억한다는 사실을 명심하자.

예시) Duolingo의 피크엔드 법칙 적용

출처: chatGPT

사용자가 버튼을 클릭하여 작업을 시작하고, 작업이 완료되었을 때 긍정적인 피드백을 제공하는 방식으로 피크엔드 법칙을 시뮬레이션하는 간단한 코드 예시

마지막에 모든 작업이 완료됐음을 알려줌으로써 사용자에게 더 나은 사용자 경험을 선사한다.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Peak-End Rule Example</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
}
.container {
text-align: center;
padding: 20px;
background: white;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div class="container">
<h1>Peak-End Rule Demo</h1>
<button id="startButton">Start Task</button>
<div id="peakMessage" class="hidden">
<p>Task is in progress... Please wait.</p>
</div>
<div id="endMessage" class="hidden">
<p>Task completed successfully!</p>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
document.addEventListener("DOMContentLoaded", function() {
const startButton = document.getElementById('startButton');
const peakMessage = document.getElementById('peakMessage');
const endMessage = document.getElementById('endMessage');

startButton.addEventListener('click', function() {
// Hide the start button and show the peak message
startButton.classList.add('hidden');
peakMessage.classList.remove('hidden');

// Simulate a task taking 3 seconds to complete
setTimeout(function() {
// Hide the peak message and show the end message
peakMessage.classList.add('hidden');
endMessage.classList.remove('hidden');
}, 3000);
});
});

7. 심미적 사용성 효과

사람들은 더 아름다운 것을 더 뛰어나게 느낀다.

  • 심미적으로 보기 좋은 디자인은 인간의 뇌에 긍정적 반응을 일으켜서 사용자에게 제품이나 서비스의 사용성이 뛰어나다는 생각이 들게 한다.
  • 제품이나 서비스의 디자인이 보기 좋으면, 사용자는 사용성 문제에 비교적 관대해진다.
  • 시각적으로 만족스러운 디자인은 사용성 문제를 가리고 사용성 테스트 중에 문제가 드러나는 것을 방해할 수 있다.

예시) 아래 사진에서 사람들은 왼쪽 휴대폰이 오른쪽 휴대폰보다 사용성이 더 높다고 평가했다.

개인 프로젝트 개발을 할 때 디자인까지 하기는 어렵다.

이때 깔끔하게 디자인된 컴포넌트들을 가져다 쓰기만 하면 되는 daisyUI 등을 이용하면 간단하게 심미적인 웹사이트를 만들 수 있다.

출처: https://daisyui.com/components/
<!--alert component-->

<div role="alert" class="alert alert-info">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
class="h-6 w-6 shrink-0 stroke-current">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<span>New software update available.</span>
</div>

8. 폰 레스토프 효과

아웃라이어가 가장 기억에 남는다.

  • 중요한 정보나 핵심 동작은 시각적으로 눈에 띄게 하라.
  • 시각적 요소를 강조할 때는 제한을 두어서, 각 요소 간 경쟁을 피하고 가장 중요한 항목이 광고로 오인되지 않게 하라.
  • 특정 요소를 강조할 때 색상에만 의존하면 색맹이나 저시력인 사용자가 배제된다는 사실을 유념하라.
  • 움직임을 활용해서 대비를 전달할 때는 움직임에 민감한 사용자를 주의 깊게 고려하라.

예시) 알림을 띄울 때 색상 대비를 이용하여 더 눈에 띄게 한다.

출처: https://daisyui.com/components/indicator/
<div class="indicator">
<span class="indicator-item badge badge-primary">new</span>
<div class="bg-base-300 grid h-32 w-32 place-items-center">content</div>
</div>

9. 테슬러의 법칙

시스템의 복잡성은 최대한 시스템이 처리하도록 하자.

  • 모든 프로세스에는 디자인 시 처리할 수 없는 기본적인 복잡성이 존재하므로, 시스템이나 사용자 중 한 쪽이 감당해야 한다.
  • 내재된 복잡성을 디자인과 개발 과정에서 처리하면 사용자의 부담을 최소로 줄일 수 있다.
  • 인간은 실생활에서 항상 합리적으로 행동하는 존재는 아니기에 이상적이며 합리적인 사용자만을 염두에 두고 제품이나 서비스를 만들어서는 안 된다는 점을 유념하라.
  • 사용자가 가이드에 접근할 수 있게 하고 제품을 사용 맥락에 맞게 디자인해서, 신규 활성 사용자들이 어떤 경로를 선택하든 제품의 도움을 받게 하라 (예: 유용한 정보를 담은 말풍선).

예시) 이메일을 보낼 때 수신자, 내용 자동 완성 등의 기능을 통해 사용자의 제품 사용 복잡성을 줄여준다.

폼 입력 시 복잡한 데이터 처리를 백엔드가 처리하고, 사용자는 간단한 인터페이스만 사용하는 코드 예시

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Form Example</title>
</head>
<body>
<h1>Calculate Age</h1>
<form id="birthdateForm">
<label for="birthdate">Enter your birthdate:</label>
<input type="date" id="birthdate" name="birthdate" required>
<button type="submit">Submit</button>
</form>
<p id="result"></p>

<script src="script.js"></script>
</body>
</html>
document.addEventListener("DOMContentLoaded", function() {
const form = document.getElementById('birthdateForm');
const result = document.getElementById('result');

form.addEventListener('submit', function(event) {
event.preventDefault();

const birthdate = new Date(document.getElementById('birthdate').value);
const age = calculateAge(birthdate);

result.textContent = `Your age is ${age} years.`;
});

function calculateAge(birthdate) {
const today = new Date();
let age = today.getFullYear() - birthdate.getFullYear();
const monthDifference = today.getMonth() - birthdate.getMonth();

if (monthDifference < 0 || (monthDifference === 0 && today.getDate() < birthdate.getDate())) {
age--;
}

return age;
}
});

10. 도허티 임계

사용자를 최대한 기다리게 하지 말자.

  • 사용자의 주의가 분산되는 것을 막는 동시에 생선성도 향상시키려면 시스템 피드백을 0.4초 이내에 제공하라.
  • 반응 시간을 개선하고 체감 대기 시간을 줄이려면 체감 성능을 활용하라.
  • 애니메이션은 로딩이나 프로세싱이 진행되는 동안 사람들의 시선을 끄는 방법이다.
  • 정확하지 않더라도 진행표시줄을 보여주면 사용자는 대기 시간에 좀 더 관대해진다.
  • 실제 작업이 훨씬 빨리 완료되더라도 의도적으로 작업 완료를 늦게 알리면 체감 가치를 높이고 신뢰를 형성하는 데 도움이 되기도 한다.

예시) 스켈레톤 UI, Axios file upload progress

Axios를 이용하여 파일을 서버에 업로드할 때 업로드 프로그레스를 알려주는

onUploadProgress를 이용하여 클라이언트에서 업로드 진행 상황을 알려주면 사용자 경험 향상에 도움을 줄 수 있다.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="viewport" content="width=device-width, initial-scale=1.0">
<title>File Upload with Progress</title>
</head>
<body>
<h1>File Upload with Progress</h1>
<form id="uploadForm">
<input type="file" id="fileInput" required>
<button type="submit">Upload</button>
</form>
<progress id="progressBar" value="0" max="100" style="width: 100%;"></progress>
<p id="status"></p>

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="script.js"></script>
</body>
</html>
document.addEventListener("DOMContentLoaded", function() {
const form = document.getElementById('uploadForm');
const fileInput = document.getElementById('fileInput');
const progressBar = document.getElementById('progressBar');
const statusText = document.getElementById('status');

form.addEventListener('submit', function(event) {
event.preventDefault();

const file = fileInput.files[0];
if (!file) return;

const formData = new FormData();
formData.append('file', file);

axios.post('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
onUploadProgress: function(progressEvent) {
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
progressBar.value = percentCompleted;
statusText.textContent = `Upload ${percentCompleted}% complete`;
}
})
.then(function(response) {
statusText.textContent = 'Upload complete!';
console.log(response.data);
})
.catch(function(error) {
statusText.textContent = 'Upload failed!';
console.error(error);
});
});
});

정리

사용자 경험 향상을 위해 디자이너뿐만 아니라 개발자역시 함께 노력해야한다.

이 책은 사용자에 대한 심리학 적인 접근을 통해 사용자 경험 향상을 위한 많은 인사이트를 제공해준다.

--

--

Namu CHO
Namu CHO

Written by Namu CHO

외노자 개발자 나무 🇸🇬

No responses yet