Змінення розміру iframe на основі вмісту


498

Я працюю над додатком iGoogle. Вміст інших програм (на інших доменах) відображається за допомогою iframes.

Як змінити розмір iframe відповідно до висоти вмісту iframe?

Я намагався розшифрувати JavaScript, який використовує Google, але він заплутаний, і пошук в Інтернеті досі був безрезультатним.

Оновлення. Зауважте, що вміст завантажується з інших доменів, тому застосовується та ж політика щодо оригіналу .

Відповіді:


584

У нас виникли подібні проблеми, але дещо зворотно до вашої ситуації - ми надавали контент із рамками на веб-сайтах інших доменів, тому та сама політика щодо походження також була проблемою. Після багатьох годин, котрих гуляли в Google, ми врешті-решт знайшли (дещо ..) дієве рішення, яке ви, можливо, зможете адаптувати під свої потреби.

Існує однакова політика щодо оригіналу, але вона вимагає змін як у вкладеному кадрі, так і на сторінці обрамлення, тому якщо у вас немає можливості вимагати змін з обох сторін, цей метод не буде дуже корисним для вас, Я боюся.

Існує химерність веб-переглядача, яка дозволяє нам знімати ту саму політику походження - javascript може спілкуватися як зі сторінками на власному домені, так і зі сторінками, на яких є рамкова рамка, але ніколи зі сторінками, на яких вона створена, наприклад, якщо у вас є:

 www.foo.com/home.html, which iframes
 |-> www.bar.net/framed.html, which iframes
     |-> www.foo.com/helper.html

тоді home.htmlможна спілкуватися з framed.html(iframed) та helper.html(той же домен).

 Communication options for each page:
 +-------------------------+-----------+-------------+-------------+
 |                         | home.html | framed.html | helper.html |
 +-------------------------+-----------+-------------+-------------+
 | www.foo.com/home.html   |    N/A    |     YES     |     YES     |
 | www.bar.net/framed.html |    NO     |     N/A     |     YES     |
 | www.foo.com/helper.html |    YES    |     YES     |     N/A     |
 +-------------------------+-----------+-------------+-------------+

framed.htmlможе надсилати повідомлення до helper.html(iframed), але ні home.html (дитина не може спілкуватися між доменним з домом ).

Ключовим тут є те, що helper.htmlможна отримувати повідомлення framed.html, а також можна спілкуватися з ними home.html.

Отже, по суті, при framed.htmlнавантаженні він працює на власній висоті, повідомляє helper.html, на що передає повідомлення, на home.htmlяке потім може змінити розмір iframe, в якому framed.htmlсидить.

Найпростіший спосіб, яким ми виявили, щоб передавати повідомлення від framed.htmlдо, helper.htmlбув через аргумент URL. Для цього framed.htmlмає iframe з src=''вказаним. Під час onloadпожежі він оцінює власну висоту і встановлює src рамки iframe в цій точціhelper.html?height=N

Тут є пояснення, як фейсбук поводиться з цим, що може бути дещо чіткіше, ніж моє вище!


Код

У www.foo.com/home.htmlцьому випадку необхідний наступний код javascript (його можна завантажити з .js-файлу на будь-якому домені, до речі ..):

<script>
  // Resize iframe to full height
  function resizeIframe(height)
  {
    // "+60" is a general rule of thumb to allow for differences in
    // IE & and FF height reporting, can be adjusted as required..
    document.getElementById('frame_name_here').height = parseInt(height)+60;
  }
</script>
<iframe id='frame_name_here' src='http://www.bar.net/framed.html'></iframe>

В www.bar.net/framed.html:

<body onload="iframeResizePipe()">
<iframe id="helpframe" src='' height='0' width='0' frameborder='0'></iframe>

<script type="text/javascript">
  function iframeResizePipe()
  {
     // What's the page height?
     var height = document.body.scrollHeight;

     // Going to 'pipe' the data to the parent through the helpframe..
     var pipe = document.getElementById('helpframe');

     // Cachebuster a precaution here to stop browser caching interfering
     pipe.src = 'http://www.foo.com/helper.html?height='+height+'&cacheb='+Math.random();

  }
