如何在Razor视图中包含内联CSS样式?

时间:2013-01-12 22:27:28

标签: asp.net-mvc razor asp.net-mvc-4 postal

我正在使用Postal呈现MVC Razor视图并通过电子邮件发送它们。我有一个我专门为电子邮件视图定义的自定义CSS。目前我将它们包括在内:

@Styles.Render("~/Content/EmailStyles.css")

但是,这只包括样式表的相对链接,这在电子邮件中不起作用:

<link href="/Content/EmailStyles.css" rel="stylesheet"/>

我希望将样式表内联,以便它在电子邮件中正常运行。在MVC视图中呈现基于文件的资源的内容的最佳方法是什么?

4 个答案:

答案 0 :(得分:33)

我自己也有同样的问题,遇到Premailer.Net。它看起来像你需要的库。这是你必须做的:

  1. 创建一个扩展方法,以帮助您将CSS嵌入到您的页面中;有an answer on a question on how to embed HTML in a Razor view可以帮助你。我修改了它 嵌入CSS:

    public static class HtmlHelpers
    {
        public static MvcHtmlString EmbedCss(this HtmlHelper htmlHelper, string path)
        {
            // take a path that starts with "~" and map it to the filesystem.
            var cssFilePath = HttpContext.Current.Server.MapPath(path);
            // load the contents of that file
            try
            {
                var cssText = System.IO.File.ReadAllText(cssFilePath);
                var styleElement = new TagBuilder("style");
                styleElement.InnerHtml = cssText;
                return MvcHtmlString.Create(styleElement.ToString());
            }
            catch (Exception ex)
            {
                // return nothing if we can't read the file for any reason
                return null;
            }
        }
    }
    
  2. 然后在您的Razor模板中,转到:

    @Html.EmbedCss("~/Content/EmailStyles.css")
    

    嵌入CSS文字。

  3. 在项目中安装Premailer.Net软件包;你可以通过NuGet获得它。

  4. 将您的Razor视图渲染成一个字符串(我想这就是您在过程中使用的邮件?我相信RazorEngine也可以这样做。)

  5. 通过Premailer.Net运行字符串:

    PreMailer pm = new PreMailer();
    string premailedOutput = pm.MoveCssInline(htmlSource, false);
    
  6. 以电子邮件方式发送!

  7. 我现在已经在生产中使用这种技术了一段时间,它看起来效果很好。

    编辑:请记住,伪元素上的样式无法内联,因为它们在标记中不存在。我也注意到Premailer.Net中的奇怪小错误 - 我认为它们的特异性和级联规则并不完全一致。尽管如此,它还是非常好的,而且还有一段我不必编写的代码!

答案 1 :(得分:9)

赞成Paul的回答,但是我发现他的帮助方法的这个版本对我来说工作得更好(不会尝试编写CSS中的引号之类的东西):< / p>

public static class CssHelper
{
  public static IHtmlString EmbedCss(this HtmlHelper htmlHelper, string path)
  {
    // take a path that starts with "~" and map it to the filesystem.
    var cssFilePath = HttpContext.Current.Server.MapPath(path);
    // load the contents of that file
    try
    {
      var cssText = File.ReadAllText(cssFilePath);
      return htmlHelper.Raw("<style>\n" + cssText + "\n</style>");
    }
    catch
    {
      // return nothing if we can't read the file for any reason
      return null;
    }
  }
}

答案 2 :(得分:0)

我想你需要有一个自定义助手。在我的头顶上,没有这样的方法来呈现css路径,包括网站的绝对路径。

e.g。 HTTP:www.example.com/css/EmailStyles.css

答案 3 :(得分:0)

我意识到这是一个老问题,但这里是 dprothero 答案的修改版本,它将嵌入捆绑包。 创建一个静态 C# 类并将此方法放入其中:

public static IHtmlString EmbedCss(this HtmlHelper htmlHelper, string path)
{
  try
  {
      // Get files from bundle
      StyleBundle b = (StyleBundle)BundleTable.Bundles.GetBundleFor("~/Content/css");
      BundleContext bc = new BundleContext(new HttpContextWrapper(HttpContext.Current), BundleTable.Bundles, "~/Content/css");
      List<BundleFile> files = b.EnumerateFiles(bc).ToList();
      // Create string to return
      string stylestring = "";
      // Iterate files in bundle
      foreach(BundleFile file in files)
      {
          // Get full path to file
          string filepath = HttpContext.Current.Server.MapPath(file.IncludedVirtualPath);
          // Read file text and append to style string
          string filetext = File.ReadAllText(filepath);
          stylestring += $"<!-- Style for {file.IncludedVirtualPath} -->\n<style>\n{filetext}\n</style>\n";
      }
      return htmlHelper.Raw(stylestring);
  }
  catch
  {
      // return nothing if we can't read the file for any reason
      return null;
  }

然后转到您想在其中使用它的任何视图。确保添加 using 语句,以便您的视图可以看到 CSS 助手。我还使用 TempData 来决定是否内联呈现它:

<!-- Using statement -->
@using Namespace.Helpers;

<!-- Check tempdata flag for whether or not to render inline -->
@if (TempData["inlinecss"] != null)
{
    <!-- Embed CSS with custom code -->
    @Html.EmbedCss("~/Content/css")
}
else
{
    <!-- Use links to reference CSS -->
    @Styles.Render("~/Content/css")
}