当使用Rails资产管道时如何内联CSS

27

我想让CSS样式直接嵌入到页面中,而不是通过在页面中包含一个链接的方式引用CSS样式表,这样我可以使用Rails的stylesheet_link_tag帮助方法将其添加到我的视图中。

目前我想到了以下解决方案:

%style(type="text/css")=File.read(physical_asset_path("email.css"))

我找不到任何Rails的帮助方法可以给出资产的物理路径 - physical_asset_path只是我自己发明的虚拟方法。

有人知道如何在使用Rails 3.2.x时获取资源的物理路径吗?

是否有更容易/更好的方法来内联获取样式表 - 来自常见Rails资产路径内的css文件?

用例:大多数电子邮件客户端在未经确认用户的情况下不会访问外部资源(如css、图片)。因此,为了正确显示电子邮件,我需要将CSS嵌入到电子邮件的HTML中。

9个回答

63

Rails.application.assets.find_asset('email').to_s会返回编译后的资源字符串。


2
很遗憾,该资产将不会被压缩。 - haimg
17
可以这样做!但必须加上 .html_safe 以避免引号被转义:Rails.application.assets.find_asset('email').to_s.html_safe - hsgubert
这就是缺失的链接 - 通过在电子邮件.html.haml文件的头部使用%style{type:"text/css"}= Rails.application.assets.find_asset('email_stylesheet').to_s以及premailer-rails gem,CSS被找到、编译和内联 - 耶!工作的HTML电子邮件! - Troy
如果您正在使用这种技术与Roadie一起使用,您仍然需要告诉Roadie忽略它:%style{:type => "text/css", :'data-roadie-ignore' => true} = Rails.application.assets['email'].to_s.html_safe - philoye
2
很遗憾,在生产环境中Rails.application.assets is nil... - Halil Özgür
3
在生产环境中:File.read("#{Rails.root}/public/assets/#{Rails.application.assets_manifest.files.collect{|k, v| k if v['logical_path'] == 'email.css' }.compact.first}").html_safe 的意思是读取名为 email.css 的文件并将其作为 HTML 代码呈现。其中的 Rails.root 是指 Rails 应用程序的根目录,Rails.application.assets_manifest 则是 assets pipeline 中的清单文件。 - lee

15
使用premailer或premailer-rails3 https://github.com/fphilipe/premailer-rails3https://github.com/alexdunae/premailer Joe's Nerd Party说:
我们还使用了Premailer gem自动将电子邮件视图中的链接样式表内联。我们的电子邮件布局类似于:
%html
  %head
    = stylesheet_link_tag 'email'

    %style{:type => "text/css"}
      :sass
        @media all and (max-width: 480px)
          table#container
            width: auto !important
            max-width: 600px !important
         ... and so on for the mobile code

    %body 
      Email body here.
      %table
        Lots of tables.

我们在HTML中包含了一个样式表。Premailer下载并处理它,将CSS规则内联插入到HTML中。 @media规则需要内联在电子邮件布局中,因为Premailer无法处理它们在单独的CSS文件中。 我们使用premailer-rails3将Premailer集成到Rails 3中。不幸的是,我们发现premailer和premailer-rails3中有很多bug。我们在https://github.com/joevandyk/premailerhttps://github.com/joevandyk/premailer-rails3上维护这些项目的分支。这些分支修复了一些编码错误,删除了premailer-rails3执行的一些奇怪的CSS处理内容,允许premailer不删除电子邮件布局中的嵌入式规则,以及其他一些内容。 我们还发现了sass-rails中的一个bug,在内联sass代码中无法嵌入image-urls。请参见https://github.com/rails/sass-rails/issues/71。当电子邮件实际发送时,Premailer-rails3会钩入ActionMailer,而不仅仅是生成邮件。在运行测试时,电子邮件实际上没有被发送,因此premailer-rails3钩子在测试期间不会运行。我没有花时间去看是否可能在测试期间运行premailer处理,但这将是一件好事。 此外,我们在premailer-rails3上的分支假定您希望premailer实际上下载链接的CSS文件。可以使用Rails 3.1资源管道获得处理后的CSS,而无需下载它。特别感谢Jordan Isip,他完成了确保在所有不同的客户端中电子邮件看起来很棒的超级繁琐的工作。编写CSS/HTML看起来并不好玩。

更新:

Roadie 似乎是更好的选择。感谢 Seth Bro 指出。


1
你的分支对我无效,所以最终我创建了自己的分支并改变了方法:https://github.com/phuongnd08/premailer-rails3/ - Phương Nguyễn
我在长期使用中更喜欢 Roadie。最后一次检查(几年前)时,premailer-rails 有一些小问题。 - Seth Bro
@SethBro,Roadie 看起来是一个干净的解决方案。 - Sully
将样式内联到元素中(Roadie和Premailer都做得很好)确实会使样式不具有响应性,因为内联样式始终具有更高的优先级。在我看来。 - Torsten

