작동하는 교차 도메인 iframe 높이 자동 크기 조정기가 있습니까?


110

몇 가지 해결책을 시도했지만 성공하지 못했습니다. 따라하기 쉬운 튜토리얼이있는 솔루션이 있는지 궁금합니다.


2
실패한 해결책은 무엇입니까?
Yzmir Ramirez 2011

1
나는 이것을 시도했지만 기사에 명시된 것처럼 웹킷 브라우저에서 놀랍습니다 . css-tricks.com/cross-domain-iframe-resizing 다른 하나가 있었지만 URL을 기억할 수 없습니다.
J82 2011


이것이 귀하의 질문에 대답합니까? 콘텐츠에 맞게 iframe의 너비와 높이 조정

답변:


68

세 가지 대안이 있습니다.

1. iFrame-resizer 사용

콘텐츠에 맞게 iFrame 크기를 유지하기위한 간단한 라이브러리입니다. PostMessage 및 MutationObserver API를 사용하며 IE8-10에 대한 폴백을 사용합니다. 또한 콘텐츠 페이지에 포함 된 iFrame을 특정 크기로 요청하는 옵션이 있으며 작업이 완료되면 iFrame을 닫을 수도 있습니다.

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

2. Easy XDM 사용 (PostMessage + Flash 콤보)

Easy XDM은 여러 브라우저에서 서로 다른 창간에 도메인 간 통신을 가능하게하는 트릭 모음을 사용하며 iframe 크기 조정에 사용하는 예가 있습니다.

http://easyxdm.net/wp/2010/03/17/resize-iframe-based-on-content/

http://kinsey.no/blog/index.php/2010/02/19/resizing-iframes-using-easyxdm/

Easy XDM은 최신 브라우저에서는 PostMessage 를 사용 하고 이전 브라우저에서는 Flash 기반 솔루션 을 사용하여 작동 합니다.

Stackoverflow의이 스레드를 참조하십시오 (다른 항목도 있으며 일반적으로 묻는 질문입니다). 또한 Facebook은 유사한 접근 방식을 사용하는 것 같습니다 .

3. 서버를 통해 통신

또 다른 옵션은 iframe 높이를 서버로 보낸 다음 JSONP를 사용하여 상위 웹 페이지에서 해당 서버에서 폴링하는 것입니다 (또는 가능하면 긴 폴링을 사용하십시오).


1
이미 jQuery를 사용하는 경우 PostMessage를 들어, 당신은 또한 벤 독일어의 환상적인 PostMessage를 플러그인으로 볼 수도 있습니다 : benalman.com/projects/jquery-postmessage-plugin
rinogo

8
iFrame-resizer는 iframe 콘텐츠를 호스팅하는 서버에 액세스해야합니다. 따라서 제어하는 ​​도메인에만 사용할 수 있습니다.
Hokascha

좋은 캐치, @Hokascha. 이 프로젝트는 교차 도메인 iframe에 대한 지원을 주장하지만 문서를 읽으면 포함 된 도메인에 대한 서버 액세스가 여전히 필요함을 알 수 있습니다.
StockB

1
없음 이 "대안"의이 문제에 대한 실제 솔루션 없습니다. 질문자가 제어 할 수없는 웹 사이트에서 교차 도메인 iFrame의 iFrame 높이를 설정하려고합니다. 1. 서버 액세스가 필요합니다. 2. 나쁘다고 생각하는 소프트웨어가 필요합니다. Easy XDM은 10 년 전처럼 만들어졌습니다. 2019의 최신 버전 에는 플래시가 필요합니다 . 고맙게도 플래시는 죽었고 아무도 그것에 의존해서는 안됩니다. 3. 서버 액세스가 필요합니다.
redanimalwar

26

콘텐츠에 따라 iframe의 높이를 동적으로 설정하는 솔루션이 있습니다. 이것은 교차 도메인 콘텐츠에 대해 작동합니다. 이를 위해 따라야 할 몇 가지 단계가 있습니다.

  1. "abc.com/page"웹 페이지에 iframe을 추가했다고 가정합니다.

    <div> <iframe id="IframeId" src="http://xyz.pqr/contactpage" style="width:100%;" onload="setIframeHeight(this)"></iframe> </div>

  2. 다음으로 "abc.com/page"웹 페이지에서 "메시지"이벤트를 바인딩해야합니다.

window.addEventListener('message', function (event) {
//Here We have to check content of the message event  for safety purpose
//event data contains message sent from page added in iframe as shown in step 3
if (event.data.hasOwnProperty("FrameHeight")) {
        //Set height of the Iframe
        $("#IframeId").css("height", event.data.FrameHeight);        
    }
});

