Вычисление кроссбраузерной высоты iframe

Одной из самых сложных проблем в моем опыте работы с javascript было правильное (то есть «кроссбраузерное») вычисление высота iframe. В моих приложениях у меня много динамически генерируемых iframe, и я хочу, чтобы все они выполняли своего рода автоматическое изменение размера в конце события загрузки, чтобы настроить их высоту и ширину.

В случае вычислений высота моим лучшим решением является следующее (с помощью jQuery):

function getDocumentHeight(doc) {
  var mdoc = doc || document;
  if (mdoc.compatMode=='CSS1Compat') {       
      return mdoc.body.offsetHeight;
  }
  else {
    if ($.browser.msie)
      return mdoc.body.scrollHeight;
    else  
      return Math.max($(mdoc).height(), $(mdoc.body).height());
  }
}

Я безуспешно искал в Интернете. Я также протестировал библиотеку Yahoo, в которой есть несколько методов для измерения размеров документа и области просмотра, но это меня не удовлетворило. Мое решение работает прилично, но иногда рассчитывает более высокую высоту. Я изучил и протестировал множество свойств, касающихся высоты документа в Firefox / IE / Safari: documentElement.clientHeight, documentElement.offsetHeight, documentElement.scrollHeight, body.offsetHeight, body.scrollHeight, ... Также jQuery не имеет последовательного поведения в различных браузерах с вызовами $(document.body).height(), $('html', doc).height(), $(window).height().

Я вызываю указанную выше функцию не только в конце события загрузки, но и в случае динамически вставленных элементов DOM или элементов, скрытых или отображаемых. Это случай, который иногда нарушает код, работающий только в событии загрузки.

Есть ли у кого-нибудь реальное кроссбраузерное решение (по крайней мере, Firefox / IE / Safari)? Несколько советов или подсказок?

Сейчас я работаю над этим вопросом. Вы нашли решение?

Shakakai 28.03.2011 21:13
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
16
1
11 173
6

Ответы 6

Хотя мне нравится ваше решение, я всегда считал, что IFRAME доставляют больше проблем, чем они того стоят.

Почему ? 1. Проблема калибровки. 2. В iframe есть атрибут src, о котором нужно беспокоиться. то есть абсолютный путь. 3. Дополнительная сложность со страницами.

Мое решение - DIV, которые динамически загружаются через вызовы AJAX. DIV будут автоматически изменять размер. Хотя код AJAX требует работы с javascript (что можно сделать с помощью фреймворков), они зависят от местоположения сайта. 3 - это промывка, вы торгуете сложностью на страницах вплоть до javascript.

Вместо <IFRAME ...> используйте <DIV id = "mystuff" />

Выполните вызов ajax, чтобы заполнить div mystuff данными и позволить браузеру позаботиться об этом.

Я рассматривал возможность DIV, но я не знаю простого решения проблемы идентификатора (элементов DOM): при совместном использовании одного и того же пространства имен DIV, вероятно, имеет много конфликтов идентификаторов. Учтите, что у меня одновременно открыто много фреймов. Тем не менее, ваше решение заслуживает внимательного рассмотрения.

Pier Luigi 16.10.2008 17:07

Вы не можете AJAX загружать контент с внешнего сайта; это нарушение безопасности браузера (межсайтовый скриптинг). <iframes>, вероятно, единственное клиентское решение, позволяющее загружать внешний контент.

artur 15.02.2010 21:32

Очень хорошее замечание об элементах x-site, однако, если мне действительно нужны эти данные, я "перекидываю" их с сервера. т.е. страница выполняет вызов, сервер выполняет построение страницы, включая другие «внешние» страницы, а затем возвращает это исходному клиенту. У меня был клиент, которому требовалось встроенное видео, и, чтобы избежать межсайтового взаимодействия, сервер временно сохранил его и вернул все клиенту.

jim 02.04.2011 03:03

@jim - моя проблема с этим подходом заключается в том, что я загружаю HTML, который может быть, а может и не быть полуразрушенным. Использование iframe ограничивает влияние плохой разметки на остальную часть страницы.

Shakakai 02.04.2011 15:49

Вы можете загружать данные из другого домена с помощью JSONP.

Eivind 04.04.2011 15:39

iFrames де-факто являются стандартом для загрузки рекламы Google, Yahoo, Microsoft, Doubleclick и тысяч других компаний.

