Как применить CSS к iframe?


1017

У меня есть простая страница, которая имеет несколько разделов iframe (для отображения ссылок RSS). Как применить тот же формат CSS с главной страницы к странице, отображаемой в iframe?


66
Это возможно, но только если домен iframe совпадает с доменом родителя
— gawpertron

13
gawpertron, просто чтобы уточнить, вы говорите, что если я использую контент iFrame из какого-то другого домена, который я не контролирую, я не смогу контролировать CSS для этого контента?
— Ville M

Можете ли вы перечислить ссылку на страницу, чтобы мы могли просто просмотреть наши изменения.

5
Домен, порт и протокол должны быть одинаковыми, также не работает с поддоменами.
— Ли Пенкман

Ответы:


434

Изменить: Это не работает кросс-домен, если не установлен соответствующий заголовок CORS .

Здесь есть две разные вещи: стиль блока iframe и стиль страницы, встроенной в iframe. Вы можете установить стиль блока iframe обычным способом:

<iframe name="iframe1" id="iframe1" src="empty.htm" 
        frameborder="0" border="0" cellspacing="0"
        style="border-style: none;width: 100%; height: 120px;"></iframe>

Стиль страницы, встроенной в iframe, должен быть установлен путем включения его в дочернюю страницу:

<link type="text/css" rel="Stylesheet" href="Style/simple.css" />

Или его можно загрузить с родительской страницы с помощью Javascript:

var cssLink = document.createElement("link");
cssLink.href = "style.css"; 
cssLink.rel = "stylesheet"; 
cssLink.type = "text/css"; 
frames['iframe1'].document.head.appendChild(cssLink);

30
Пожалуйста, обратите внимание, мне кажется, что некоторые примеры, опубликованные ранее, теперь недействительны для html5. Вы можете получить доступ содержимого фрейма следующим образом : document.getElementById("myframe").contentDocument. Однако встраивание CSS все еще не работает для меня.
— Рено Линдек

35
ссылка может появиться только в ГОЛОВЕ
— Кну

18
У меня работало только тогда, когда я это делал ...document.head.appendChild(cssLink)- Firefox и Safari.
— Моджуба

24
Это на самом деле работает кросс-домен? Я не думаю, что это будет.
— Саймон Ист

89
Точно так же № 1 еще должен проверить это, чтобы выяснить: правильно, он не работает междоменный. Сразу после выполнения frame ['name'] вы получаете «Небезопасная попытка JavaScript получить доступ к фрейму с URL-бла из фрейма с URL-бла. Домены, протоколы и порты должны совпадать».
— Кевин

205

Я столкнулся с этой проблемой в Календаре Google . Я хотел стилизовать его на более темном фоне и изменить шрифт.

К счастью, URL из встраиваемого кода не имеет ограничений на прямой доступ, поэтому с помощью функции PHP file_get_contentsможно получить весь контент со страницы. Вместо того, чтобы вызывать URL-адрес Google, можно вызвать php-файл, расположенный на вашем сервере, например. google.php, который будет содержать оригинальный контент с изменениями:

$content = file_get_contents('https://www.google.com/calendar/embed?src=%23contacts%40group.v.calendar.google.com&ctz=America/Montreal');

Добавление пути к вашей таблице стилей:

$content = str_replace('</head>','<link rel="stylesheet" href="http://www.yourwebsiteurl.com/google.css" /></head>', $content);

(Это сделает вашу таблицу стилей последней перед headконечным тегом.)

Укажите базовый URL-адрес из исходного URL-адреса в случае, если css и js называются относительно:

$content = str_replace('</title>','</title><base href="https://www.google.com/calendar/" />', $content);

Окончательный google.phpфайл должен выглядеть так:

<?php
$content = file_get_contents('https://www.google.com/calendar/embed?src=%23contacts%40group.v.calendar.google.com&ctz=America/Montreal');
$content = str_replace('</title>','</title><base href="https://www.google.com/calendar/" />', $content);
$content = str_replace('</head>','<link rel="stylesheet" href="http://www.yourwebsiteurl.com/google.css" /></head>', $content);
echo $content;

