针对 IE 4096 选择器/样式表限制的 Rails 资产管道解决方案
Posted
技术标签:
【中文标题】针对 IE 4096 选择器/样式表限制的 Rails 资产管道解决方案【英文标题】:Rails asset pipeline solution for IE 4096 selector/stylesheet limit 【发布时间】:2012-08-21 00:06:50 【问题描述】:问题
Microsoft's IE support documentation 解释说在 Internet Explorer 6-9 中:
前 31 个样式标记之后的所有样式标记均未应用。 不应用前 4,095 条规则之后的所有样式规则。 在使用@import 规则持续导入外部样式表的页面上,导入其他样式表的样式表深度超过三层的样式表将被忽略。
script demos 有很多证据表明这个问题。另见Bless。
需要解决方案
我们需要一种方法来拆分资产管道中由 Sprockets 生成的编译样式表,以保持最大选择器计数低于 4096,并在已部署 Rails 应用程序的 html 中链接到它们。 我们如何将已处理资产(特别是样式表)的编译输出作为参数传递给可以修改文件的方法?
请参阅以下尝试以了解起点。如果有人可以帮助我找到一种方法来使这两种方法都可以运行(或全新的解决方案),那就太好了!
现有的解决方案尝试
Bless 是为了解决这个问题而创建的,它通过拆分样式表以将每张表的最大选择器计数保持在限制之下。 Bless 在 node.js 中的服务器上运行。我还没有看到一个 Ruby 等效的。 Eric Fields 尝试serve assets compiled with compass to Bless(在节点中运行),但该解决方案依赖于 Compass 处理资产编译,因此似乎不适用于资产管道。 请注意,Bless 不是链接到多个样式表,而是在第一个表中添加 @include
语句,这可能是避免接触标记的方法。
当 Christian Peters (@crispy) discovered this problem 时,他 implemented a splitter 喜欢 Bless,它也将 Compass 输出传递给自定义模块,这在 Rails 3.1 之前工作得很好。后来他adapted his splitter with a SprocketsEngine for integration with the Rails Asset pipeline。我已尝试实现新代码,但它似乎无法自动运行(尽管在控制台中手动调用拆分器时工作正常)。
相关信息
有关 IE 6-9 中的 CSS 限制的更多信息,请参阅以下相关问题:
Does IE 8 have a limit on number of stylesheets per page? Internet Explorer's CSS rules limits【问题讨论】:
值得指出的是,虽然如此大量的 CSS 在 IE 中可能会完全崩溃,但要发送到 any 浏览器的代码很多,并且可能是全面的绩效影响。您可能需要考虑如何优化它。有了这么多代码,很可能有一些重要的优化机会。 【参考方案1】:我在生产中使用的解决方案非常简单,不是自动化的,但效果很好。 对我来说,这是显而易见的事情,所以也许你已经考虑过了但不喜欢它——不管怎样,我们开始吧:
我假设你正在使用 sass,如果没有,我认为你应该:)
首先,将您的 application.css.scss
拆分为单独的文件,例如:
application_a.css.scss
和 application_b.css.scss
第二,在您的 application.css.scss
文件中,使用:
@import "application_a"
@import "application_b"
第三,在您的布局模板中,包含完整文件或两个部分:
<!--[if !IE]><!-->
# link to application.css.scss
<!--<![endif]-->
<!--[if IE]>
# link to application_a.css.scss
# link to application_b.css.scss
<![endif]-->
旁注:
不要通过资产管道生成样式表清单文件,通过 sass 和 @import
语句来生成,其他一切都会导致问题。
【讨论】:
似乎将 CSS_splitter 库作为预处理器可以解决问题,但该函数 has yet to be implemented with the Rails asset pipeline(当前读取为 'TODO')。【参考方案2】:我们有一个自动化的(尽管有点尴尬)解决方案在生产中用于具有资产管道的 Rails 3.1 应用程序。 Ryan 已经在他的问题中引用了该解决方案,但我尝试提出更全面的答案。
资产管道通过不同的 Sprocket 引擎对资产进行管道传输。
所以你可能有例如一个ie.css.sass.erb
,它通过ERB Sprocket引擎运行,然后传递给Sass Sprocket引擎等。但它始终是一个文件输入和一个文件输出。
在这个特殊的问题中,我们希望有 1 个入站文件和 n 个出站文件。 我们还没有找到使用链轮实现这一点的方法。但我们找到了解决方法:
提供一个包含完整样式表的 ie.css.sass
和一个仅导入完整 ie.css 文件的 ie_portion2.css.sass.split2
:
//= include 'ie.css'
对于 split2
文件扩展名,我们注册了一个 Sprockets 引擎:
require 'css_splitter'
Rails.application.assets.register_engine '.split2', CssSplitter::SprocketsEngine
在使用 split2 扩展评估资产时,我们将其内容传递给 CssSplitter 并指示它提取第 2 部分(> 4095 个选择器):
require 'tilt'
module CssSplitter
class SprocketsEngine < Tilt::Template
def self.engine_initialized?
true
end
def prepare
end
def evaluate(scope, locals, &block)
part = scope.pathname.extname =~ /(\d+)$/ && $1 || 0
CssSplitter.split_string data, part.to_i
end
end
end
这也适用于其他部分(split3,...)。
The CSS Splitter 识别可以将样式表拆分为少于 4096 个选择器的部分的有效位置并返回请求的部分。
结果是一个 ie_portion2.css,您必须在头部链接并单独预编译。
我希望我修改后的CSS Splitter Gist 足够完整,可以使用该解决方案。
更新:
上面提到的 CssSplitter 现已作为 gem 发布:https://github.com/zweilove/css_splitter
【讨论】:
以上是关于针对 IE 4096 选择器/样式表限制的 Rails 资产管道解决方案的主要内容,如果未能解决你的问题,请参考以下文章