</script>

Зміст www.foo.com/helper.html:

<html> 
<!-- 
This page is on the same domain as the parent, so can
communicate with it to order the iframe window resizing
to fit the content 
--> 
  <body onload="parentIframeResize()"> 
    <script> 
      // Tell the parent iframe what height the iframe needs to be
      function parentIframeResize()
      {
         var height = getParam('height');
         // This works as our parent's parent is on our domain..
         parent.parent.resizeIframe(height);
      }

      // Helper function, parse param from request string
      function getParam( name )
      {
        name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
        var regexS = "[\\?&]"+name+"=([^&#]*)";
        var regex = new RegExp( regexS );
        var results = regex.exec( window.location.href );
        if( results == null )
          return "";
        else
          return results[1];
      }
    </script> 
  </body> 
</html>

7
справді сповнений прозріння. Мені було цікаво, чому на igoogle.com був файл helper.html! Дякую
IEnumerator

9
Дивовижне, дякую! Я зробив кілька доповнень: Використовуйте jQuery, щоб отримати висоту тіла в framed.html (проблема FF, тіло постійно зростає): var висота = $ (document.body) .height (); Використовували подію завантаження тіла для створення кадру в home.html, подібному до вашого підходу в framed.html. Адреси, що не оновлюють кадр для оновлення у FF та Safari.
Абдулла Джибалі

5
Геніальний! На додаток до доповнень Абдулла: замість того, щоб встановлювати завантаження тіла для виклику parentIframeResize(), я використовував JQuery для лову як завантаження сторінки, так і будь-яких подій зміни розміру: $(document).ready(iframeResizePipe); $(window).resize(iframeResizePipe);Це дозволяє мені встановити рамку iframe width="100%"та якщо ширина вікна зміниться, щоб зробити обгортання тексту чи щось таке, Внутрішня рамка визнає, що її потрібно змінити.
Стриптинг-воїн

9
Я пропоную надати iframe id = frame_name_here атрибут висоти за замовчуванням, наприклад висота = "2000". Це означає, що на сторінку завантажується обрамлений вміст. Коли зміни розміру не трапляються, немає "мерехтіння". Розмір зменшується / розширюється нижче сторінки. Якщо ви знаєте максимальну висоту вмісту iframed, тоді використовуйте це значення ... це також призводить до кращого досвіду носкриптів.
Кріс Якоб

3
Сім років потому, як і раніше найкраще крос-браузер, крос-доменне рішення, яке я знайшов. Браво.
FurryWombat

81

Якщо вам не потрібно обробляти вміст iframe з іншого домену, спробуйте цей код, він вирішить проблему повністю і це просто:

<script language="JavaScript">
<!--
function autoResize(id){
    var newheight;
    var newwidth;

    if(document.getElementById){
        newheight=document.getElementById(id).contentWindow.document .body.scrollHeight;
        newwidth=document.getElementById(id).contentWindow.document .body.scrollWidth;
    }

    document.getElementById(id).height= (newheight) + "px";
    document.getElementById(id).width= (newwidth) + "px";
}
//-->
</script>

<iframe src="usagelogs/default.aspx" width="100%" height="200px" id="iframe1" marginheight="0" frameborder="0" onLoad="autoResize('iframe1');"></iframe>

9
Можливо, буде більш оптимальним передати сам елемент у функцію, щоб уникнути всіх тих, document.getElementById(id)що у вас є, та спростити код.
Muhd

1
Для мене це не працює, оскільки contentWindow.document.body.scrollHeight має значення 0, а не реальна висота.
kroiz

4
Це рішення, як і всі інші, які я спробував, працює лише в тому випадку, якщо висота збільшується, якщо з високої сторінки ви переходите до коротшої, висота все ще встановлюється відповідно до висоти першої. Хтось знайшов рішення для цієї проблеми?
Євгеніо

6
@Eugenio та всі інші, включаючи мене, щоб вирішити цю остаточну проблему: див. Stackoverflow.com/questions/3053072/… Перш ніж запитати висоту документа всередині iframe, слід встановити висоту об’єкта iframe на "auto". Зауважте, що ви повинні використовувати style.height не просто висоту, як у відповіді вище
Кайл

