[javascript] 종횡비 가정없이 iframe을 반응 적으로 만드는 방법은 무엇입니까?

종횡비를 가정하지 않고 iframe을 반응 형으로 만드는 방법은 무엇입니까? 예를 들어, 컨텐츠는 임의의 폭 또는 높이를 가질 수 있으며, 이는 렌더링 전에 알려지지 않았다.

Javascript를 사용할 수 있습니다.

예:

<div id="iframe-container">
    <iframe/>
</div>

iframe-container내용물이 여분의 공간없이 내부에 거의 들어 가지 않도록 크기를 조정하십시오. 즉, 내용을위한 공간이 충분하므로 스크롤하지 않고 표시 할 수 있지만 초과 공간은 없습니다. 컨테이너는 iframe을 완벽하게 감싸줍니다.

컨텐츠의 종횡비가 iframe 가정이 확인 응답하는 방법을 16 : 9. 그러나이 질문에서 종횡비는 가변적입니다.



답변

크기를 얻기 위해 Javascript를 사용하여 다른 원점 iFrame과 상호 작용할 수 없습니다. 그것을 할 수있는 유일한 방법은 사용하는 것입니다 window.postMessagetargetOrigin도메인으로 설정하거나 wildchar *iframe이 소스에서. 다른 원본 사이트의 내용을 프록시하고 사용할 수 srcdoc있지만 이것은 으로 간주 되며 SPA 및 기타 여러 동적 페이지에서는 작동하지 않습니다.

동일한 원점 iFrame 크기

두 개의 동일한 원점 iFrame, 즉 짧은 높이와 고정 너비 중 하나가 있다고 가정하십시오.

<!-- iframe-short.html -->
<head>
  <style type="text/css">
    html, body { margin: 0 }
    body {
      width: 300px;
    }
  </style>
</head>
<body>
  <div>This is an iFrame</div>
  <span id="val">(val)</span>
</body>

긴 높이의 iFrame :

<!-- iframe-long.html -->
<head>
  <style type="text/css">
    html, body { margin: 0 }
    #expander {
      height: 1200px; 
    }
  </style>
</head>
<body>
  <div>This is a long height iFrame Start</div>
  <span id="val">(val)</span>
  <div id="expander"></div>
  <div>This is a long height iFrame End</div>
  <span id="val">(val)</span>
</body>

우리는 다음을 load사용 iframe.contentWindow.document하여 부모 창에 보낼 이벤트를 사용하여 iFrame 크기를 얻을 수 있습니다 postMessage.

<div>
  <iframe id="iframe-local" src="iframe-short.html"></iframe>
</div>
<div>
  <iframe id="iframe-long" src="iframe-long.html"></iframe>
</div>

<script>

function iframeLoad() {
  window.top.postMessage({
    iframeWidth: this.contentWindow.document.body.scrollWidth,
    iframeHeight: this.contentWindow.document.body.scrollHeight,
    params: {
      id: this.getAttribute('id')
    }
  });
}

window.addEventListener('message', ({
  data: {
    iframeWidth,
    iframeHeight,
    params: {
      id
    } = {}
  }
}) => {
  // We add 6 pixels because we have "border-width: 3px" for all the iframes

  if (iframeWidth) {
    document.getElementById(id).style.width = `${iframeWidth + 6}px`;
  }

  if (iframeHeight) {
    document.getElementById(id).style.height = `${iframeHeight + 6}px`;
  }

}, false);

document.getElementById('iframe-local').addEventListener('load', iframeLoad);
document.getElementById('iframe-long').addEventListener('load', iframeLoad);

</script>

두 iFrame 모두에 대해 적절한 너비와 높이를 얻게됩니다. 여기에서 온라인으로 확인하고 여기 에서 스크린 샷을 볼 수 있습니다 .

다른 출처 iFrame 크기 ( 권장되지 않음 )

