iframe을 사용할 때, 부모 요소에서 특정 height 값을 설정하면 iframe 내부에서 추가적인 세로 스크롤이 생긴다. 즉, 브라우저에 스크롤이 있는 것과 별개로, iframe 내부에서도 세로 스크롤이 하나 더 있는 상태가 된다.
내부 스크롤 없이 컨텐츠를 자연스럽게 표시하기 위해서는 iframe 내부의 컨텐츠 크기에 맞게 자동으로 height이 조정되도록 해야 한다.
iframe의 내부 컨텐츠의 height을 들고와 수정해주면 되었는데 내부 컨텐츠 height을 어떻게 가져올 수 있을지 알아보았다.
iframe은 아래처럼 내부 컨텐츠의 height을 직접 가져와 읽으면 CORS(Cross-Origin Resource Sharing) 정책에 의해 차단된다.
const element = document.getElementById('iframe');
console.log(element.contentWindow.document.body.scrollHeight);
발생된 에러
Uncaught SecurityError: Failed to read a named property 'document' from 'Window': Blocked a frame with origin "http://localhost:3001" from accessing a cross-origin frame.
CORS 에러를 해결하고 iframe 요소 정보를 가져오려면 postMessage()를 사용해야 한다.
window.postMessage() 메소드는 Window 객체 사이에서 안전하게 cross-origin 통신을 할 수 있도록 도와준다. 예를 들어, 부모 페이지와 iframe 내부 페이지가 서로 다른 도메인일 경우, 직접적으로 접근이 불가능하지만, postMessage()를 사용하면 데이터를 주고받을 수 있다.
아래처럼 postMessage를 사용해 height을 가져오면 정상적으로 동작한다. iframe 내부 컨텐츠 길이를 수용하는 크기로 세팅되어 내부 세로 스크롤 없이 컨텐츠를 볼 수 있다.
onMessage(event) {
const iframeHeight = JSON.parse(event.data.data).height;
const element = document.getElementById('iframe');
element.style.height = iframeHeight + 'px';
},
mounted() {
window.addEventListener('message', this.onMessage);
},
postMessage를 사용해야 할 때 주의해야 할 점은 보안이다.postMessage는 교차 출처 간에 데이터 교환이 가능하기 때문에 많은 위험에 노출될 수 있다. 그렇기에 postMessage를 사용할 땐 message를 전송한 출처를 꼭 검사하여 허용된 출처일 때만 처리되도록 해야 한다.
onMessage(event) {
if (event.origin !== '허용할 출처') return;
}
안전하게 iframe 요소를 읽어와 height을 내부 컨텐츠 요소에 따라 동적으로 설정해보았다. 아래 모습처럼 iframe 내부 스크롤 없이 잘 보이고 있다.
onMessage(event) {
if (event.origin !== process.env.IRIS_ORIGIN) return;
if (!event.srcElement) return;
const iframeHeight = JSON.parse(event.data.data).height;
const element = document.getElementById('iframe');
element.style.height = iframeHeight + 'px';
},
mounted() {
window.addEventListener('message', this.onMessage);
},