如何将CSS应用于iframe?

1204

我有一个简单的页面,其中包含一些iframe部分(用于显示RSS链接)。我如何将主页面的相同CSS格式应用于在iframe中显示的页面?


79
只有当 iframe 的域名与父级相同时才可能实现。 - gawpertron
14
gawpertron,我想澄清一下,你的意思是说如果我使用来自我无法控制的其他域的iFrame内容,那么我就无法控制该内容的CSS样式吗? - Ville M
你能列出一个链接给我们看看我们的更改吗? - user3376708
5
域名、端口和协议必须保持一致,子域名也不可用。 - lee penkman
28个回答

13

在上面的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();
});

12

如果你想重复使用主页面的CSS和JavaScript,也许你应该考虑将<IFRAME>替换为Ajax加载内容。当搜索机器人能够执行JavaScript时,这更有利于SEO。

这是一个jQuery示例,它将另一个HTML页面包含在文档中。这比iframe更有助于SEO。为了确保机器人不会索引所包含的页面,只需将其添加到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>

你还可以直接从Google引入jQuery:http://code.google.com/apis/ajaxlibs/documentation/ - 这意味着自动引入新版本的可选项以及一些显著的速度增加。不过这也意味着你需要信任他们只提供给你jQuery ;)


11

我的简化版

<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>

11

由于许多答案都是针对相同的域编写的,因此我将介绍如何在跨域中完成此操作。

首先,您需要了解Post Message 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
})

接着,从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教程以获取更多详细信息。


9

这里的其他答案似乎使用了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()”时,它意味着你可以在iframe中编写任何HTML标签,因此你应该编写HTML页面的所有基本标签,如果你想在iframe头部有一个CSS链接,只需在其中编写一个带有CSS链接的iframe。我给你举个例子:

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="/css/print.css"/></head><body><table id="' + gridId + 'Printable' + '" class="print" >' + out + '</table></body></html>');

doc.close();

6

您无法通过这种方式对iframe的内容进行样式设置。我的建议是使用服务器端脚本(PHP、ASP或Perl脚本)或查找在线服务,将源提供程序转换为JavaScript代码。另外一种方法是如果您可以进行服务器端包含。


31
当你说某事无法完成时,请小心,实际上可能只是难度较大。 - Lathan

4
如果您可以访问 iframe 页面并且想要在通过页面的 iframe 加载它时应用不同的 CSS,那么我找到了这种情况的解决方案。即使 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>');

});

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
我们可以将样式标签插入到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>

2
这个不起作用。似乎正确地插入了样式标签,但里面没有内容和ID。 - darylknight

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接