Затем вы меняете iframeкод встраивания на:

<iframe src="http://www.yourwebsiteurl.com/google.php" style="border: 0" width="800" height="600" frameborder="0" scrolling="no"></iframe>

Удачи!


71
Вы можете назвать это взломом по определению, если хотите. Но вы не предложили лучшего решения ... Это решение не способ нанести вред службе Google или обмануть людей, чтобы использовать их слабости.
— SequenceDigitale.com

5
Я хотел бы убить способ заставить это решение работать с Google Docs. Это бросает все виды ошибок JavaScript. «Uncaught TypeError: Невозможно прочитать свойство« a »с неопределенным значением»
— deweydb

1
Неважно, я понял, разместил решение здесь: stackoverflow.com/questions/25395279/…
— deweydb

9
@ChrisHoughton FYI, это в основном не так. Это может, однако, сделать весь iframe бессмысленным (например, одна из причин использования iframe - в целях безопасности, например, с платежами по карте, и если вы сделаете то, что предлагается здесь, у вас, вероятно, возникнут проблемы).
— Аластер

10
Делая это, вы всегда получаете календарь как не авторизованный пользователь. При использовании обычного html iframe пользователь будет видеть свой личный календарь, если он вошел в Google, но, поскольку ваш PHP-код не может знать идентификатор сеанса Google, он не может получить их личный календарь.
— 17

72

Если содержимое iframe находится не полностью под вашим контролем, или вы хотите получить доступ к содержимому с разных страниц с разными стилями, вы можете попробовать манипулировать им с помощью JavaScript.

var frm = frames['frame'].document;
var otherhead = frm.getElementsByTagName("head")[0];
var link = frm.createElement("link");
link.setAttribute("rel", "stylesheet");
link.setAttribute("type", "text/css");
link.setAttribute("href", "style.css");
otherhead.appendChild(link);

Обратите внимание, что в зависимости от того, какой браузер вы используете, это может работать только на страницах, обслуживаемых из того же домена.


82
Стоит отметить, что одна и та же политика происхождения прекратит эту работу, если страница находится в другом домене.
— ConroyP

2
В том же духе мышления, но более лаконично: <iframe onload="this.contentDocument.body.style.overflow='hidden';" />
— Защитник один

Даже Firefox вышел из CORS

59
var $head = $("#eFormIFrame").contents().find("head");

$head.append($("<link/>", {
    rel: "stylesheet",
    href: url,
    type: "text/css"
}));

@deweydb Я использовал его с междоменным iframe. но я могу только попросить у тебя прощения!
— Рами Сариеддин

@ramie, а вы тестировали это в нескольких браузерах? большинство браузеров выдают ошибку безопасности.
— deweydb

Я видел эту идею раньше, но добавляю ссылку на файл, это действительно здорово и профессионально ... + вверх
— J.Tural

29

В большинстве браузеров iframe универсально обрабатывается как другая HTML-страница. Если вы хотите применить ту же таблицу стилей к содержимому iframe, просто назовите ее со страниц, используемых там.


22
@ Ханги, но ... как?
— Дитя Божие

29

Вот как применить код CSS напрямую, без использования <link>для загрузки дополнительной таблицы стилей.

var head = jQuery("#iframe").contents().find("head");
var css = '<style type="text/css">' +
          '#banner{display:none}; ' +
          '</style>';
jQuery(head).append(css);

Это скрывает баннер на странице iframe. Спасибо вам за ваши предложения!


1
Нужен ли для этого iframe с идентификатором iframe?
— Джереми

1
@jmalais Просто замените #iframeс #<id>или даже iframeвыбрать все iframeS
— Зеб Маккоркл