11
< p > (抱歉,这个答案是用html而不是HAML编写的...但这对HAML粉丝来说不应该是问题)

我在寻找一种将作为css编译的Sass嵌入html以创建html电子邮件模板的方法时发现了这个问题。

结合以上建议,我在我的html页面的head中使用了以下代码:

<style type="text/css">
  <%= Rails.application.assets['path/to/sass/file'].to_s.html_safe %>
</style>

这段代码将Sass编译为CSS,并将CSS插入到<style>标签中。 html_safe 确保CSS中使用的任何引号('")或尖括号(><)不会被转义。

path/to/sass/file与创建样式表链接标记时使用的路径相同:

<%= stylesheet_link_tag 'path/to/sass/file', :media => 'all' %>

9

Rails.application.assets['asset.js'] 只能在本地环境中使用,因为在生产和预发布环境中,Rails资产编译被禁用。

Rails.application.assets_manifest.find_sources('asset.js').first.to_s.html_safe 应该在使用 Rails 资产管道时用于嵌入 CSS。


真正在生产中可用的只有这个。除非更喜欢premailer/roadie,但是那些无法响应。 - Torsten

5
无法给Seth Bro的回答添加评论。最好使用#[]代替#find_assetRails.application.assets ["email"] .to_s
关于“资产不会被压缩”的问题,这是不正确的。如果启用了压缩器(在Rails配置中),它将被压缩:
Rails.application.configure do
  # ...
  config.assets.css_compressor = :sass
  config.assets.js_compressor  = :uglify
end

请注意,默认情况下,在生产环境中启用此功能(config/environments/production.rb)。

你能举个你所说的压缩器的例子吗?我无法将其压缩。 - Jason
添加了一个示例以回复。 - ixti
在生产环境中似乎无法工作。有什么解决方法吗?那里的资产似乎为空。 - Jeffrey Basurto

4

我曾遇到相同问题,采用了@phlegx在Premailer的类似问题中提供的解决方法(@phlegx's answer)解决了这个问题。

如果您需要一个安全的解决方案,请使用以下代码:

(Rails.application.assets || ::Sprockets::Railtie.build_environment(Rails.application)).find_asset('email.css').to_s

我已将其打包成我的应用程序中的一个助手:

# app/helpers/application_helper.rb
# Returns the contents of the compiled asset (CSS, JS, etc) or an empty string
def asset_body(name)
   (Rails.application.assets || ::Sprockets::Railtie.build_environment(Rails.application)).find_asset(name).to_s
end

3

我正在尝试为Rails中与Google AMP兼容的页面内联CSS。我发现了来自vyachkonovalov的以下助手,这是在生产环境和本地环境中唯一适用于我的内容。

将以下内容添加到erb模板中:

<style amp-custom>
  <%= asset_to_string('application.css').html_safe %>
</style>

还有一个辅助类ApplicationHelper。在本地和生产环境中都能完美运行。

module ApplicationHelper
  def asset_to_string(name)
    app = Rails.application
    if Rails.configuration.assets.compile
      app.assets.find_asset(name).to_s
    else
      controller.view_context.render(file: File.join('public/assets', app.assets_manifest.assets[name]))
    end
  end

1
简化版(不使用Roadie):
%style(type="text/css")
  = render template: '../assets/stylesheets/email_responsive.css'

如果要将CSS作为内联样式实际应用,我建议使用roadie-rails(它是Roadie的Rails封装器)。它还具有其他很棒的功能,如绝对化hrefsrc等。

结合内联(email.scss)和非内联(email_responsive.css)样式表的用法,两者都位于app/assets/stylesheets中:

-# This will be inlined and applied to HTML elements.
-# Note that you need to include this in your asset config, e.g.:
-# Rails.application.config.assets.precompile += %w(... email.css)
-# (You need to list it as `email.css` even if it's actually `email.scss`.)

= stylesheet_link_tag 'email'


-# E.g. for media queries which can't be inlined - yeah, some iOS devices support them.
-# This will not be inlined and will be included as is (thanks to `data-roadie-ignore`).
-# `template:` marks it as a full template rather than a partial and disables `_` prefix.
-# We need to add the extension (`.css`) since it's non-standard for a view.

%style(type="text/css" data-roadie-ignore)
  = render template: '../assets/stylesheets/email_responsive.css'

0

您可以使用这个:

Rails.root.join('public', ActionController::Base.helpers.asset_path("email.css")[1..-1]).read.html_safe

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