모달은 중앙에 있었지만 사용자가 보는 화면과 달랐다

LearningX 대시보드는 LMS의 LTI 화면으로 열리면서 카탈로그에도 iframe으로 들어간다. 카탈로그에서는 대시보드 안의 팝업이 사용자가 보는 화면의 중앙에 나타나지 않았다. 자식 모달의 위치만 볼 문제가 아니라 부모가 iframe의 높이를 정하는 방식까지 함께 봐야 했다.

모달은 이미 position: fixed에 100vw·100vh 배경을 두고, flex로 가운데 정렬하고 있었다. iframe 안에서 이 기준은 자식 문서의 viewport다. 부모가 iframe을 긴 콘텐츠 전체 높이로 늘리면 자식이 계산하는 중앙과 부모 화면에서 지금 보이는 중앙이 어긋날 수 있다. 이것은 당시 높이 설정과 모달 CSS를 대조한 원인 해석이며, 모달 좌표를 측정한 기록은 아니다.

콘텐츠를 모두 펼치려던 높이 교환이 모달 기준도 바꿨다

카탈로그 연결은 자식 콘텐츠 크기를 부모에게 보내 iframe 높이를 맞추는 방식이었다. 자식은 root.clientHeight를 메시지로 보냈고, 부모는 받은 값을 iframe.style.height에 지정했다. iframe에는 scrolling="no"도 있었다.

반대 방향으로는 부모의 화면 높이를 viewportHeight 메시지에 담았다. 자식은 받은 높이를 CSS 변수 --vh에 넣고 타임라인 높이에 사용했다. 자식의 DOM 변화는 MutationObserver로 감지해 다시 높이를 보냈다. 부모 화면에 콘텐츠를 펼치려는 규칙과 부모 viewport를 자식에 전달하는 규칙이 함께 있었다.

이 구성을 유지한 채 모달만 부모 스크롤에 맞추려면 별도의 좌표 교환이 필요해진다. 그러나 실제 변경은 부모 스크롤 좌표를 전달하거나 모달의 top 값을 계산하지 않았다. 콘텐츠 전체 높이에 맞추던 iframe 구성을 제거하는 쪽을 선택했다.

자식 메시지를 지우고 부모가 가용 높이를 정했다

LearningX 쪽에서는 React의 높이 송신 effect와 Blade의 viewport 메시지 수신, 높이 송신, MutationObserver, --vh 설정을 제거했다. 카탈로그 쪽도 크기 수신과 viewport 송신을 함께 제거했다. 한쪽만 바꾸면 다른 쪽에 남아 있는 높이 규칙이 계속 적용될 수 있어 두 저장소를 같이 수정했다.

카탈로그는 헤더를 제외한 화면 높이를 iframe의 최소 높이로 지정한다. 아래는 높이 계산에 해당하는 실제 코드다.

function adjustIframeHeight() {
    const header = document.getElementById("header");
    const iframe = document.getElementById("fulliframe");
    if (header && iframe) {
        const headerHeight = header.offsetHeight;
        iframe.style.minHeight = `calc(100vh - ${headerHeight}px)`;
    }
}

document.addEventListener("DOMContentLoaded", adjustIframeHeight);
window.addEventListener("resize", adjustIframeHeight);

지정한 속성은 고정 height가 아닌 minHeight다. 동시에 scrolling="no"를 제거해 iframe 안에서 스크롤할 수 있게 하고, 대시보드 경로에서는 카탈로그 footer를 숨겼다. child 콘텐츠 길이를 부모 페이지의 iframe 높이로 계속 전파하던 연결을 끊은 것이다.

함께 바꾼 부모·자식의 책임
위치기존 규칙변경
LearningX 자식콘텐츠 크기 송신, 부모 높이 수신크기 메시지와 부모 높이 기반 CSS 제거
카탈로그 부모자식 크기로 iframe 높이 확장헤더를 뺀 화면 높이를 최소 높이로 지정
스크롤 구성iframe 스크롤 제한제한 제거, 대시보드의 부모 footer 숨김

모달은 기존 고정 위치 정렬을 유지한다. 모달 좌표를 보정하는 코드 대신 모달이 기준으로 삼는 자식 viewport의 구성을 바꿨다.

메시지 교환을 줄이는 대신 iframe 스크롤을 받아들였다

긴 대시보드를 부모 문서에 모두 펼치는 방식은 부모 스크롤 하나로 내용을 훑는 데 유리할 수 있다. 가용 화면 높이에 맞춘 iframe은 내부 스크롤을 갖는다. 부모 페이지와 자식 화면의 스크롤 관계가 달라지는 비용을 받아들인 선택이다. 키보드와 모바일에서의 이동이 모두 같아졌다고 주장할 근거는 없다.

높이 계산은 부모의 헤더 높이와 100vh에 의존한다. 헤더의 구성이나 모바일 브라우저의 화면 영역이 달라지는 조건도 남는다. 최소 높이를 지정했다는 사실만으로 모든 해상도에서 콘텐츠가 잘리지 않는다거나 모달이 정확한 같은 좌표에 표시된다고 보장할 수는 없다.

양쪽 적용 확인은 있고 브라우저별 좌표 기록은 없다

팝업 위치 개선은 카탈로그와 LearningX 양쪽에 적용하고 QA로 확인했다. 자동화된 모달 좌표 검사나 브라우저·해상도별 회귀 결과는 확인되지 않았다.

대시보드처럼 다른 화면 안에 들어가는 UI에서는 CSS 속성의 값뿐 아니라 그 속성이 어느 문서의 viewport를 읽는지 중요하다. 이 변경은 모달 자체를 복잡하게 만들기 전에 부모와 자식 사이의 높이 책임을 줄인 사례였다.