3
Кажется, это не работает для меня. У iframe, который я пытаюсь отредактировать, также нет головы прямо под ним в dom. Значит ли это, что мне нужен доступ к заголовку внутри html-документа или это то, что функция поиска jquery должна выполнять сама?
— Дэвид А. Френч

1
Проверьте консоль и похоже, что она заблокирована от доступа к содержимому iframe из-за несоответствия домена. В настоящее время я использую Chrome и размещаю свою среду разработки локально.
— Дэвид А. Френч

Uncaught DOMException: заблокировал фрейм с источником, это дает мне эту ошибку
— priyanka patel

26

Если вы управляете страницей в iframe, как сказал Hangy, самый простой подход - создать общий CSS-файл с общими стилями, а затем просто дать ссылку на него со своих html-страниц.

В противном случае маловероятно, что вы сможете динамически изменять стиль страницы с внешней страницы в вашем фрейме. Это связано с тем, что браузеры ужесточили меры безопасности для межкадровых сценариев из-за возможного неправильного использования для подмены и других хаков.

Этот учебник может предоставить вам больше информации о скриптовых фреймах в целом. О межкадровом сценарии объясняются ограничения безопасности с точки зрения IE.


19

Выше с небольшим изменением работает:

var cssLink = document.createElement("link") 
cssLink.href = "pFstylesEditor.css"; 
cssLink.rel = "stylesheet"; 
cssLink.type = "text/css"; 

//Instead of this
//frames['frame1'].document.body.appendChild(cssLink);
//Do this

var doc=document.getElementById("edit").contentWindow.document;

//If you are doing any dynamic writing do that first
doc.open();
doc.write(myData);
doc.close();

//Then append child
doc.body.appendChild(cssLink);

Отлично работает с ff3 и ie8 как минимум


7
Что такое мои данные и откуда они взялись
— Тигран

1
@Tigran это дляdynamic data
— Акаш

13

Если вы хотите повторно использовать CSS и JavaScript с главной страницы, возможно, вам стоит подумать о замене <IFRAME>контента, загруженного Ajax. Это более оптимизировано для SEO, когда поисковые роботы могут выполнять JavaScript.

Это пример jQuery, который включает другую HTML-страницу в ваш документ. Это гораздо более дружественный, чем SEO iframe. Чтобы убедиться, что боты не индексируют включенную страницу, просто добавьте ее, чтобы запретить вrobots.txt

<html>
  <header>
    <script src="/js/jquery.js" type="text/javascript"></script>
  </header>
  <body>
    <div id='include-from-outside'></div>
    <script type='text/javascript'>
      $('#include-from-outside').load('http://example.com/included.html');
    </script> 
  </body>
</html>

Вы также можете включить jQuery непосредственно из Google: http://code.google.com/apis/ajaxlibs/documentation/ - это означает необязательное автоматическое включение более новых версий и значительное увеличение скорости. Кроме того, это означает, что вы должны доверять им за то, что они предоставили вам только jQuery;)


1
Следует отметить, что это решение не работает, если содержание страницы является динамическим в любом случае.
— nickdnk

12

Следующее сработало для меня.

var iframe = top.frames[name].document;
var css = '' +
          '<style type="text/css">' +
          'body{margin:0;padding:0;background:transparent}' +
          '</style>';
iframe.open();
iframe.write(css);
iframe.close();

1
Ошибка:Uncaught TypeError: Cannot read property 'open' of undefined
— KingRider

10

Расширение на вышеупомянутое решение jQuery, чтобы справиться с любыми задержками в загрузке содержимого кадра.

$('iframe').each(function(){
    function injectCSS(){
        $iframe.contents().find('head').append(
            $('<link/>', { rel: 'stylesheet', href: 'iframe.css', type: 'text/css' })
        );
    }

    var $iframe = $(this);
    $iframe.on('load', injectCSS);
    injectCSS();
});

1
'$ This' должно быть '$ (this)', чтобы оно работало. Приятно, когда это так :)
— h.coates

9

Моя компактная версия :

