Как применить 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>

Удачи!

SequenceDigitale.com
источник
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, просто назовите ее со страниц, используемых там.

hangy
источник
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. Спасибо вам за ваши предложения!

domih
источник
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>
Збигнев Wiadro
источник
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);
2540625
источник
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();
Parham Fazel
источник
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>');

});
CodeRows
источник
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» в родительском окне.

jperelli
источник
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" }
     ));
K.Suthagar
источник
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>
Palanikumar
источник
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);

Jeeva
источник
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">'
});
karlisup
источник
1
Почему вы хотите это сделать?!
Дилан Уотсон
1

В качестве альтернативы вы можете использовать технологию CSS-in-JS, как показано ниже: lib:

https://github.com/cssobj/cssobj

Он может внедрить JS-объект как CSS в iframe, динамически

Джеймс Ян
источник
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>
..........
T.Todua
источник
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. Должно работать в других браузерах, проверьте!

JannuD
источник
9
нужно контролировать div внутри iframe, это не так
MSD