7
Я не розумію ... ви перевіряєте наявність document.getElementById, а потім все-таки називаєте його поза межами перевіреної області?
Леголас

41

https://developer.mozilla.org/en/DOM/window.postMessage

window.postMessage ()

window.postMessage - це спосіб безпечного ввімкнення перехресного походження. Як правило, скриптам на різних сторінках доступ до одне одного дозволяється лише тоді, і лише тоді, коли сторінки, які їх виконали, знаходяться в місцях з одним і тим же протоколом (як правило, обидва http), номер порту (80 за замовчуванням для http) та хост (модуль) document.domain встановлюється для обох сторінок однаковим значенням). window.postMessage надає керований механізм обходу цього обмеження способом, захищеним при правильному використанні.

Підсумок

window.postMessage, коли викликається, викликає відправлення MessageEvent у цільове вікно, коли завершується будь-який очікуваний сценарій, який повинен бути виконаний (наприклад, залишилися обробники подій, якщо window.postMessage викликається від обробника подій, попередньо встановлені очікувані очікувані очікування тощо). ). MessageEvent має повідомлення типу, властивість даних, яке встановлюється у рядковому значенні першого аргументу, наданого window.postMessage, властивості початків, що відповідає походженню основного документа у вікні, що викликає window.postMessage у вікні часу. був викликаний postMessage, а властивість джерела - це вікно, з якого викликається window.postMessage. (Інші стандартні властивості подій присутні з очікуваними значеннями.)

Бібліотека iFrame-Resizer використовує postMessage для збереження розміру iFrame до його вмісту, поряд з MutationObserver для виявлення змін у вмісті і не залежить від jQuery.

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

jQuery: Міждоменний сценарій користі

http://benalman.com/projects/jquery-postmessage-plugin/

Має демонстрацію зміни розміру вікна iframe ...

http://benalman.com/code/projects/jquery-postmessage/examples/iframe/

У цій статті показано, як зняти залежність від jQuery ... Плюс має багато корисної інформації та посилань на інші рішення.

http://www.onlineaspect.com/2010/01/15/backwards-compatible-postmessage/

Приклад босоніжок ...

http://onlineaspect.com/uploads/postmessage/parent.html

HTML 5 робочий проект на window.postMessage

http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages

Джон Резіг на обмін повідомленнями між вікнами

http://ejohn.org/blog/cross-window-messaging/


postMessage сам по собі не є крос-браузером, але плагін jQuery, здається, добре справляється з підробкою, коли це необхідно. Єдиною справжньою проблемою є "мотлох", який додається до рядка URL у випадках, коли postMessage не підтримується.
Гермс

2
postMessage, здається, X-браузер. Тільки IE має помилки або речі, які мають бути обережні: 1. Зв'язок лише між кадрами або рамками 2. Можливий лише розміщення рядків. Дивіться: caniuse.com/x-doc-messaging
Крістіан Куетбах

3
Було б приємно бачити, що ви відповіли на питання замість пояснення про допоміжну технологію, яка допомагає вирішити ..
hitautodestruct

periscopedata використовує postMessage, якщо це достатньо добре для них, це досить добре для нас. Ось їхні документи: doc.periscopedata.com/docv2/embed-api-options
Євген Афанасьєв,

8

Найпростіший спосіб використання jQuery:

$("iframe")
.attr({"scrolling": "no", "src":"http://www.someotherlink.com/"})
.load(function() {
    $(this).css("height", $(this).contents().height() + "px");
});

14
Не перехрещуйте домен відповідно до запиту.
willem

6

Рішення на http://www.phinesolutions.com/use-jquery-to-adjust-the-iframe-height.html чудово працює (використовує jQuery):

<script type=”text/javascript”>
  $(document).ready(function() {
    var theFrame = $(”#iFrameToAdjust”, parent.document.body);
    theFrame.height($(document.body).height() + 30);
  });
</script>

Я не знаю, що вам потрібно додати 30 в довжину ... 1 працював на мене.

FYI : Якщо у вас вже є атрибут "висота" у вашому iFrame, це просто додає style = "height: xxx". Це може бути не те, що ви хочете.


7
Не міждомен, ні.
Воломіке

Тільки те, що мені було потрібно, оскільки я не роблю крос-домен, +1 для дійсного html.
WildJoe

4

можливо трохи пізно, оскільки всі інші відповіді старші :-) але ... ось моє рішення. Тестовано на фактичних FF, Chrome та Safari 5.0.