<script type="text/javascript">
$(window).load(function () {
    var frame = $('iframe').get(0);
    if (frame != null) {
        var frmHead = $(frame).contents().find('head');
        if (frmHead != null) {
            frmHead.append($('style, link[rel=stylesheet]').clone()); // clone existing css link
            //frmHead.append($("<link/>", { rel: "stylesheet", href: "/styles/style.css", type: "text/css" })); // or create css link yourself
        }
    }   
});
</script>

Однако иногда iframeон не готов к загрузке окна, поэтому необходимо использовать таймер .

Готовый код (с таймером):

<script type="text/javascript">
var frameListener;
$(window).load(function () {
    frameListener = setInterval("frameLoaded()", 50);
});
function frameLoaded() {
    var frame = $('iframe').get(0);
    if (frame != null) {
        var frmHead = $(frame).contents().find('head');
        if (frmHead != null) {
            clearInterval(frameListener); // stop the listener
            frmHead.append($('style, link[rel=stylesheet]').clone()); // clone existing css link
            //frmHead.append($("<link/>", { rel: "stylesheet", href: "/styles/style.css", type: "text/css" })); // or create css link yourself
        }
    }
}
</script>

... и ссылка JQuery:

<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js" type="text/javascript"></script>

8

Другие ответы здесь, похоже, используют ссылки jQuery и CSS.

Этот код использует ванильный JavaScript. Это создает новый <style>элемент. Он устанавливает текстовое содержимое этого элемента как строку, содержащую новый CSS. И он добавляет этот элемент непосредственно в заголовок документа iframe.

var iframe = document.getElementById('the-iframe');
var style = document.createElement('style');
style.textContent =
  '.some-class-name {' +
  '  some-style-name: some-value;' +
  '}' 
;
iframe.contentDocument.head.appendChild(style);

7

Когда вы говорите «doc.open ()», это означает, что вы можете написать любой тег HTML внутри iframe, поэтому вы должны написать все основные теги для страницы HTML, и если вы хотите иметь ссылку CSS в вашей голове iframe, просто напишите iframe со ссылкой на CSS. Я приведу вам пример:

doc.open();

doc.write('<!DOCTYPE html><html><head><meta charset="utf-8"/><meta http-quiv="Content-Type" content="text/html; charset=utf-8"/><title>Print Frame</title><link rel="stylesheet" type="text/css" href="https://stackoverflow.com/css/print.css"/></head><body><table id="' + gridId + 'Printable' + '" class="print" >' + out + '</table></body></html>');

doc.close();

7

Использование может попробовать это:

$('iframe').load( function() {
     $('iframe').contents().find("head")
     .append($("<style type='text/css'>  .my-class{display:none;}  </style>"));
  });

3
Если ваш iframe имеет другое происхождение, механизм CORS не допустит этот обходной путь.
— г-н Андерсон

Что если в iframe-url CORS включен для всех местоположений?
— августа

6

Вы не сможете стилизовать содержимое iframe таким образом. Я бы предложил использовать серверные сценарии (PHP, ASP или Perl) или найти онлайн-сервис, который преобразует канал в код JavaScript. Единственный способ сделать это - включить серверное включение.


29
Осторожнее, когда вы говорите, что что-то не может быть сделано, когда на самом деле это просто сложно
— Lathan

4

Если у вас есть доступ к странице iframe и вы хотите, чтобы другой CSS применялся к ней только тогда, когда вы загружаете ее через iframe на своей странице, здесь я нашел решение для такого рода вещей.

это работает, даже если iframe загружает другой домен

проверить о postMessage()

план, отправьте css в iframe как сообщение

iframenode.postMessage('h2{color:red;}','*');

* отправить это сообщение независимо от того, в каком домене оно находится в iframe

и получите сообщение в iframe и добавьте полученное сообщение (CSS) в заголовок документа.

код для добавления на страницу iframe

