2009-08-13 13 views
8

A muchos clientes de correo electrónico no les gustan las hojas de estilo CSS vinculadas, o incluso la etiqueta <style> incrustada, sino que desean que el CSS aparezca en línea como atributos de estilo en todas sus marcas.¿Cómo puedo fusionar las definiciones de CSS en archivos en atributos de estilo en línea, usando Perl?

  • MALO: <link rel=stylesheet type="text/css" href="/style.css">
  • malo: <style type="text/css">...</style>
  • funciona: <h1 style="margin: 0">...</h1>

Sin embargo este enfoque atributo de estilo en línea es un dolor derecho de administrar.

He encontrado herramientas para Ruby y PHP que tomarán un archivo CSS y un marcado separado como entrada y te devolverán el resultado combinado: un único archivo de marcado con todos los CSS convertidos en atributos de estilo.

Estoy buscando una solución Perl para este problema, pero no he encontrado ninguna en CPAN o buscando en Google. ¿Alguna sugerencia? Alternativamente, ¿hay módulos de CPAN que uno pueda combinar para lograr el mismo resultado?

+0

@mintywalker El código que he publicado trabajado en un montón de archivos que tenía, produce válida HTML de HTML válido y CSS válido válido de CSS válido. ¿Lo has probado? Sería genial tener algunos comentarios. –

+0

@Sinan Ünür: sí - ciertamente se ejecuta y se acerca bastante, pero noté algo que no está yendo del todo bien al comentar tu respuesta: es un problema CSS :: DOM, no es lo tuyo. Y la falta de una vista previa de los comentarios significa que el comentario quedó destrozado, pero creo que deberías ser capaz de descubrir el enigma. Muchas gracias por su ayuda, voy a jugar con CSS :: DOM, pero me temo que la complejidad puede estar más allá de mí aquí. – mintywalker

+0

Podría ser más fácil 'HTML :: TreeBuilder' y' CSS'. Estoy experimentando un poco. –

Respuesta

10

No conozco una solución completa y preempaquetada.

CSS::DOM 's compute_style está sujeto a más o menos las mismas advertencias que emogrifier anteriormente. Ese módulo, junto con HTML::TokeParser debe ser útil para cocinar algo.

Actualización: Aquí es un buggy batiburrillo de cosas:

#!/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)$/; 
} 
+0

Gracias - eso es bastante sorprendente, aunque creo que hay un error/todo con CSS :: Dom (que se ve un poco frágil aún) que saltea las cosas un poco #foo {border-width: 2px} div {border: 1px discontinua verde} con el html < div id = foo > ... </div > debe obtener style = 'border: 1px discontinua verde; ancho del borde: 2px; ' pero actualmente obtiene style = 'border-width: 2px; borde: 1px verde discontinuo ' – mintywalker

+0

@mintywalker Eso es un problema. Miré la fuente de 'compute_style' y no estoy seguro de poder arreglar eso ahora. Un arreglo kludgy es cambiar el orden en el archivo CSS: div {border: 1px dashed green} #foo {border-width: 8px} pero eso no es práctico en el caso general. –

+0

Voy a jugar con CSS :: DOM - para mis propósitos, detectar y lanzar una excepción sería mejor que emitir algo que estaba mal, así que me pregunto si podría modificar el estilo de cálculo en esa dirección al menos. Informaré aquí si llego a algún lado (¡lo cual no está garantizado en absoluto!) Nuevamente, muchas gracias, es un comienzo muy útil. – mintywalker

4

Usted puede utilizar CSS::Inlinerhttp://search.cpan.org/dist/CSS-Inliner/

+0

Recientemente me encontré con este problema también. CSS :: Inliner parece exactamente la herramienta para mí. Quiero mantener mis plantillas usando reglas CSS, pero alinear los estilos justo antes de enviar el correo electrónico. Gracias por el enlace! –

Cuestiones relacionadas