iframe로드시 "FrameHeight"메시지와 함께 iframe 창 콘텐츠에 메시지를 보내야합니다.

function setIframeHeight(ifrm) {
   var height = ifrm.contentWindow.postMessage("FrameHeight", "*");   
}
  1. "xyz.pqr / contactpage"의 iframe 아래에 추가 된 메인 페이지에서 모든 메시지가 "abc.com/page"의 상위 창에서 수신 될 Windows "메시지"이벤트를 바인딩해야합니다.
window.addEventListener('message', function (event) {

    // Need to check for safety as we are going to process only our messages
    // So Check whether event with data(which contains any object) contains our message here its "FrameHeight"
   if (event.data == "FrameHeight") {

        //event.source contains parent page window object 
        //which we are going to use to send message back to main page here "abc.com/page"

        //parentSourceWindow = event.source;

        //Calculate the maximum height of the page
        var body = document.body, html = document.documentElement;
        var height = Math.max(body.scrollHeight, body.offsetHeight,
            html.clientHeight, html.scrollHeight, html.offsetHeight);

       // Send height back to parent page "abc.com/page"
        event.source.postMessage({ "FrameHeight": height }, "*");       
    }
});

3
smooooothly 작동합니다. 감사합니다!
Alex Leonov

단순히 이것은 내가 찾을 수있는 가장 기술적 인 방법입니다. @sudhir, 감사합니다. :)
java

14

내가 한 것은 iframe 높이를 점진적으로 설정하는 동안 크기가 변경 될 때까지 iframe scrollWidth를 비교하는 것입니다. 그리고 그것은 나를 위해 잘 작동했습니다. 증분을 원하는대로 조정할 수 있습니다.

   <script type="text/javascript">
    function AdjustIFrame(id) {
        var frame = document.getElementById(id);
        var maxW = frame.scrollWidth;
        var minW = maxW;
        var FrameH = 100; //IFrame starting height
        frame.style.height = FrameH + "px"

        while (minW == maxW) {
            FrameH = FrameH + 100; //Increment
            frame.style.height = FrameH + "px";
            minW = frame.scrollWidth;
        }
    }

   </script>


<iframe id="RefFrame" onload="AdjustIFrame('RefFrame');" class="RefFrame"
    src="http://www.YourUrl.com"></iframe>

4
루프 수에 제한을 추가하고 싶을 것입니다. 그렇지 않으면 'while'이 무한 루프로 퇴화 될 수 있습니다.
Kevin Seifert 2013

1
이것은 내 페이지를 충돌시킵니다.
DDDD

좋은 간단한 해결책. 그러나 내 caes에서 크기 증가는 화면 크기로 제한됩니다.
Zeta

1

콘텐츠와 함께 iframe에 드롭되는 스크립트가 있습니다. 또한 iFrameResizer가 있는지 확인한 다음 (스크립트로 삽입) 크기 조정을 수행합니다.

아래에 간단한 예를 들어 보겠습니다.

// /js/embed-iframe-content.js

(function(){
    // Note the id, we need to set this correctly on the script tag responsible for
    // requesting this file.
    var me = document.getElementById('my-iframe-content-loader-script-tag');

    function loadIFrame() {
        var ifrm = document.createElement('iframe');
        ifrm.id = 'my-iframe-identifier';
        ifrm.setAttribute('src', 'http://www.google.com');
        ifrm.style.width = '100%';
        ifrm.style.border = 0;
        // we initially hide the iframe to avoid seeing the iframe resizing
        ifrm.style.opacity = 0;
        ifrm.onload = function () {
            // this will resize our iframe
            iFrameResize({ log: true }, '#my-iframe-identifier');
            // make our iframe visible
            ifrm.style.opacity = 1;
        };

        me.insertAdjacentElement('afterend', ifrm);
    }

    if (!window.iFrameResize) {
        // We first need to ensure we inject the js required to resize our iframe.

        var resizerScriptTag = document.createElement('script');
        resizerScriptTag.type = 'text/javascript';

        // IMPORTANT: insert the script tag before attaching the onload and setting the src.
        me.insertAdjacentElement('afterend', ifrm);

        // IMPORTANT: attach the onload before setting the src.
        resizerScriptTag.onload = loadIFrame;

        // This a CDN resource to get the iFrameResizer code.
        // NOTE: You must have the below "coupled" script hosted by the content that
        // is loaded within the iframe:
        // https://unpkg.com/iframe-resizer@3.5.14/js/iframeResizer.contentWindow.min.js
        resizerScriptTag.src = 'https://unpkg.com/iframe-resizer@3.5.14/js/iframeResizer.min.js';
    } else {
        // Cool, the iFrameResizer exists so we can just load our iframe.
        loadIFrame();
    }    
}())

