댓글 모듈 iframe 사용기

댓글 모듈 iframe 사용기

웹 페이지 어디든 쉽고 간편하게 추가하는 댓글 모듈 서비스 "다라쓰"를 만들면서 겪었던 많은 어려움 중 iframe을 사용하면서 마주했던 이슈들에 대해 회고하는 시간을 가져보고자 한다.

다라쓰에서 iframe을 사용한 이유는 간단하다. HTML에 스크립트 코드를 붙여넣는 것만으로 기존 페이지에 영향을 전혀 주지 않으면서 댓글 모듈 서비스를 사용할 수 있어야 하기 때문이다.

iframe은 inline frame의 약자로 iframe을 이용하면 해당 웹 페이지 안에 어떠한 제한 없이 또 다른 하나의 웹 페이지를 삽입할 수 있다. iframe은 부모 document 안에 새로운 document가 생성된다. 그리고 이 둘은 서로 독립적이다. 부모에 적용된 스타일을 자식은 적용 받지 않는다. 따라서 모듈 서비스처럼 기존 서비스에 영향을 주거나 받지 않아야하는 경우에 사용하기 적합하다.

만약 iframe을 사용하지 않고 부모 요소에 바로 element를 추가하는 식으로 코드를 작성한다면 어떤 일이 일어날까?

바로, 우리가 작성한 스타일이 제대로 그려질 것이라는 보장할 수 없게 된다. 부모 요소에서 우선 순위가 높은 스타일이 우리가 작성한 스타일을 덮어씌울 수도 있다. 무엇보다도 부모 요소에서 어떤 영역에 댓글 모듈이 그려질지 알 수가 없기 때문에 반응형으로 코드를 짤 수가 없다.

예를 들어, 부모 요소의 뷰포트가 1920px이지만 실제로 댓글 모듈은 화면의 가운데 1000px에 해당하는 영역으로 그려진다고 가정해보자. 댓글 모듈을 iframe으로 만들지 않으면 부모 요소의 뷰포트를 기준으로 폰트 사이즈가 결정되고 우리는 댓글 모듈이 실제로 그려지는 영역은 1000px이지만 1920px에 맞게 화면을 그리게 될 것이다. 따라서 댓글 모듈은 부자연스럽게 크게 그려질 것이다. 하지만 iframe을 사용하면 iframe이 그려지는 영역이 곧 iframe의 뷰포트 사이즈가 되기 때문에 반응형으로 만들기가 수월해진다.

이제 iframe을 사용하면서 겪었던 문제점과 그것들을 어떻게 해결해나갔는지에 대해 알아보자.

1. iframe 높이 동적으로 변경하기

iframe은 height 속성을 사용하여 iframe의 높이를 설정할 수 있다. 높이를 설정해주지 않으면 컨텐츠의 높이에 맞게 동적으로 높이가 설정될 것 같지만 그렇지 않다. height을 설정해놓지 않는 경우, 크롬 기준 높이는 자동으로 150px로 설정된다. 컨텐츠의 높이가 150px이 넘어가게 되면 스크롤이 등장하게 되고 굉장히 부자연스러워진다. 때문에 iframe의 높이를 컨텐츠의 높이로 일치 시켜줘야한다. 하지만 댓글 모듈처럼 댓글의 추가 혹은 삭제로 인해 컨텐츠의 높이가 계속해서 달라진다면 어떻게 해야할까?

댓글이 0개인 경우가 가장 기본값이라고 판단하여 iframe의 height 을 596px로 고정하면 처음에는 다음과 같이 자연스럽게 iframe이 출력된다.

하지만 댓글이 추가되어 컨텐츠의 높이가 변경되면 다음과 같이 스크롤이 생기게 된다. 다라쓰를 블로그에 달고자 하는 사용자의 입장에서 댓글을 아래와 같이 스크롤링으로 확인해야한다면 사용하고 싶지 않을 것이다. 이는 치명적인 결함이다.

결국, 컨텐츠의 높이가 변경될 때 마다 iframe의 height도 동적으로 변경되야한다. 이를 위해서는 iframe과 부모 window가 서로 통신을 해야한다. 이를 위해 window.postMessage를 사용했다.

// deploy-script (부모 window = iframe을 사용하는 쪽) window.addEventListener("message", ({ data: { type, data } }) => { if (!type) return; if (type === POST_MESSAGE_TYPE.SCROLL_HEIGHT) { resizeElementHeight({ element: $replyModuleIframe, height: data }); return; } }); // reply-module (content window = iframe에 그려지는 페이지) // 부모 window에 컨텐츠의 높이를 보내는 함수 const postScrollHeightToParentWindow = () => { window.parent.postMessage( { type: POST_MESSAGE_TYPE.SCROLL_HEIGHT, data: document.querySelector("#root")?.scrollHeight }, "*" ); }; // 반응형으로 html font size가 바뀌었을 때 높이를 iframe에 메세지 형태로 전달 const onResize = () => { let throttle: NodeJS.Timeout | null; const runThrottle = () => { if (!throttle) { throttle = setTimeout(() => { throttle = null; postScrollHeightToParentWindow(); }, 600); } }; return runThrottle; }; window.addEventListener("resize", onResize()); // 댓글에 따라 iframe 높이 변경 useEffect(() => { postScrollHeightToParentWindow(); }, [comments]);

reply module은 iframe에 그려지는 페이지이다. reply module의 높이가 변할 때마다 부모 window에 postMessage로 변경된 높이를 보내고 있다. deploy-script는 부모 window로 iframe을 사용하는 쪽이다. deploy-script는 높이를 변경하는 message 이벤트가 발생할 때 iframe의 height을 변경시킨다. 이를 통해 댓글의 추가나 삭제 그리고 iframe의 뷰포트 변경에 따른 반응형 페이지의 높이도 동적으로 변경할 수 있게 된다.

스크롤 없이 댓글 모듈이 정상적으로 나오는 모습

from http://yung-developer.tistory.com/108 by ccl(A) rewrite - 2021-08-22 14:26:25