기호가 나타나도 글이 흔들리지 않게 만든 방법
목록 항목에 커서를 옮겼을 뿐인데 글자 전체가 옆으로 한 번 흔들린 적 있나요. 기호를 숨겼다 보여 주는 에디터라면 거의 다 겪는 일이에요.

목록을 편집하려고 캐럿을 옮기면 글자가 옆으로 밀렸어요. 캐럿이 빠지면 다시 돌아왔고요.
움직인 건 한 줄뿐이었지만, 문단 전체가 흔들리는 것처럼 보였어요. 작은 차이가 편집의 흐름을 계속 끊었어요.
원인은 마커의 폭이었어요.
평소 화면에는 동그란 글머리표가 보여요. 하지만 파일에는 하이픈과 공백이 저장돼 있어요. 캐럿이 마커에 닿으면 직접 고칠 수 있도록 원문을 보여 줘야 하죠.
문제는 두 모양이 차지하는 폭이 다르다는 거예요. 글머리표는 폭이 정해진 상자지만, 하이픈과 공백의 폭은 글꼴에 따라 달라져요. mote에서는 그 차이가 4.9 px이었어요. 원문이 나타날 때마다 뒤에 있는 글자가 그만큼 밀렸죠.
폭의 차이만큼 줄을 옮겨요
두 폭을 똑같이 만들지는 않았어요. 대신 차이를 상쇄해요.
마커가 원문으로 바뀌는 순간, 줄 전체를 폭의 차이만큼 반대 방향으로 옮겨요. 기호의 모양은 바뀌어도 본문이 시작하는 자리는 그대로예요.
파일은 건드리지 않아요. 글머리표는 하이픈 위에 덮어 그린 장식이고, 보정은 화면에서 줄을 그리는 위치만 바꿔요. 캐럿이 들어오고 나가도 저장된 내용은 그대로예요.
폭을 계산하는 기준도 하나로 합쳤어요. 전에는 마커를 그리는 곳과 줄을 보정하는 곳에 숫자가 따로 있었어요. 두 값의 작은 차이가 바로 그 4.9 px이었어요.
이제 두 곳 모두 같은 함수에 마커의 폭을 물어요. 기준이 하나라서 어긋날 일도 없어요.
다만 왼쪽 여백이 부족하면 보정하지 않아요. 줄을 옮겼다가 글자가 창 밖으로 잘릴 수 있기 때문이에요. 흔들림보다 글자가 사라지는 문제가 더 크니까요.
제목과 인용은 밀리도록 뒀어요
처음에는 제목과 인용에도 같은 방식을 적용했어요.
하지만 제목의 #과 인용의 >는 평소 화면에서 차지하는 폭이 0이에요. 본문을 고정하려면 기호를 왼쪽 여백으로 내보내야 했어요.
기술적으로는 잘 작동했어요. 글자는 움직이지 않았죠. 그런데 화면이 낯설었어요. 기호가 여백에 따로 떠 있는 모습이 자연스럽지 않았어요.
그래서 되돌렸어요. 지금은 제목과 인용의 기호가 나타나면 본문이 오른쪽으로 밀려요.

결국 마커마다 다른 답을 골랐어요.
글머리표와 할 일 체크박스처럼 화면에 상자가 있는 마커는 본문을 고정해요. 제목과 인용처럼 평소 폭이 0인 마커는 본문을 밀어요.
하나의 규칙보다 자연스러운 화면이 더 중요했어요.
기호는 꼭 필요할 때만 보여 줘요
흔들림을 줄이는 가장 좋은 방법은 기호가 바뀌는 순간 자체를 줄이는 거예요.
이제 글머리 기호는 캐럿이 기호 위에 있을 때만 원문으로 보여요. 캐럿이 공백을 지나 본문으로 이동하면 곧바로 글머리표로 돌아와요. 목록의 내용을 고치는 동안 하이픈을 계속 볼 필요가 없어요.
줄이 길어져 다음 줄로 넘어가도 정렬은 유지해요. 마커가 원문으로 보이는 동안에도 두 번째 줄은 첫 번째 줄의 본문 아래에서 시작해요.
클릭이 드래그로 잘못 인식되는 문제도 고쳤어요. 마커가 바뀌는 순간 포인터가 조금 흔들리면 글자가 선택되곤 했거든요. 이제 포인터가 8 px 넘게 움직여야 드래그로 판단해요.
눈 대신 숫자로 확인해요
이런 차이는 눈으로만 확인하기 어려워요. 잠깐 보면 괜찮아 보여도 오래 쓰면 산만하게 느껴져요.
그래서 실제 앱을 띄우는 테스트를 만들었어요. 캐럿을 마커 안팎으로 옮기고, 본문이 시작하는 x 좌표를 직접 비교해요. 두 값이 같아야 테스트를 통과해요.
글머리표와 할 일 체크박스, 중첩 목록을 모두 같은 방식으로 검사해요.
픽셀 하나짜리 어긋남은 버그로 신고되기 어려워요. 사용자는 무엇이 움직였는지 설명하기보다 “왠지 산만하다”고 느끼니까요.
그래서 이런 움직임은 사람이 아니라 숫자가 지켜야 해요.
조용한 화면은 아무 일도 일어나지 않는 화면이 아니에요. 필요한 변화가 눈에 거슬리지 않는 곳에서 일어나는 화면이에요.