window.addEventListener('message',function(e){

    if(e.data == 'send_user_details')
    document.head.appendChild('<style>'+e.data+'</style>');

});

4

Поскольку для одних и тех же доменов написано много ответов, я напишу, как это сделать в кросс-доменах.

Во-первых, вам нужно знать API Post Message . Нам нужен мессенджер для связи между двумя окнами.

Вот мессенджер, которого я создал.

/**
 * Creates a messenger between two windows
 *  which have two different domains
 */
class CrossMessenger {

    /**
     * 
     * @param {object} otherWindow - window object of the other
     * @param {string} targetDomain - domain of the other window
     * @param {object} eventHandlers - all the event names and handlers
     */
    constructor(otherWindow, targetDomain, eventHandlers = {}) {
        this.otherWindow = otherWindow;
        this.targetDomain = targetDomain;
        this.eventHandlers = eventHandlers;

        window.addEventListener("message", (e) => this.receive.call(this, e));
    }

    post(event, data) {

        try {
            // data obj should have event name
            var json = JSON.stringify({
                event,
                data
            });
            this.otherWindow.postMessage(json, this.targetDomain);

        } catch (e) {}
    }

    receive(e) {
        var json;
        try {
            json = JSON.parse(e.data ? e.data : "{}");
        } catch (e) {
            return;
        }
        var eventName = json.event,
            data = json.data;

        if (e.origin !== this.targetDomain)
            return;

        if (typeof this.eventHandlers[eventName] === "function") 
            this.eventHandlers[eventName](data);
    }

}

Использование этого в двух окнах для общения может решить вашу проблему.

В главных окнах

var msger = new CrossMessenger(iframe.contentWindow, "https://iframe.s.domain");

var cssContent = Array.prototype.map.call(yourCSSElement.sheet.cssRules, css_text).join('\n');
msger.post("cssContent", {
   css: cssContent
})

Затем получите событие от Iframe.

В Iframe:

var msger = new CrossMessenger(window.parent, "https://parent.window.domain", {
    cssContent: (data) => {
        var cssElem = document.createElement("style");
        cssElem.innerHTML = data.css;
        document.head.appendChild(cssElem);
    }
})

См. Полный учебник по Javascript и Iframes для более подробной информации.


3

Я нашел другое решение, чтобы поместить стиль в основной HTML, как это

<style id="iframestyle">
    html {
        color: white;
        background: black;
    }
</style>
<style>
    html {
        color: initial;
        background: initial;
    }
    iframe {
        border: none;
    }
</style>

а затем в iframe сделать это (см. JS Onload)

<iframe  onload="iframe.document.head.appendChild(ifstyle)" name="log" src="/upgrading.log"></iframe>

и в JS

<script>
    ifstyle = document.getElementById('iframestyle')
    iframe = top.frames["log"];
</script>

Возможно, это не лучшее решение, и, безусловно, его можно улучшить, но это еще один вариант, если вы хотите сохранить тег «style» в родительском окне.


3

Здесь есть две вещи внутри домена

  1. Раздел iFrame
  2. Страница загружена внутри iFrame

Итак, вы хотите оформить эти два раздела следующим образом:

1. Стиль для раздела iFrame

Это может стилизовать использование CSS с этим уважаемым idили classименем. Вы можете просто стилизовать его в своих родительских таблицах стилей.

<style>
#my_iFrame{
height: 300px;
width: 100%;
position:absolute;
top:0;
left:0;
border: 1px black solid;
}
</style>

<iframe name='iframe1' id="my_iFrame" src="#" cellspacing="0"></iframe>

2. Стиль страницы, загруженной в iFrame

Эти стили могут быть загружены с родительской страницы с помощью Javascript

var cssFile  = document.createElement("link") 
cssFile.rel  = "stylesheet"; 
cssFile.type = "text/css"; 
cssFile.href = "iFramePage.css"; 

затем установите этот файл CSS в соответствующий раздел iFrame