Steve K 01.02.2012 17:44

@Stephen - То, что есть «тысячи» других, не означает, что решение подходит для того, что вы пытаетесь сделать. Посмотрите на cpmadvisors.com/2009/11/16/…, чтобы узнать о том, как Amazon обертывает фреймы рекламных сетей, чтобы предотвратить сбор данных.

jim 01.02.2012 22:23

Вот решение, которое, кажется, работает. По сути, scrollHeight является правильным значением в большинстве случаев. Однако в IE (в частности, 6 и 7), если контент просто содержится в текстовых узлах, высота не вычисляется и по умолчанию используется только высота, установленная в CSS или в атрибуте «высота» в iframe. Это было найдено методом проб и ошибок, так что принимайте это как следует.

function getDocumentHeight(doc) {
  var mdoc = doc || document; 
  var docHeight = mdoc.body.scrollHeight;

  if ($.browser.msie) {
      // IE 6/7 don't report body height correctly.  
      // Instead, insert a temporary div containing the contents.

      var child = $("<div>" + mdoc.body.innerHTML + "</div>", mdoc);
      $("body", mdoc).prepend(child);
      docHeight = child.height();
      child.remove();
  }

  return docHeight;
}

Я нашел, что это решение работает, например, 6+, ff 3.5+, safari 4+. Я создаю и добавляю в документ iframe. Следующий код выполняется в конце события загрузки jQuery после некоторой другой манипуляции с dom. Тайм-аут нужен мне из-за дополнительных манипуляций с dom, происходящих в событии загрузки.

// sizing - slight delay for good scrollheight
setTimeout(function() {
   var intContentHeight = objContentDoc.body.scrollHeight;
   var $wrap = $("#divContentWrapper", objContentFrameDoc);
   var intMaxHeight = getMaxLayeredContentHeight($wrap);
   $this.height(intContentHeight > intMaxHeight ? intMaxHeight : intContentHeight);

   // animate
   fireLayeredContentAnimation($wrap);
}, 100);

У меня есть некоторые ограничения по размеру, которые нужно учитывать, и это то, что для меня проверяет вызов getMaxLayeredContentHeight. Надеюсь, это поможет.

Поскольку в вашем примере вы обращаетесь к документу внутри в IFRAME, я думаю, вы говорите о знании высоты документа, а не самого фрейма. Кроме того, это означает, что контент поступает с вашего собственного веб-сайта, и вы можете контролировать его содержимое.

Итак, почему бы вам просто не разместить DIV вокруг своего контента, а затем использовать clientHeight этого DIV?

Код, который вы загружаете в свой IFRAME:

...
<body>
  <div id = "content">
  ...
  </div>
</body>

Родительский документ:

 function getDocumentHeight(mdoc) {
    return mdoc.getElementById("content").clientHeight;
 }

Кстати, эта часть вашей примерной функции не имеет смысла, поскольку «документ» не относится к IFRAME: var mdoc = doc || document;

Вот сценарий, который изменяет размер iFrame в зависимости от высоты тела внутри него.

Некоторое время не было принятого ответа, поэтому я хотел внести свой вклад в решение, к которому я пришел после некоторых исследований. Это кроссбраузерный и междоменный (например, когда iframe указывает на контент из другого домена)

В итоге я использовал механизм передачи сообщений html5, завернутый в подключение jQuery, что делает его совместимым со старыми браузерами с использованием различных методов (некоторые из них описаны в этом потоке).

Конечное решение очень простое.

На главной (родительской) странице:

// executes when a message is received from the iframe, to adjust 
// the iframe's height
    $.receiveMessage(
        function( event ){
            $( 'my_iframe' ).css({
                height: event.data
            });
    });

// Please note this function could also verify event.origin and other security-related checks.

На странице iframe:

$(function(){

    // Sends a message to the parent window to tell it the height of the 
    // iframe's body

    var target = parent.postMessage ? parent : (parent.document.postMessage ? parent.document : undefined);

    $.postMessage(
        $('body').outerHeight( true ) + 'px',
        '*',
        target
    );

});

Я тестировал это на Chrome 13+, Firefox 3.6+, IE7, 8 и 9 на XP и W7, safari на OSX и W7. ;)

Другие вопросы по теме