css:

iframe {border:0; overflow:hidden;}

javascript:

$(document).ready(function(){
    $("iframe").load( function () {
        var c = (this.contentWindow || this.contentDocument);
        if (c.document) d = c.document;
        var ih = $(d).outerHeight();
        var iw = $(d).outerWidth();
        $(this).css({
            height: ih,
            width: iw
        });
    });
});

Сподіваюсь, це допоможе комусь.


@pashute - ти маєш на увазі "перехресний домен"?
Лука

вибачте. Значення: Не працює крос-платформа ... Ось загальна публікація: gist.github.com/pashute/c4705ce7f767f50fdf56d0030ecf9192 Отримує відмову у виконанні помилки. Змінення сценарію на тип = "text / javascript" не допомагає. Не встановлюйте ширину та висоту рамки (скажімо, 80%).
пашуте

4

Нарешті я знайшов інше рішення для надсилання даних на батьківський веб-сайт із iframe за допомогою window.postMessage(message, targetOrigin); . Тут я пояснюю, як я це зробив.

Сайт A = http://foo.com Сайт B = http://bar.com

SiteB завантажується всередині сайтуAAA

Цей веб-сайт має веб-сайт SiteB

window.parent.postMessage("Hello From IFrame", "*"); 

або

window.parent.postMessage("Hello From IFrame", "http://foo.com");

Тоді siteA має такий код

// Here "addEventListener" is for standards-compliant web browsers and "attachEvent" is for IE Browsers.
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];


var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";

// Listen to message from child IFrame window
eventer(messageEvent, function (e) {
   alert(e.data);
   // Do whatever you want to do with the data got from IFrame in Parent form.
}, false); 

Якщо ви хочете додати з'єднання безпеки, ви можете використовувати це, якщо умова в eventer(messageEvent, function (e) {})

if (e.origin == 'http://iframe.example.com') {
    alert(e.data); 
    // Do whatever you want to do with the data got from IFrame in Parent form.
}

Для IE

Всередині IFrame:

 window.parent.postMessage('{"key":"value"}','*');

Зовні:

 eventer(messageEvent, function (e) {
   var data = jQuery.parseJSON(e.data);
   doSomething(data.key);
 }, false);

2

Ось просте рішення, використовуючи динамічно генерований аркуш стилів, який обслуговується тим же сервером, що і вміст iframe. Досить просто таблиця стилів "знає", що є у кадрі, і знає розміри, які слід використовувати для стилістики рамки. Це наближається до тих самих обмежень щодо політики походження.

http://www.8degrees.co.nz/2010/06/09/dynamically-resize-an-iframe-depending-on-its-content/

Отже, наданий код iframe матиме супровідну таблицю стилів, як-от ...

<link href="http://your.site/path/to/css?contents_id=1234&dom_id=iframe_widget" rel="stylesheet" type="text/css" />
 <iframe id="iframe_widget" src="http://your.site/path/to/content?content_id=1234" frameborder="0" width="100%" scrolling="no"></iframe>

Для цього потрібна можливість логіки на стороні сервера обчислювати розміри відображеного вмісту iframe.


Посилання не працює. Чи можете ви поділитися відповідним кодом у своїй відповіді, щоб він залишався актуальним для цієї теми?
зед

2

Ця відповідь застосовується лише для веб-сайтів, які використовують Bootstrap. Функція чуйного вбудовування Bootstrap робить свою роботу. Він заснований на ширині (не висоті) вмісту.

<!-- 16:9 aspect ratio -->
<div class="embed-responsive embed-responsive-16by9">
  <iframe class="embed-responsive-item" src="http://www.youtube.com/embed/WsFWhL4Y84Y"></iframe>
</div>

jsfiddle: http://jsfiddle.net/00qggsjj/2/

