如何将CSS应用于iframe?


1016

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


66
这是可能的,但
前提

13
gawpertron,只是为了澄清一下,您是说如果我使用我无法控制的其他领域的iFrame内容,那么我无法控制该内容的CSS吗?
Ville M 2010年

您能否列出该页面的链接,以便我们仅能够查看我们的更改。

5
域,端口和协议必须相同,也不能与子域一起使用。
李·彭克曼

Answers:


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似乎仍然不适合我。
Rehno Lindeque 2011年

35
链接只能出现在HEAD
克伦民族联盟

18
仅在我工作时为我工作...document.head.appendChild(cssLink)-Firefox和Safari。
mojuba 2011年

24
这实际上可以跨域工作吗?我认为不会。
西蒙东

89
只是没有其他人必须对其进行测试才能发现:正确,它不能跨域工作。在执行frame ['name']后,您立即获得“不安全的JavaScript尝试从具有URL blah的框架访问具有URL blah的框架。域,协议和端口必须匹配。”
凯文

205

我在Google日历中遇到了这个问题。我想在深色背景上设置样式并更改字体。

幸运的是,嵌入代码中的URL对直接访问没有任何限制,因此通过使用PHP函数file_get_contents,可以从页面中获取全部内容。除了调用Google URL之外,还可以调用服务器上的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);

(这会将样式表放置在headend标记之前的最后。)

在相对调用css和js的情况下,从原始URL指定基本URL:

$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文档一起使用。它会引发各种JavaScript错误。“未捕获的TypeError:无法读取未定义的属性'a'”
deweydb 2014年

1
没关系,我想通了,在此发布的解决方案:stackoverflow.com/questions/25395279/...
deweydb

9
@ChrisHoughton仅供参考,基本上不是。但是,这可能会使整个iframe变得毫无意义(例如,使用iframe的一个原因是出于安全目的,例如使用卡付款,如果您按照此处的建议进行操作,很可能会导致自己出现问题)。
alastair

10
这样,您始终可以将日历作为未登录用户使用。使用普通的html iframe,如果用户登录google,则用户将看到他们自己的个人日历,但是由于您的PHP代码无法知道用户的Google会话ID,因此无法获取他们的个人日历。
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 2014年

我以前见过这个主意,但是添加了一个链接来提交其真正出色和专业的内容... +上
J.Tural 2015年

29

大多数浏览器普遍将iframe视为不同的HTML页面。如果要将相同的样式表应用于iframe的内容,只需从那里使用的页面引用它即可。


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
这是否需要ID为的iframe iframe
杰里米

1
@jmalais只需更换#iframe#<id>,甚至iframe选择所有iframe小号
奇布麦科克尔

3
这似乎不适用于我。我尝试编辑的iframe在dom中也没有直接位于其下方的位置。那么这是否意味着我需要访问html文档的头部,还是jquery find函数应该能够自己完成的事情?
David A. French

1
检查了控制台,由于域不匹配,它似乎已被阻止访问iframe内容。我正在使用chrome,目前在本地托管我的开发环境。
David A. French

未捕获的DOMException:阻止了具有原始点的帧,这给了我这个错误
priyanka patel

26

正如hangy所说,如果您在iframe中控制页面,最简单的方法是创建具有通用样式的共享CSS文件,然后从html页面链接到该文件。

否则,您不太可能能够从iframe中的外部页面动态更改页面的样式。这是因为浏览器已经加强了跨框架dom脚本的安全性,这可能是由于滥用欺骗和其他黑客行为造成的。

本教程一般而言,可为您提供有关编写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 2010年

1
@Tigran,这是dynamic data
Akash

13

如果要从主页重用CSS和JavaScript,则应考虑替换<IFRAME>为Ajax加载的内容。当搜索机器人能够执行JavaScript时,这对SEO更加友好了。

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

您也可以直接从Google包含jQuery:http : //code.google.com/apis/ajaxlibs/documentation/-这意味着可以选择自动包含较新的版本,并且可以显着提高速度。同样,这意味着您必须信任他们才能为您提供jQuery;)


1
应该注意的是,如果页面的内容以任何方式都是动态的,则此解决方案将不起作用。
nickdnk '16

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

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在窗口加载时尚未就绪,因此需要使用timer

即用型代码(带计时器):

<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()”时,它意味着您可以在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="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网址在所有位置都启用了CORS,该怎么办?
adrhc

6

您将无法以这种方式设置iframe的内容样式。我的建议是使用服务器端脚本(PHP,ASP或Perl脚本)或找到将提要转换为JavaScript代码的在线服务。唯一的其他方法是可以进行服务器端包含。


29
当您说无法做某事时要小心,而实际上
却很

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>');

});

4

由于针对相同的域编写了许多答案,因此我将编写如何在跨域中执行此操作。

首先,您需要了解Post Message API。我们需要使者在两个窗口之间进行通信。

这是我创建的Messenger。

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

它可能不是最好的解决方案,但肯定可以改进,但是如果您想在父窗口中保留“样式”标签,则这是另一种选择。


3

在这里,域内有两件事

  1. iFrame部分
  2. 页面已加载到iFrame中

因此,您希望按照以下方式设置这两部分的样式,

1. iFrame部分的样式

它可以使用具有该方面idclass名称的CSS样式。您也可以在父样式表中为其设置样式。

<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
这行不通。似乎正确插入了样式标签,但其中没有内容,也没有ID。
darylknight 2014年

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什么?
基兰库玛尔·达夫达,2013年

1
它的iframe的名字
Jeeva

我没有尝试过,但我想这不会因为它对着沙箱而产生
Jeeva

1

我认为最简单的方法是在与iframe相同的位置添加另一个div,然后

使其z-index比iframe容器大,因此您可以轻松设置自己的div样式。如果您需要单击它,只需pointer-events:none在自己的div上使用,这样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)使用style参数设置iframe链接,例如:

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
邑,不这样做,除非你想渗透测试机器人和脚本小子你的服务器= ON的负载)...
exside

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
需要iframe的控制DIV中,这不
MSD
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.