1️⃣ 어쩌다 버그를 마주했는가
드롭다운 모바일 이슈와 이어집니다.
이전 드롭다운 모바일 이슈를 해결하기 위해 전체적인 구조를 개선하였고, 드롭다운의 위치를 커스텀 할 수 있는
direction
기능을 추가하게 되었습니다. 따라서 현재 드롭다운 v2.0.0 부터는 드롭다운이 부모 요소의 children으로 들어가도록 구조를 변경하게 되었습니다. 이는 relative, absolute 사용을 통해 위치를 컨트롤 하기 위함입니다.

direction
은 총 12방향을 지원하며, 실제 left-bottom
값을 주었을 때의 예시입니다.현재 위 예시는 부모 요소(CircleButton)이 자식요소(Dropdown)보다 작기 때문에, 제가 예상한 설계대로 잘 동작하여 문제가 없다고 생각했습니다.
그러나 경빈님의 제보로 문제점을 발견하게 되었습니다.

현재 위 2개의 드롭다운은 전부
left-bottom
을 적용한 상태입니다. 그러나 부모 요소를 드롭다운보다 큰 크기를 가진 쉐도우 박스로 설정한 경우, 마치 left-top
이 적용된 것 처럼 보입니다.원인을 찾아본 결과, absolute의 기준점이 부모 요소의 윗 단이 되었기 때문에 해당 이슈가 발생한 것을 알 수 있었습니다.
// 기존 코드 case 'left-bottom': return css` right: 100%; top: 0; `; case 'left-top': return css` right: 100%; bottom: 0; `;

부모 요소(CircleButton)가 자식 요소(Dropdown)보다 작은 경우,
top: 0
을 주었을 때 우리가 생각하는 left-bottom
위치에 올 수 있습니다. 그러나 부모 요소(ShadowBox)가 자식 요소(Dropdown)보다 큰 경우,
top: 0
을 그대로 준다면 맨 위에 붙어버리기 때문에, left-top
처럼 보이게 됩니다. 오히려 이 경우엔 left-top
을 적용했을 때 left-bottom
처럼 보이는, 마치 반대로 적용되는 듯한 현상을 보였습니다.따라서 해당 코드는 드롭다운보다 부모 요소가 더 큰 경우, 부모 요소가 더 작은 경우 이렇게 2가지 케이스로 나누어 각 상황에 맞도록 값을 보정해줘야 했습니다.
💦어떤 시도를 해보았나
일단 부모 요소의 크기를 알아내려고 했으나, css 내부에서 부모 요소의 크기를 직접적으로 알 수 있는 방법은 없었습니다. 그렇기 때문에 처음에는 기존의 top, bottom, left, right 속성만으로 조절을 해보려고 했으나, 어떻게 해도 2가지 케이스를 모두 만족시킬 수 있는 방법은 찾을 수 없었습니다. 해당 이슈를 해결하기 위해서는 무조건 부모 요소의 크기 정보를 알아야 했습니다.
직접적으로는 크기를 알아낼 방법이 없지만 곰곰히 생각해본 결과,
% 단위
를 사용하면 해당 부모 요소의 크기를 간접적으로 판단할 수 있었기 때문에, %단위로 비교를 해야겠다고 생각했습니다. left-bottom
의 케이스로 예시를 들겠습니다.left-bottom
의 경우, Y축 기준점이 부모가 작을 때는 top: 0
이 되어야하고, 부모가 더 클때는 top: 100%
이 되야합니다. 이 때 부모 요소의 height는 100%
를 통해 간접적으로 판단할 수 있고, 자식 요소의 height는 드롭다운 props로 넘겨받은 height
값을 통해 직접적으로 정보를 알고 있습니다. 따라서 max()
함수를 통해 두 값을 비교하여, 더 큰 값으로 기준점을 잡습니다.top: max(100%, ${height});
부모 요소가 더 큰 경우
top: 100%
가 되고, 부모 요소가 더 작은 경우 top: ${height}
가 됩니다.
그 결과 두 케이스 모두 나름
left-bottom
에 해당하는 곳에 위치하게 되었습니다. 그러나 드롭다운의 height
만큼 위치를 더 벗어나게 되었습니다.따라서
transform: translateY()
함수를 통해 한번 더 보정을 해줍니다.transform: translateY(-${height});

드롭다운의
height
만큼 추가적으로 위로 이동시켜주니 부모 요소의 크기와 상관없이 두 케이스 모두 left-bottom
위치를 잘 찾아간 것을 확인할 수 있습니다.💼최종 해결 방법
case 'left-top': return css` right: 100%; bottom: max(100%, ${height}); transform: translateY(${height}); margin-right: 0.5rem; `; case 'left-bottom': return css` right: 100%; top: max(100%, ${height}); transform: translateY(-${height}); margin-right: 0.5rem; `;
case 'top-left': return css` bottom: 100%; right: max(100%, ${width}); transform: translateX(${width}); margin-bottom: 0.5rem; `; case 'top-right': return css` bottom: 100%; left: max(100%, ${width}); transform: translateX(-${width}); margin-bottom: 0.5rem; `;
left-top
left-bottom
right-top
right-bottom
의 경우 드롭다운의 height를 이용해 위치를 보정합니다.top-left
top-right
bottom-left
bottom-right
의 경우 드롭다운의 width를 이용해 위치를 보정합니다.