http://getbootstrap.com/components/#responsive-embed


Це працює для вставки відео, але якщо я хочу вставити веб-сторінку з висотою, вона отримує прокрутку та дивну висоту.
cabaji99

1

Я реалізую рамкове рішення ConroyP для заміни рішення на основі встановлення document.domain, але виявив, що досить важко правильно визначити висоту вмісту iframe в різних браузерах (тестування з FF11, Ch17 та IE9 прямо зараз ).

ConroyP використовує:

var height = document.body.scrollHeight;

Але це працює лише при початковому завантаженні сторінки. Мій iframe має динамічний зміст, і мені потрібно змінити розмір iframe для певних подій.

У кінцевому підсумку я використовував різні властивості JS для різних браузерів.

function getDim () {
    var body = document.body,
        html = document.documentElement;

    var bc = body.clientHeight;
    var bo = body.offsetHeight;
    var bs = body.scrollHeight;
    var hc = html.clientHeight;
    var ho = html.offsetHeight;
    var hs = html.scrollHeight;

    var h = Math.max(bc, bo, bs, hc, hs, ho);

    var bd = getBrowserData();

    // Select height property to use depending on browser
    if (bd.isGecko) {
        // FF 11
        h = hc;
    } else if (bd.isChrome) {
        // CH 17
        h = hc;
    } else if (bd.isIE) {
        // IE 9
        h = bs;
    }

    return h;
}

getBrowserData () - це функція виявлення браузера, "натхненна" http://docs.sencha.com/core/source/Ext.html#method-Ext-apply Ext Core

Це добре працювало для FF та IE, але тоді були проблеми з Chrome. Одне з питань було тимчасовим, очевидно, Chrome потребує певного часу, щоб встановити / виявити висоту iframe. І тоді Chrome також ніколи не повертав висоту вмісту у iframe правильно, якщо iframe був вищим за вміст. Це не працює з динамічним вмістом, коли висота зменшується.

Щоб вирішити це, я завжди встановлюю рамку iframe на низьку висоту, перш ніж визначати висоту вмісту, а потім встановлюю висоту iframe на правильне значення.

function resize () {
    // Reset the iframes height to a low value.
    // Otherwise Chrome won't detect the content height of the iframe.
    setIframeHeight(150);

    // Delay getting the dimensions because Chrome needs
    // a few moments to get the correct height.
    setTimeout("getDimAndResize()", 100);
}

Код не оптимізований, це з мого розробника :)

Сподіваюся, хтось вважає це корисним!


1
<html>
<head>
<script>
function frameSize(id){
var frameHeight;

document.getElementById(id).height=0 + "px";
if(document.getElementById){
    newheight=document.getElementById(id).contentWindow.document.body.scrollHeight;    
}

document.getElementById(id).height= (frameHeight) + "px";
}
</script>
</head>

<body>

<iframe id="frame"  src="startframe.html" frameborder="0" marginheight="0" hspace=20     width="100%" 

onload="javascript:frameSize('frame');">

<p>This will work, but you need to host it on an http server, you can do it locally.    </p>
</body>
</html>

0

Гаджети iGoogle повинні активно впроваджувати розміри, тому, напевно, у крос-доменній моделі вам не обійтися без віддаленого вмісту. Якщо ваш вміст може надіслати повідомлення нового розміру на сторінку контейнера за допомогою типових прийомів комунікації між доменами, тоді все інше просте.


0

Коли ви хочете зменшити масштаб веб-сторінки, щоб вона підходила до розміру рамки:

  1. Ви повинні змінити розмір iframe, щоб він відповідав вмісту
  2. Тоді вам слід зменшити масштаб всього iframe із завантаженим вмістом веб-сторінки

Ось приклад:

<div id="wrap">
   <IFRAME ID="frame" name="Main" src ="http://www.google.com" />
</div>

<style type="text/css">
    #wrap { width: 130px; height: 130px; padding: 0; overflow: hidden; }
    #frame { width: 900px; height: 600px; border: 1px solid black; }
    #frame { zoom:0.15; -moz-transform:scale(0.15);-moz-transform-origin: 0 0; }
</style>

0