여기에 설명 된 방법은 해킹 이므로 절대적으로 필요하고 다른 방법이없는 경우 사용해야합니다. 대부분의 동적 생성 페이지 및 SPA 에서는 작동하지 않습니다 . 이 메소드 cors-anywherehttps://cors-anywhere.herokuapp.com CORS 정책을 우회하기 위해 프록시를 사용하여 페이지 HTML 소스 코드를 페치합니다 ( 간단한 CORS 프록시 서버를 작성하는 쉬운 방법이며 온라인 데모가 있습니다 ). 그러면 해당 HTML에 JS 코드를 삽입 postMessage하여 크기를 전송합니다. 부모 문서로 iFrame. 심지어 iFrame resize( iFrame 과 결합width: 100% ) 이벤트를 처리 하고 iFrame 크기를 부모에게 다시 게시합니다.

patchIframeHtml:

iFrame HTML 코드를 패치하고 postMessageiFrame 크기를 부모에게 계속 전송하는 데 사용할 사용자 정의 Javascript를 삽입하는 기능 load입니다 resize. origin매개 변수에 대한 값이있는 경우 HTML <base/>요소가 해당 오리진 URL을 사용하여 헤드 앞에 추가되므로 /some/resource/file.extiFrame 내의 오리진 URL 에서 HTML URI와 같은 HTML을 올바르게 가져옵니다.

function patchIframeHtml(html, origin, params = {}) {
  // Create a DOM parser
  const parser = new DOMParser();

  // Create a document parsing the HTML as "text/html"
  const doc = parser.parseFromString(html, 'text/html');

  // Create the script element that will be injected to the iFrame
  const script = doc.createElement('script');

  // Set the script code
  script.textContent = `
    window.addEventListener('load', () => {
      // Set iFrame document "height: auto" and "overlow-y: auto",
      // so to get auto height. We set "overlow-y: auto" for demontration
      // and in usage it should be "overlow-y: hidden"
      document.body.style.height = 'auto';
      document.body.style.overflowY = 'auto';

      poseResizeMessage();
    });

    window.addEventListener('resize', poseResizeMessage);

    function poseResizeMessage() {
      window.top.postMessage({
        // iframeWidth: document.body.scrollWidth,
        iframeHeight: document.body.scrollHeight,
        // pass the params as encoded URI JSON string
        // and decode them back inside iFrame
        params: JSON.parse(decodeURIComponent('${encodeURIComponent(JSON.stringify(params))}'))
      }, '*');
    }
  `;

  // Append the custom script element to the iFrame body
  doc.body.appendChild(script);

  // If we have an origin URL,
  // create a base tag using that origin
  // and prepend it to the head
  if (origin) {
    const base = doc.createElement('base');
    base.setAttribute('href', origin);

    doc.head.prepend(base);
  }

  // Return the document altered HTML that contains the injected script
  return doc.documentElement.outerHTML;
}

getIframeHtml:

useProxyparam이 설정된 경우 프록시를 사용하여 CORS를 무시하고 페이지 HTML을 가져 오는 기능 입니다. postMessage크기 데이터를 전송할 때 전달 될 추가 매개 변수가있을 수 있습니다 .

function getIframeHtml(url, useProxy = false, params = {}) {
  return new Promise(resolve => {
    const xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function() {
      if (xhr.readyState == XMLHttpRequest.DONE) {
        // If we use a proxy,
        // set the origin so it will be placed on a base tag inside iFrame head
        let origin = useProxy && (new URL(url)).origin;

        const patchedHtml = patchIframeHtml(xhr.responseText, origin, params);
        resolve(patchedHtml);
      }
    }

    // Use cors-anywhere proxy if useProxy is set
    xhr.open('GET', useProxy ? `https://cors-anywhere.herokuapp.com/${url}` : url, true);
    xhr.send();
  });
}

메시지 이벤트 핸들러 함수는 “Same origin iFrame size”와 정확히 동일 합니다.

이제 사용자 정의 JS 코드를 삽입하여 iFrame 내에 교차 도메인을로드 할 수 있습니다.

<!-- It's important that the iFrame must have a 100% width 
     for the resize event to work -->
<iframe id="iframe-cross" style="width: 100%"></iframe>

<script>
window.addEventListener('DOMContentLoaded', async () => {
  const crossDomainHtml = await getIframeHtml(
    'https://en.wikipedia.org/wiki/HTML', true /* useProxy */, { id: 'iframe-cross' }
  );

  // We use srcdoc attribute to set the iFrame HTML instead of a src URL
  document.getElementById('iframe-cross').setAttribute('srcdoc', crossDomainHtml);
});
</script>