//to Load in the Body Part
frames['my_iFrame'].document.body.appendChild(cssFile); 
//to Load in the Head Part
frames['my_iFrame'].document.head.appendChild(cssFile);

Здесь вы также можете редактировать заголовок страницы внутри iFrame также

var $iFrameHead = $("#my_iFrame").contents().find("head");
$iFrameHead.append(
   $("<link/>",{ 
      rel: "stylesheet", 
      href: urlPath, 
      type: "text/css" }
     ));

2

Мы можем вставить тег стиля в iframe. Размещено также здесь ...

<style type="text/css" id="cssID">
.className
{
    background-color: red;
}
</style>

<iframe id="iFrameID"></iframe>

<script type="text/javascript">
    $(function () {
        $("#iFrameID").contents().find("head")[0].appendChild(cssID);
        //Or $("#iFrameID").contents().find("head")[0].appendChild($('#cssID')[0]);
    });
</script>

1
Это не работает Кажется, правильно вставил тег стиля, но в нем нет содержимого и нет идентификатора.
— darylknight

2

var link1 = document.createElement('link');
    link1.type = 'text/css';
    link1.rel = 'stylesheet';
    link1.href = "../../assets/css/normalize.css";
window.frames['richTextField'].document.body.appendChild(link1);


1
Я проверял этот ответ много раз, что richTextFieldздесь?
— Киранкумар Дафда

1
это имя iframe
— Jeeva

Я не пробовал, но я думаю, что не будет, потому что это против песочницы
— Jeeva

1

Я думаю, что самый простой способ - добавить еще один div в том же месте, что и iframe, тогда

сделайте его z-indexбольше, чем контейнер iframe, так что вы можете просто создать свой собственный div. Если вам нужно нажать на нее, просто используйтеpointer-events:none на своем собственном div, так что iframe будет работать, если вам нужно нажать на него;)

Надеюсь, это кому-нибудь поможет;)


1

Существует замечательный сценарий, который заменяет узел самой версией iframe. CodePen Demo

введите описание изображения здесь

Примеры использования:

// Single node
var component = document.querySelector('.component');
var iframe = iframify(component);

// Collection of nodes
var components = document.querySelectorAll('.component');
var iframes = Array.prototype.map.call(components, function (component) {
  return iframify(component, {});
});

// With options
var component = document.querySelector('.component');
var iframe = iframify(component, {
  headExtra: '<style>.component { color: red; }</style>',
  metaViewport: '<meta name="viewport" content="width=device-width">'
});

1
Почему вы хотите это сделать?!
— Дилан Уотсон


0

Это всего лишь концепция, но не реализуйте ее без проверок безопасности и фильтрации! В противном случае скрипт может взломать ваш сайт!

Ответ: если вы управляете целевым сайтом, вы можете настроить скрипт получателя так:

1) установить ссылку iframe с styleпараметром, например:

http://your_site.com/target.php?color=red

(последняя фраза a{color:red} кодируется urlencodeфункцией.

2) установить страницу получателя target.phpтак:

<head>
..........
$col = FILTER_VAR(SANITIZE_STRING, $_GET['color']);
<style>.xyz{color: <?php echo (in_array( $col, ['red','yellow','green'])?  $col : "black") ;?> } </style>
..........

3
Предупреждение: это инъекция во всей красе.
— Кано

1
да, НЕ делайте этого, за исключением того, что вы хотите загрузить на свой сервер ботов-тест-ботов и скриптовых детишек =) ...
— кроме

1
Я обновил ответ сейчас, с добавленным предупреждением безопасности
— T.Todua

-18

Ну, я следовал за этими шагами:

  1. Div с классом для проведения iframe
  2. Добавьте iframeк div.
  3. В файле CSS
divClass { width: 500px; height: 500px; }
divClass iframe { width: 100%; height: 100%; }

Это работает в IE 6. Должно работать в других браузерах, проверьте!


9
нужно контролировать div внутри iframe, это не так
— MSD
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.