Як застосувати CSS до iframe?


1016

У мене проста сторінка, яка містить кілька розділів iframe (для відображення RSS-посилань). Як я можу застосувати той самий формат CSS з головної сторінки до сторінки, що відображається в iframe?


66
Це можливо, але лише в тому випадку, якщо домен iframe такий же, як і батьківський
gawpertron

13
gawpertron, просто для уточнення, ви хочете сказати, що якщо я використовую вміст iFrame з іншого домену, який я не контролюю, то для мене немає можливості контролювати CSS для цього вмісту?
Ville M

Чи можете ви перелічити посилання на сторінку, щоб ми могли просто переглянути наші зміни.

5
Домен, порт і протокол повинні бути однаковими, також не працює з піддоменами.
lee penkman

Відповіді:


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>

Стиль сторінки, вбудованої у рамку кадрів, повинен бути встановлений, включивши його в дочірню сторінку:

<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 все ще, здається, не працює для мене.
Rehno Lindeque

35
посилання може з’являтися лише в
ГЛАВНІ

18
Працювали для мене лише тоді, коли я ...document.head.appendChild(cssLink)- Firefox та Safari.
mojuba

24
Це насправді працює міждоменним? Я не думаю, що це буде.
Simon East

89
Просто так ніхто інший не повинен перевірити це, щоб з’ясувати: правильно, він не працює між доменом. Одразу після виконання фреймів ['name'] ви отримуєте "Небезпечний спробу JavaScript отримати доступ до кадру з URL blah з фрейму з URL blah. Домени, протоколи та порти повинні збігатися."
Кевін

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' of undefined"
deweydb

1
Nevermind, я зрозумів це, відправив рішення тут: stackoverflow.com/questions/25395279 / ...
deweydb

9
@ChrisHoughton FYI, це в основному не так. Однак це може призвести до безглуздості всього iframe (одна з причин використання iframe, наприклад, для цілей безпеки, наприклад, за допомогою платежів карткою, і якщо ви зробите те, що пропонується тут, ви, ймовірно, викличете собі проблеми).
аластер

10
Цим ви завжди отримуєте календар як користувач, який не входить в систему. Зі звичайним HTML-програмою iframe користувач побачив би свій особистий календар, якби увійшов у google, але оскільки ваш PHP-код не може знати користувачів ідентифікатора сесії Google, він не може отримати їх особистий календар.
bdsl

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. Якщо ви хочете застосувати ту саму таблицю стилів до вмісту рамки кадрів, просто посилайтеся на неї зі сторінок, які використовуються там.


22
@hangry але ... як?
Дитина Божа

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?
Джеремі

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

3
Це, здається, не працює для мене. У iframe, який я намагаюсь відредагувати, також немає голови прямо під ним у домі. Так це означає, що мені потрібно звернутися до голови всередині html-документа або це те, що функція пошуку jquery повинна бути спроможна зробити сама?
Девід А. Французький

1
Перевірив консоль і схоже, що їй було заборонено доступ до вмісту iframe через невідповідність домену. Зараз я використовую хром і розміщую своє середовище розробників локально.
Девід А. Французький

Uncaught DOMException: Заблокований кадр з початковим кодом, він дає мені цю помилку
priyanka patel

26

Якщо ви керуєте сторінкою в iframe, як це було сказано в повітрі, найпростішим підходом є створення спільного CSS-файлу із загальними стилями, а потім просто посилання на нього зі своїх html-сторінок.

Інакше навряд чи ви зможете динамічно змінити стиль сторінки із зовнішньої сторінки у вашому iframe. Це пов’язано з тим, що браузери посилили захист сценаріїв перехресних кадрів у зв'язку з можливим неправомірним використанням підробки та іншими хаками.

Цей підручник може надати вам більше інформації про сценарії кадрів iframe взагалі. Про сценарії між кадрів пояснюються обмеження безпеки з точки зору 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
Що таке myData та звідки вона походить
Tigran

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 для всіх локацій?
adrhc

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 повідомлення на повідомлення . Нам потрібен месенджер для спілкування між двома вікнами.

Ось месенджер, який я створив.

/**
 * 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
})

Потім отримайте подію від Іфрейму.

У Іфреймі:

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)

<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, там же, як і рамка

зробіть його z-indexбільше, ніж контейнер iframe, так що ви можете легко просто створити свій власний дів. Якщо вам потрібно натиснути на нього, просто скористайтеся pointer-events:noneсвоїм власним дівом, щоб iframe працював у випадку, якщо вам потрібно натиснути на нього;)

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


1

Існує чудовий сценарій, який замінює вузол версією iframe себе. Демонстрація CodePen

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

Приклади використання:

// 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
Зараз я оновив відповідь, додавши попередження про безпеку
Т.Тодуа

-18

Ну, я дотримувався цих кроків:

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

Це працює в IE 6. Якщо працювати в інших браузерах, перевірте!


9
потрібно контролювати діви всередині iframe, це не так
MSD
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.