그리고 overflow-y: autoiFrame 바디를 사용하더라도 세로 스크롤없이 iFrame의 내용을 전체 높이 로 조정할 수 있습니다 (resize에서 스크롤 막대가 깜박이지 않아야 함overflow-y: hidden ).

여기에서 온라인으로 확인할 수 있습니다 .

다시 말하지만 이것은 해킹 이므로 피해야합니다 . 우리는 할 수 없습니다 액세스 크로스 원산지 iframe이 문서 나 물건의 종류를 주입.


답변

iframe에서 컨텐츠의 크기를 계산할 때 많은 문제가 발생합니다. 주로 CSS를 사용하면 컨텐츠 크기를 측정하는 방법을 깨뜨릴 수있는 작업이 가능하기 때문입니다.

나는이 모든 것들을 돌보고 교차 도메인에서 작동하는 라이브러리를 작성했습니다. 도움이 될 수 있습니다.

https://github.com/davidjbradshaw/iframe-resizer


답변

내 솔루션은 GitHubJSFiddle 입니다.

종횡비를 가정하지 않고 반응 형 iframe 솔루션을 제시합니다.

목표는 필요할 때, 즉 창의 크기를 조정할 때 iframe의 크기를 조정하는 것입니다. 이것은 새로운 윈도우 크기를 얻고 결과적으로 iframe의 크기를 조정하기 위해 JavaScript로 수행됩니다.

NB : 페이지를로드 한 후 창 자체의 크기가 조정되지 않으므로 페이지가로드 된 후 크기 조정 기능을 호출하는 것을 잊지 마십시오.

코드

index.html

<!DOCTYPE html>
<!-- Onyr for StackOverflow -->

<html>

<head> 
    <meta http-equiv="content-type" content="text/html;charset=utf-8" />
    <title>Responsive Iframe</title>
    <link rel="stylesheet" type="text/css" href="./style.css">
</head>

<body id="page_body">
    <h1>Responsive iframe</h1>

    <div id="video_wrapper">
        <iframe id="iframe" src="https://fr.wikipedia.org/wiki/Main_Page"></iframe>
    </div>

    <p> 
        Presenting a solution for responsive iframe without aspect
        ratio assumption.<br><br>
    </p>

    <script src="./main.js"></script>
</body>

</html>

style.css

html {
    height: 100%;
    max-height: 1000px;
}

body {
    background-color: #44474a;
    color: white;
    margin: 0;
    padding: 0;
}

#videoWrapper {
    position: relative;
    padding-top: 25px;
    padding-bottom: 100px;
    height: 0;
    margin: 10;
}
#iframe {
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

main.js

let videoWrapper = document.getElementById("video_wrapper");

let w;
let h;
let bodyWidth;
let bodyHeight;

// get window size and resize the iframe
function resizeIframeWrapper() {
    w = window.innerWidth;
    h = window.innerHeight;

    videoWrapper.style["width"] = `${w}px`;
    videoWrapper.style["height"] = `${h - 200}px`;
}

// call the resize function when windows is resized and after load
window.onload = resizeIframeWrapper;
window.onresize = resizeIframeWrapper;

나는 이것에 약간의 시간을 보냈다. 나는 당신이 그것을 즐기기를 바랍니다 =)

편집
아마도 가장 일반적인 솔루션 일 것입니다. 그러나 매우 작게 만들면 iframe에 적절한 크기가 부여되지 않습니다. 이것은 사용중인 iframe에만 해당됩니다. iframe의 코드가 없으면 코드가 iframe에서 어떤 크기를 올바르게 표시하는지 알 수있는 방법이 없기 때문에이 현상에 대한 적절한 답변을 코딩 할 수 없습니다.

@Christos Lytras가 제시 한 것과 같은 일부 해킹 만이 트릭을 만들 수 있지만 모든 iframe에서 작동하지는 않습니다. 특정 상황에서.


답변

CSS 프레임 속성을 설정하여 너비와 높이를 Iframe 컨테이너에 설정하십시오.

.iframe-container{
     width:100%;
     min-height:600px;
     max-height:100vh;
}

.iframe-container iframe{
     width:100%;
     height:100%;
     object-fit:contain;
}


답변