【问题标题】:How can I merge CSS definitions in files into inline style attributes, using Perl?如何使用 Perl 将文件中的 CSS 定义合并到内联样式属性中?
【发布时间】:2010-11-19 06:39:02
【问题描述】:

许多电子邮件客户端不喜欢链接的 CSS 样式表,甚至不喜欢嵌入的 <style> 标记,而是希望 CSS 内联显示为所有标记的样式属性。

  • 错误:<link rel=stylesheet type="text/css" href="/style.css">
  • 错误:<style type="text/css">...</style>
  • 作品:<h1 style="margin: 0">...</h1>

但是,这种内联样式属性方法管理起来很麻烦。

我找到了用于 Ruby 和 PHP 的工具,它们将 CSS 文件和一些单独的标记作为输入并返回合并结果 - 一个标记文件,所有 CSS 都转换为样式属性。

我正在寻找针对此问题的 Perl 解决方案,但我在 CPAN 上或通过 Google 搜索都没有找到。任何指针?或者,是否有 CPAN 模块可以组合起来达到相同的结果?

【问题讨论】:

  • @mintywalker 我发布的代码处理了我拥有的一堆文件,从有效的 HTML 生成了有效的 HTML,从有效的 CSS 生成了看似有效的 CSS。你试过了吗?很高兴能得到一些反馈。
  • @Sinan Ünür:是的-它确实可以运行并且非常接近,但是我注意到通过评论您的答案并不太正确-这是 CSS::DOM 问题,而不是您的问题。并且缺乏对 cme​​ts 的预览意味着评论被破坏了,但我认为你应该能够找出症结所在。非常感谢您的帮助,我将尝试使用 CSS::DOM,但我担心这里的复杂性可能超出我的能力。
  • HTML::TreeBuilderCSS 可能更容易。我正在做一些实验。
  • 为什么必须是 Perl?例如,你能用 Ruby 的东西来做一个单独的过程吗?
  • @brian d foy :一般来说,脱壳不会是一个大问题,除了我们会为每个用户生成大量电子邮件,因此脱壳的“成本”是对我们来说不是微不足道的。也许相对于进行 css 转换的成本不是很高,但仍然如此。

标签: html css perl parsing


【解决方案1】:

我不知道一个完整的、预先打包好的解决方案。

CSS::DOMcompute_style 与上面的 emogrifier 几乎相同。该模块与HTML::TokeParser 一起应该可以用来制作一些东西。

更新:这是一个错误的混搭:

#!/usr/bin/perl

use strict;
use warnings;

use CSS::DOM;
use File::Slurp;
use HTML::DOM;
use HTML::TokeParser;

die "convert html_file css_file" unless @ARGV == 2;
my ($html_file, $css_file) = @ARGV;

my $html_parser = HTML::TokeParser->new($html_file)
    or die "Cannot open '$html_file': $!";

my $sheet = CSS::DOM::parse( scalar read_file $css_file );

while ( my $token = $html_parser->get_token ) {
    my $type = $token->[0];
    my $text = $type eq 'T' ? $token->[1] : $token->[-1];
    if ( $type eq 'S' ) {
        unless ( skip( $token->[1] ) ) {
            $text = insert_computed_style($sheet, $token);
        }
    }
    print $text;
}

sub insert_computed_style {
    my ($sheet, $token) = @_;
    my ($tag, $attr, $attrseq) = @$token[1 .. 3];
    my $doc = HTML::DOM->new;

    my $element = $doc->createElement($tag);

    for my $attr_name ( @$attrseq ) {
        $element->setAttribute($attr_name, $attr->{$attr_name});
    }

    my $style = CSS::DOM::compute_style(
        element => $element, user_sheet => $sheet
    );

    my @attrseq = (style => grep { lc $_ ne 'style' } @$attrseq );
    $attr->{style} = $style->cssText;

    my $text .= join(" ",
        "<$tag",
        map{ qq/$_='$attr->{$_}'/ } @attrseq );
    $text .= '>';

    return $text;
}

sub skip {
    my ($tag) = @_;
    $tag = lc $tag;
    return 1 if $tag =~ /^(?:h(?:ead|tml)|link|meta|script|title)$/;
}

【讨论】:

  • 谢谢 - 这真是太棒了,虽然我认为 CSS::Dom 有一个错误/待办事项(看起来还是有点脆弱!),这有点浪费#foo {border-width : 2px } div {border: 1px dashed green } with html <div id=foo> ... </div>应该得到 style='border: 1px dashed green;边框宽度:2px;'但目前得到 style='border-width: 2px;边框:1px 虚线绿色'
  • @mintywalker 这是个问题。我查看了compute_style 的来源,但我不确定我现在能不能解决这个问题。一个笨拙的解决方法是更改​​ CSS 文件中的顺序: div {border: 1px dashed green } #foo {border-width: 8px } 但这在一般情况下并不实用。
  • 我将尝试使用 CSS::DOM - 就我的目的而言,发现并抛出异常比发出错误的东西要好,所以我想知道我是否可能至少能够在那个方向调整compute_style。如果我到达任何地方,我会在这里报告(根本无法保证!)再次 - 非常感谢,这是一个非常有帮助的开始。
【解决方案2】:

您可以使用 CPAN Perl 模块 CSS::Inliner https://metacpan.org/release/CSS-Inliner

【讨论】:

  • 我最近也遇到了这个问题。 CSS::Inliner 看起来正是我的工具。我想使用 CSS 规则保留我的模板,但在我发送电子邮件之前内联样式。感谢您的链接!
猜你喜欢
  • 2022-11-23
  • 1970-01-01
  • 2021-02-21
  • 2012-03-05
  • 1970-01-01
  • 1970-01-01
  • 2013-12-06
  • 2020-03-19
  • 2016-09-01
相关资源
最近更新 更多