我可以按需加载外部样式表吗?

48
$.getScript('ajax/test.js', function() {
  alert('Load was performed.');
});

类似上面的代码可以在请求时加载外部JS文件,是否有类似的方法可以在需要时加载外部CSS样式表呢?

比如当我在网站上使用轻量级弹出框时,我希望除非用户请求,否则不会在页面加载时就加载轻量级弹出框的JS和CSS文件。

谢谢

7个回答

70

没错:如果你创建一个链接到样式表的<link>标签,然后将其添加到<head>标签中,浏览器会加载该样式表。

例如:

$('head').append('<link rel="stylesheet" type="text/css" href="lightbox_stylesheet.css">');

然而根据@peteorpeter的评论,这在IE 8或更低版本中不起作用- 在那里,您需要:

  1. 在设置其href之前附加<link>;或者
  2. 使用IE的document.createStyleSheet()方法

此外,在所有浏览器上可靠地检查链接是否已添加是行不通的。

我还要质疑你观点的一部分:

我想避免在onload时加载lightbox JS和CSS文件,除非用户请求。

为什么?减少页面重量吗?我可以理解这种愿望,但是您应该测量带有lightbox代码时的CSS和JS文件的大小(经过最小化和gzip),以及没有它们时的大小,以确定减少是否值得:

  1. 按需加载的增加复杂性;和
  2. 轻盈相对较差的反应速度(因为在按需加载时,lightbox必须等待自己的CSS和JS加载完成才能正常工作)

最小化和gzip后,可能没有太大的区别。

请记住,您可以指示浏览器长时间缓存您的CSS和JS,这意味着只有在用户使用空缓存访问您的站点时才会下载它们。


4
会加载样式表,但不应该将link语句用$()括起来,而是应该使用lightbox_stylesheet = '<link ... />',然后.append()调用将完成所需操作。通常情况下,不要将任何不能包含在div中的内容都用jQuery对象包装起来。 - Doug Neiner
2
注意:使用 if('head link[href=foo]') 检查是否已经添加了 <link> 不可靠,因为受浏览器 DOM 限制的影响。 - peteorpeter
2
注意2:这在IE <= 8中不起作用。请参见此问答 - peteorpeter
@PaulD.Waite 我曾经与一个应用程序一起工作,其中子页面在对话框中打开...其中一些动态地引用了css文件...某个时刻我注意到有30个相同的样式表实例附加到了主页面上。不是最好的方法。但那是“特例”。 - Jeffz
@Jeffz:当然。不过这是否引起了实际问题呢?我猜可能会使 Web Inspector 视图有点不可用(每个元素被第 30 个覆盖的 29 个重复样式,哎呀)。 - Paul D. Waite
显示剩余4条评论

28
$('<link/>', {rel: 'stylesheet', href: 'myHref'}).appendTo('head');

我必须在触发额外的代码之前等待CSS加载完成。https://dev59.com/HF_Va4cB1Zd3GeqPPARz#8767297 - Matthew Lock

12

你可以这样做:

$('<link>').attr('rel','stylesheet')
  .attr('type','text/css')
  .attr('href','link_to.css')
  .appendTo('head');

1
@Reigel 我不确定在跨浏览器情况下它将如何工作。据我了解,当你调用 $(htmlString) 时,元素必须能够被包含在一个 div 中,直到它被添加到页面中。虽然 link 元素可以在 div 中,但这是无效的。例如,你不应该使用 $('<option>'),因为它只在 select 元素中有效。我认为这种方法在某些浏览器中实际上会失败,所以我想提出对这个方法的担忧。 - Doug Neiner
1
我认为过于担心JavaScript生成的HTML在添加到页面之前可能存储在哪里有点过分。用户永远不会看到那个,对吧? - Paul D. Waite
1
@DougNeiner,你的看法是错误的,4年过去了... jQuery(expression) 的作用是返回与表达式匹配的元素集合(数组)。表达式可以是选择器或 HTML 字符串。这些元素被存储在内存中作为文档片段,并且当你执行类似 var els = $('<img>'); 这样的操作时,它们会通过引用传递。 - qodeninja

5
你可以通过在头部添加动态HTML内容来添加外部样式表的引用:
$('head').append('<link rel="stylesheet" href="style.css" type="text/css" />');

这段内容会被插入到DOM中,并且随后会按照正常方式渲染,这种情况下会导致获取外部样式表。

但是请注意cletus的回答,如果您在动态加载静态内容时不小心,可能会导致页面加载时间过长和资源传输过度。


2

IE浏览器问题...

我在使用以下代码时导致IE 6、7、8浏览器崩溃:

$('head').append( $('<link rel="stylesheet" type="text/css" />').attr('href', 'assets/css/jquery.fancybox-1.3.4.css') );

只需将它们复制到主表中,以避免另一个 http 请求,就完成了。


1
我刚遇到了同样的问题(似乎是一个 3 年前的 jQuery bug),出现在 IE7/8 和 Windows XP 上... 添加一个空的 href 也可以解决崩溃问题,例如:$('<link rel="stylesheet" type="text/css" href=""/>').attr('href', 'assets/css/jquery.fancybox-1.3.4.css')。 - Shautieh

2

一般来说,最好假设你正确地包含了所有需要的内容。

我的意思是,对于静态内容(图像、Javascript、CSS),最佳实践是:

  • 最小化外部HTTP请求(最小化文件数量);
  • 对文件进行版本控制,并使用远期过期标头(far futures Expires header);
  • 根据需要进行代码压缩和内容压缩。

这样用户只需下载给定文件一次,直到它发生变化。

动态加载CSS和Javascript(除非它特别大),通常是不必要且适得其反的。


3
有时候这是必要的,例如,如果你正在编写一个小部件风格的插件,并且想要最小化将其集成到给定页面的难度。能够出售“一行代码集成”的能力可能是一个重要的区分因素。 - Ken Smith

0
我们可以直接通过追加来实现它。
$("head").append($("<link rel='stylesheet' href='style.css' type='text/css' media='screen' />"));

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