그런 다음 다음과 같은 스크립트를 사용하여 iframe 콘텐츠를 다른 페이지 / 사이트 내 어디에나 삽입 할 수 있습니다.

<script
  id="my-iframe-content-loader-script-tag"
  type="text/javascript"
  src="/js/embed-iframe-content.js"
></script>

iframe 콘텐츠는 스크립트 태그를 배치 할 때마다 아래에 삽입됩니다.

이것이 누군가에게 도움이되기를 바랍니다. 👍


<script ... data-src="http://google.com">좋습니다. iframe src를 추가 하고 채웠습니다.
BananaAcid

현재 버전은iframe-resizer@4.2.10
BananaAcid

1
... 전체 사용 가능한 예제 코드로
BananaAcid

@BananaAcid-귀하의 codesandbox 링크가 더 이상 작동하지 않음
ctrlplusb

그것을 언급 해 주셔서 감사합니다. 링크는 codesandbox.io/s/remote-embed-ifrm-yz0xl 입니다. (참고 : codesandbox는 여러 페이지를 사용하는 "가짜"이며 중단 될 수 있습니다.
새로 고침

1

이 페이지의 간단한 해결책은 다음과 같습니다. http://lab.ohshiftlabs.com/iframesize/

작동 원리는 다음과 같습니다.

여기에 이미지 설명 입력

기본적으로 다른 도메인에서 페이지를 편집 할 수 있다면 쿠키에 높이를 절약하는 서버에 속한 다른 iframe 페이지를 배치 할 수 있습니다. 업데이트 될 때 간격 읽기 쿠키를 사용하여 iframe의 높이를 업데이트합니다. 그게 다입니다.

다운로드; http://lab.ohshiftlabs.com/iframesize/iframesizepost.zip

편집 : 2019 년 12 월

위의 솔루션은 기본적으로 iframe 내부의 다른 iframe을 사용합니다. 세 번째 iframe은 최상위 페이지 도메인에 속하며,이 페이지를 쿠키에 크기 값을 저장하는 쿼리 문자열로 호출하고 외부 페이지는이 쿼리를 일정 간격으로 확인합니다. 그러나 좋은 해결책이 아니므로 다음을 따라야합니다.

톱 페이지에서 :

window.addEventListener("message", (m)=>{iframeResizingFunction(m)});

여기 m.origin에서 그것이 어디에서 왔는지 확인할 수 있습니다 .

프레임 페이지에서 :

window.parent.postMessage({ width: 640, height:480 }, "*")

그러나 이것이 그렇게 안전한 방법이 아니라는 것을 잊지 마십시오. 보안을 유지하려면 원하는 값으로 * 값 (targetOrigin)을 업데이트하십시오. 문서를 따르십시오 : https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage


1
이 링크는 이제 죽었고 (404) 내용이 답변에 요약되지 않았습니다. :(
StockB

1
링크는 여전히 죽었습니다. 404
Arslan Ameer

0

iframe의 크기를 얻기 위해 PHP를 사용하는 웹 개발 용 또 다른 서버 측 솔루션을 찾았습니다.

첫 번째는 내부 함수를 통해 외부 호출에 서버 스크립트 PHP를 사용하는 것입니다 : ( file_get_contentswith but curl 및 dom).

function curl_get_file_contents($url,$proxyActivation=false) {
    global $proxy;
    $c = curl_init();
    curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($c, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7");
    curl_setopt($c, CURLOPT_REFERER, $url);
    curl_setopt($c, CURLOPT_URL, $url);
    curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);
    if($proxyActivation) {
        curl_setopt($c, CURLOPT_PROXY, $proxy);
    }
    $contents = curl_exec($c);
    curl_close($c);
    $dom = new DOMDocument();
    $dom->preserveWhiteSpace = false;
    @$dom->loadHTML($contents);
    $form = $dom->getElementsByTagName("body")->item(0);
    if ($contents) //si on a du contenu
        return $dom->saveHTML();
    else
        return FALSE;
}
$url = "http://www.google.com"; //Exernal url test to iframe
<html>
    <head>
    <script type="text/javascript">

    </script>
    <style type="text/css">
    #iframe_reserve {
        width: 560px;
        height: 228px
    }
    </style>
    </head>

    <body>
        <div id="iframe_reserve"><?php echo curl_get_file_contents($url); ?></div>

        <iframe id="myiframe" src="http://www.google.com" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"  style="overflow:none; width:100%; display:none"></iframe>

        <script type="text/javascript">
            window.onload = function(){
            document.getElementById("iframe_reserve").style.display = "block";
            var divHeight = document.getElementById("iframe_reserve").clientHeight;
            document.getElementById("iframe_reserve").style.display = "none";
            document.getElementById("myiframe").style.display = "block";
            document.getElementById("myiframe").style.height = divHeight;
            alert(divHeight);
            };
        </script>
    </body>
</html>

div ( iframe_reserve) 아래 에 간단한 사용하여 함수 호출에 의해 생성 된 html 을 표시해야합니다.echo curl_get_file_contents("location url iframe","activation proxy")

이 작업을 수행 한 후 자바 스크립트를 사용하여 본문 이벤트 함수를로드하면 콘텐츠 div ( iframe_reserve) 의 간단한 제어만으로 페이지 iframe의 높이를 가져옵니다.

그래서 divHeight = document.getElementById("iframe_reserve").clientHeight;div 컨테이너 ( iframe_reserve)를 마스킹 한 후 호출 할 외부 페이지의 높이를 가져 왔습니다 . 그 후에 우리는 좋은 높이로 iframe을로드합니다.


0

직장에서 작업하는 동안 (React 사용)이 문제가 발생했습니다. 기본적으로 데이터베이스의 문서 테이블에 저장 한 다음 문서 데이터 세트에있을 때 특정 상황에서 페이지에 삽입하는 일부 외부 html 콘텐츠가 있습니다.

따라서 외부 html을 포함 nn수있는 인라인이 주어지면 콘텐츠가 각각에 완전히로드되면 각 인라인의 iframe 크기를 자동으로 조정하는 시스템을 고안해야했습니다. 내 바퀴를 조금 돌린 후, 이렇게하게되었습니다.

  1. message보낸 사람 iframe에서 설정할 특정 키를 확인하는 React 앱의 색인에 이벤트 리스너를 설정합니다 .
  2. 실제로 iframe을 렌더링하는 구성 요소에서 외부 HTML을 삽입 한 후 iframe이 실행될 <script>때까지 대기 하는 태그를 추가합니다 window.onload. 실행되면 postMessageiframe ID, 계산 된 높이 등에 대한 정보와 함께 상위 창에 메시지를 보내는 데 사용 합니다.
  3. 오리진이 일치하고 인덱스 리스너에서 키가 충족 id되면 MessageEvent객체 에서 전달하는 iframe 의 DOM 을 가져옵니다.
  4. 일단 우리는 iframeiframe에서 전달 된 값에서 높이를 설정합니다 postMessage.
// index
if (window.postMessage) {
    window.addEventListener("message", (messageEvent) => {
        if (
            messageEvent.data.origin &&
            messageEvent.data.origin === "company-name-iframe"
        ) {
            const iframe = document.getElementById(messageEvent.data.id)
            // this is the only way to ensure that the height of the iframe container matches its body height
            iframe.style.height = `${messageEvent.data.height}px`
            // by default, the iframe will not expand to fill the width of its parent
            iframe.style.width = "100%"
            // the iframe should take precedence over all pointer events of its immediate parent
            // (you can still click around the iframe to segue, for example, but all content of the iframe
            // will act like it has been directly inserted into the DOM)
            iframe.style.pointerEvents = "all"
            // by default, iframes have an ugly web-1.0 border
            iframe.style.border = "none"
        }
    })
}
// in component that renders n iframes
<iframe
    id={`${props.id}-iframe`}
    src={(() => {
        const html = [`data:text/html,${encodeURIComponent(props.thirdLineData)}`]
        if (window.parent.postMessage) {
            html.push(
                `
                <script>
                window.onload = function(event) {
                    window.parent.postMessage(
                        {
                            height: document.body.scrollHeight,
                            id: "${props.id}-iframe",
                            origin: "company-name-iframe",
                        },
                        "${window.location.origin}"
                    );
                };
                </script>
                `
            )
        }

        return html.join("\n")
    })()}
    onLoad={(event) => {
        // if the browser does not enforce a cross-origin policy,
        // then just access the height directly instead
        try {
            const { target } = event
            const contentDocument = (
                target.contentDocument ||
                // Earlier versions of IE or IE8+ where !DOCTYPE is not specified
                target.contentWindow.document
            )
            if (contentDocument) {
                target.style.height = `${contentDocument.body.scrollHeight}px`
            }
        } catch (error) {
            const expectedError = (
                `Blocked a frame with origin "${window.location.origin}" ` +
                `from accessing a cross-origin frame.`
            )
            if (error.message !== expectedError) {
                /* eslint-disable no-console */
                console.err(
                    `An error (${error.message}) ocurred while trying to check to see ` +
                    "if the inner iframe is accessible or not depending " +
                    "on the browser cross-origin policy"
                )
            }
        }
    }}
/>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.