Ось підхід jQuery, який додає інформацію в json через атрибут src iframe. Ось демонстрація, змініть розмір і прокрутіть це вікно. Отриманий URL з json виглядає приблизно так ... http://fiddle.jshell.net/zippyskippy/RJN3G/show/#{docHeight:5124,windowHeight:1019,scrollHeight: 571} #

Ось джерела вихідного коду http://jsfiddle.net/zippyskippy/RJN3G/

function updateLocation(){

    var loc = window.location.href;
    window.location.href = loc.replace(/#{.*}#/,"") 
        + "#{docHeight:"+$(document).height() 
        + ",windowHeight:"+$(window).height()
        + ",scrollHeight:"+$(window).scrollTop()
        +"}#";

};

//setInterval(updateLocation,500);

$(window).resize(updateLocation);
$(window).scroll(updateLocation);

0

Отримайте висоту вмісту iframe, тоді надайте цьому iframe

 var iframes = document.getElementsByTagName("iframe");
 for(var i = 0, len = iframes.length; i<len; i++){
      window.frames[i].onload = function(_i){
           return function(){
                     iframes[_i].style.height = window.frames[_i].document.body.scrollHeight + "px";
                     }
      }(i);
 }

1
Чи можете ви додати якийсь опис про те, чому ваш код відповідає на питання?
реге

0

Робота з jquery при завантаженні (крос-браузер):

 <iframe src="your_url" marginwidth="0"  marginheight="0" scrolling="No" frameborder="0"  hspace="0" vspace="0" id="containiframe" onload="loaderIframe();" height="100%"  width="100%"></iframe>

function loaderIframe(){
var heightIframe = $('#containiframe').contents().find('body').height();
$('#frame').css("height", heightFrame);
 }  

на розмірі на чуйній сторінці:

$(window).resize(function(){
if($('#containiframe').length !== 0) {
var heightIframe = $('#containiframe').contents().find('body').height();
 $('#frame').css("height", heightFrame);
}
});

-1

Використання jQuery:

parent.html

<body>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<style>
iframe {
    width: 100%;
    border: 1px solid black;
}
</style>
<script>
function foo(w, h) {
    $("iframe").css({width: w, height: h});
    return true;  // for debug purposes
}
</script>
<iframe src="child.html"></iframe>
</body>

child.html

<body>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script>
$(function() {
    var w = $("#container").css("width");
    var h = $("#container").css("height");

    var req = parent.foo(w, h);
    console.log(req); // for debug purposes
});
</script>
<style>
body, html {
    margin: 0;
}
#container {
    width: 500px;
    height: 500px;
    background-color: red;
}
</style>
<div id="container"></div>
</body>

-2

Це трохи хитро, тому що ви повинні знати, коли завантажується сторінка iframe, що явно, коли ви не контролюєте її вміст. Можна додати оброблювача завантаження до iframe, але я це намагався в минулому, і він має зовсім іншу поведінку в браузерах (не здогадуйтесь, хто найбільше дратує ...). Вам, ймовірно, доведеться додати функцію на сторінку iframe, яка виконує розмір і вводить якийсь скрипт у вміст, який або слухає завантаження подій, або зміни розміру подій, яка потім викликає попередню функцію. Я думаю додати функцію на сторінку, оскільки ви хочете переконатися, що її безпека, але я не маю уявлення, як легко це зробити.


-2

Щось на лінії цього, я вірю, має працювати.

parent.document.getElementById(iFrameID).style.height=framedPage.scrollHeight;

Завантажте це, коли ваше тіло буде завантажено на вміст iframe.


3
Це неможливо, оскільки вміст в iFrames завантажується з інших доменів, тому намагаючись це зробити, це призводить до помилки, наприклад, від Firefox: "Дозволу заборонено отримувати властивість Window.document".
larssg

-4

У мене є просте рішення, і вам потрібно визначити ширину та висоту посилання, будь ласка, спробуйте (Це працює з більшістю браузерів):

<a href='#' onClick=" document.getElementById('myform').src='t2.htm';document.getElementById('myform').width='500px'; document.getElementById('myform').height='400px'; return false">500x400</a>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.