마우스를 따라 기우는 화면에서 호버가 스스로 풀렸다
메인 화면은 커서를 따라 기운다. 마우스를 왼쪽으로 옮기면 화면 전체가 왼쪽으로 살짝 기울고, 오른쪽으로 옮기면 반대로 기운다. 그 위에 가운데 글자가 있고, 마우스를 올리면 다른 나라 말로 바뀌게 만들었다.
올려도 안 바뀌었다. 가끔 바뀌다가 도로 돌아왔다.
결론부터 쓰면, 히트 테스트 문제가 아니었다. 마우스를 움직이는 행위 자체가 대상을 커서 밑에서 밀어내고 있었다.
증상
글자 위에 커서를 놓는다. 아무 일도 안 일어난다. 조금 움직이면 잠깐 바뀌다가 원래대로 돌아온다.
아니었던 것
먼저 커서가 글자를 못 짚는 줄 알았다. 화면에 3D 변환이 잔뜩 걸려 있어서 그럴 만했다.
elementFromPoint 로 글자 한가운데를 찍어봤다.
wm-word → wordmark → tilt → scene
정확히 잡혔다. 히트 테스트는 멀쩡했다.
그럼 셀렉터인가. 호버 중 상태를 페이지 안에서 기록하게 심어놓고 다시 올려봤다. :hover 도 매칭됐고 :has() 도 매칭됐다. 그런데 계산된 스타일은 안 바뀌어 있었다.
여기서 한참 헤맸다. 셀렉터가 맞는데 효과가 없다는 게 말이 안 됐다.
원인
기록을 두 시점에 남기게 했다. 마우스를 올린 직후와 1.2초 뒤. 그 사이에 나는 마우스를 건드리지 않았다.
enter+0 :hover 매칭 true
enter+1200 :hover 매칭 false
커서는 그대로인데 호버가 풀렸다. 커서가 떠난 게 아니라 대상이 커서 밑에서 빠져나간 것이다.
고리는 이렇다.
- 마우스가 움직인다
- 그 좌표로 기울기 값을 갱신한다
- 화면 전체가 회전한다
- 그 위에 얹힌 글자가 이동한다
- 커서가 글자 밖으로 나간다
- 호버가 풀린다
게다가 기울기 전환에 0.65초를 줬다. 마우스를 멈춰도 화면은 0.65초 동안 계속 움직인다. 그래서 가만히 두고만 있어도 호버가 저절로 풀렸다.
호버 효과에는 0.4초짜리 전환이 걸려 있었다. 전환이 끝나기 전에 매번 취소되니 화면에는 아무 변화도 안 나타났다.
고친 방법
보이는 글자와 판정하는 영역을 분리했다.
글자는 그대로 기울기 판 안에 둔다. 화면과 같이 기울어야 하니까. 대신 호버 판정만 담당하는 상자를 기울기 판 밖에 하나 만들어 같은 자리에 겹쳐 놨다. 이 상자는 안 움직인다.
.scene:has(.wm-hit:hover) .wm-word { opacity: 0; }
확인해보니 기울기를 세 가지로 바꿔도 판정 상자의 위치는 한 픽셀도 안 변했다.
정면 [527, 399, 384, 112]
+0.5,+0.5 [527, 399, 384, 112]
-0.5,-0.5 [527, 399, 384, 112]
글자는 여전히 기울고, 판정만 고정됐다. 오브젝트 네 개의 클릭 판정도 그대로다. DOM 상 판정 상자가 오브젝트보다 앞이라 뒤엣것을 가로채지도 않는다.
남은 것
판정 상자를 글자보다 넉넉하게 잡았다. 글자가 303×96 인데 상자는 384×112 다. 가장자리에서 뚝 끊기지 않게 하려고 그랬는데, 이 여유가 적당한지는 재본 게 아니라 감이다.
그리고 이 구조는 결국 나중에 걷어냈다. 호버 대신 좌상단 버튼을 누르면 바뀌는 쪽으로 바꿨기 때문이다. 그래도 원인은 남겨둘 값어치가 있다고 본다.
입력이 화면을 움직이는 인터랙션에서는 입력 대상도 같이 움직인다. 움직이는 것 위에 판정을 얹으면 안 된다.