n. e•mog•ri•fi•er [ē-'mä-grƏ-,fī-Ər] - um utilitário para mudar completamente a natureza ou aparência do e-mail HTML, esp. de uma maneira particularmente fantástica ou bizarra
O Emogrifier converte estilos CSS em atributos de estilo embutidos em seu código HTML. Isso garante a exibição adequada em leitores de e-mail e dispositivos móveis que não possuem suporte para folhas de estilo.
Este utilitário foi desenvolvido como parte do Intervals para lidar com os problemas colocados por certos clientes de e-mail (nomeadamente Outlook 2007 e GoogleMail) no que diz respeito à forma como lidam com o estilo contido em e-mails HTML. Como muitos desenvolvedores e designers web já sabem, certos clientes de e-mail são notórios pela falta de suporte CSS. Embora estejam sendo feitas tentativas para desenvolver padrões comuns de e-mail, a implementação ainda está distante.
O principal problema com clientes de e-mail não cooperativos é que a maioria tende a considerar apenas CSS in-line, descartando todos os elementos <style>
e links para folhas de estilo em elementos <link>
. O Emogrifier resolve esse problema convertendo estilos CSS em atributos de estilo embutidos em seu código HTML.
O Emogrifier transmogrifica automaticamente seu HTML analisando seu CSS e inserindo suas definições de CSS em tags dentro de seu HTML com base em seus seletores de CSS.
Para instalar o emogrificador, adicione pelago/emogrifier
à seção require
no composer.json
do seu projeto ou você pode usar o compositor conforme abaixo:
composer require pelago/emogrifier
Consulte https://getcomposer.org/ para obter mais informações e documentação.
A maneira mais básica de usar a classe CssInliner
é criar uma instância com o HTML original, incorporar o CSS externo e então recuperar o HTML resultante:
use Pelago Emogrifier CssInliner ;
…
$ visualHtml = CssInliner:: fromHtml ( $ html )-> inlineCss ( $ css )-> render ();
Se não houver nenhum arquivo CSS externo e todo o CSS estiver localizado nos elementos <style>
do HTML, você poderá omitir o parâmetro $css
:
$ visualHtml = CssInliner:: fromHtml ( $ html )-> inlineCss ()-> render ();
Se quiser recuperar apenas o conteúdo do elemento <body>
em vez do documento HTML completo, você pode usar o método renderBodyContent
:
$ bodyContent = $ visualHtml = CssInliner:: fromHtml ( $ html )-> inlineCss ()
-> renderBodyContent ();
Se desejar modificar o processo de inlining com qualquer uma das opções disponíveis, você precisará chamar os métodos correspondentes antes de inlining o CSS. O código então ficaria assim:
$ visualHtml = CssInliner:: fromHtml ( $ html )-> disableStyleBlocksParsing ()
-> inlineCss ( $ css )-> render ();
Existem também algumas outras classes de processamento de HTML disponíveis (todas subclasses de AbstractHtmlProcessor
) que você pode usar para alterar ainda mais o HTML após incorporar o CSS. (Para mais detalhes sobre as classes, dê uma olhada nas seções abaixo.) CssInliner
e todas as classes de processamento HTML podem compartilhar a mesma instância DOMDocument
para trabalhar:
use Pelago Emogrifier CssInliner ;
use Pelago Emogrifier HtmlProcessor CssToAttributeConverter ;
use Pelago Emogrifier HtmlProcessor HtmlPruner ;
…
$ cssInliner = CssInliner:: fromHtml ( $ html )-> inlineCss ( $ css );
$ domDocument = $ cssInliner -> getDomDocument ();
HtmlPruner:: fromDomDocument ( $ domDocument )-> removeElementsWithDisplayNone ()
-> removeRedundantClassesAfterCssInlined ( $ cssInliner );
$ finalHtml = CssToAttributeConverter:: fromDomDocument ( $ domDocument )
-> convertCssToVisualAttributes ()-> render ();
A classe HtmlNormalizer
normaliza o HTML fornecido das seguintes maneiras:
A classe pode ser usada assim:
use Pelago Emogrifier HtmlProcessor HtmlNormalizer ;
…
$ cleanHtml = HtmlNormalizer:: fromHtml ( $ rawHtml )-> render ();
O CssToAttributeConverter
converte alguns valores de atributos de estilo em atributos HTML visuais. Isso permite obter pelo menos um pouco de estilo visual para clientes de e-mail que não suportam bem CSS. Por exemplo, style="width: 100px"
será convertido em width="100"
.
A classe pode ser usada assim:
use Pelago Emogrifier HtmlProcessor CssToAttributeConverter ;
…
$ visualHtml = CssToAttributeConverter:: fromHtml ( $ rawHtml )
-> convertCssToVisualAttributes ()-> render ();
Você também pode fazer com que o CssToAttributeConverter
funcione em um DOMDocument
:
$ visualHtml = CssToAttributeConverter:: fromDomDocument ( $ domDocument )
-> convertCssToVisualAttributes ()-> render ();
A classe CssVariableEvaluator
pode ser usada para aplicar os valores de variáveis CSS definidas em atributos de estilo embutido às propriedades de estilo embutido que os utilizam.
Por exemplo, o CSS a seguir define e usa uma propriedade customizada:
: root {
--text-color : green;
}
p {
color : var ( --text-color );
}
Depois que CssInliner
incorporou esse CSS no HTML (artificial) <html><body><p></p></body></html>
, ficará assim:
< html style =" --text-color: green; " >
< body >
< p style =" color: var(--text-color); " >
< p >
</ body >
</ html >
O método CssVariableEvaluator
evaluateVariables
aplicará o valor de --text-color
para que o atributo style
de parágrafo se torne color: green;
.
Pode ser usado assim:
use Pelago Emogrifier HtmlProcessor CssVariableEvaluator ;
…
$ evaluatedHtml = CssVariableEvaluator:: fromHtml ( $ html )
-> evaluateVariables ()-> render ();
Você também pode fazer com que o CssVariableEvaluator
funcione em um DOMDocument
:
$ evaluatedHtml = CssVariableEvaluator:: fromDomDocument ( $ domDocument )
-> evaluateVariables ()-> render ();
A classe HtmlPruner
pode reduzir o tamanho do HTML removendo elementos com uma declaração de estilo display: none
e/ou removendo classes de atributos class
que não são necessários.
Pode ser usado assim:
use Pelago Emogrifier HtmlProcessor HtmlPruner ;
…
$ prunedHtml = HtmlPruner:: fromHtml ( $ html )-> removeElementsWithDisplayNone ()
-> removeRedundantClasses ( $ classesToKeep )-> render ();
O método removeRedundantClasses
aceita uma lista de permissões de nomes de classes que devem ser retidas. Se esta for uma etapa de pós-processamento após a incorporação do CSS, você pode alternativamente usar removeRedundantClassesAfterCssInlined
, passando a instância CssInliner
que incorporou o CSS (e fazendo com que o HtmlPruner
funcione no DOMDocument
). Isso usará informações do CssInliner
para determinar quais classes ainda são necessárias (ou seja, aquelas usadas em regras não inlináveis que foram copiadas para um elemento <style>
):
$ prunedHtml = HtmlPruner:: fromDomDocument ( $ cssInliner -> getDomDocument ())
-> removeElementsWithDisplayNone ()
-> removeRedundantClassesAfterCssInlined ( $ cssInliner )-> render ();
O método removeElementsWithDisplayNone
não removerá nenhum elemento que possua a classe -emogrifier-keep
. Portanto, se, por exemplo, houver elementos que, por padrão, tenham display: none
, mas sejam revelados por uma regra @media
, ou que sejam destinados a um pré-cabeçalho, você poderá adicionar essa classe a esses elementos. O parágrafo neste snippet HTML não será removido mesmo que tenha display: none
(que presumivelmente foi aplicado por CssInliner::inlineCss()
a partir de uma regra CSS .preheader { display: none; }
):
< p class =" preheader -emogrifier-keep " style =" display: none; " >
Hello World!
</ p >
O método removeRedundantClassesAfterCssInlined
(ou removeRedundantClasses
), se invocado após removeElementsWithDisplayNone
, removerá a classe -emogrifier-keep
.
Existem diversas opções que você pode definir na instância CssInliner
antes de chamar o método inlineCss
:
->disableStyleBlocksParsing()
- Por padrão, CssInliner
irá capturar todos os blocos <style>
no HTML e aplicará os estilos CSS como atributos de "estilo" embutidos no HTML. Os blocos <style>
serão então removidos do HTML. Se você deseja desabilitar esta funcionalidade para que CssInliner
deixe esses blocos <style>
no HTML e não os analise, você deve usar esta opção. Se você usar esta opção, o conteúdo dos blocos <style>
não será aplicado como estilos embutidos e qualquer CSS que você queira que CssInliner
use deverá ser passado conforme descrito na seção Uso acima.->disableInlineStyleAttributesParsing()
- Por padrão, CssInliner
preserva todos os atributos de "estilo" nas tags do HTML que você passa para ele. No entanto, se quiser descartar todos os estilos embutidos existentes no HTML antes da aplicação do CSS, você deve usar esta opção.->addAllowedMediaType(string $mediaName)
- Por padrão, CssInliner
manterá apenas os tipos de mídia all
, screen
e print
. Se quiser manter alguns outros, você pode usar este método para defini-los.->removeAllowedMediaType(string $mediaName)
- Você pode usar este método para remover tipos de mídia que o Emogrifier mantém.->addExcludedSelector(string $selector)
- Evita que os elementos sejam afetados pelo inlining CSS. Observe que apenas os elementos que correspondem ao(s) seletor(es) fornecido(s) serão excluídos do inlining CSS, não necessariamente seus descendentes. Se você deseja excluir uma subárvore inteira, você deve fornecer seletores que corresponderão a todos os elementos da subárvore, por exemplo, usando o seletor universal: $ cssInliner -> addExcludedSelector ( ' .message-preview ' );
$ cssInliner -> addExcludedSelector ( ' .message-preview * ' );
->addExcludedCssSelector(string $selector)
- Ao contrário de addExcludedSelector
, que exclui nós HTML, este método exclui seletores CSS de serem embutidos. Isso é útil, por exemplo, se você não deseja que suas regras de redefinição de CSS sejam incorporadas em cada nó HTML (por exemplo, * { margin: 0; padding: 0; font-size: 100% }
). Observe que esses seletores devem corresponder exatamente aos seletores que você deseja excluir. O que significa que excluir .example
não excluirá p .example
. $ cssInliner -> addExcludedCssSelector ( ' * ' );
$ cssInliner -> addExcludedCssSelector ( ' form ' );
->removeExcludedCssSelector(string $selector)
- Remove seletores excluídos adicionados anteriormente, se houver. $ cssInliner -> removeExcludedCssSelector ( ' form ' );
Emogrifier
eliminada para a classe CssInliner
Código antigo usando Emogrifier
:
$ emogrifier = new Emogrifier ( $ html );
$ html = $ emogrifier -> emogrify ();
Novo código usando CssInliner
:
$ html = CssInliner:: fromHtml ( $ html )-> inlineCss ()-> render ();
NB: Neste exemplo, o código antigo remove elementos com display: none;
enquanto o novo código não, já que os comportamentos padrão da antiga e da nova classe diferem nesse aspecto.
Código antigo usando Emogrifier
:
$ emogrifier = new Emogrifier ( $ html , $ css );
$ emogrifier -> enableCssToHtmlMapping ();
$ html = $ emogrifier -> emogrify ();
Novo código usando CssInliner
e família:
$ domDocument = CssInliner:: fromHtml ( $ html )-> inlineCss ( $ css )-> getDomDocument ();
HtmlPruner:: fromDomDocument ( $ domDocument )-> removeElementsWithDisplayNone ();
$ html = CssToAttributeConverter:: fromDomDocument ( $ domDocument )
-> convertCssToVisualAttributes ()-> render ();
O Emogrifier atualmente oferece suporte aos seguintes seletores CSS:
~
(uma palavra dentro de uma lista de palavras separadas por espaços em branco)|
(correspondência exata de valor ou prefixo seguido por um hífen)^
(correspondência de prefixo)$
(correspondência de sufixo)*
(correspondência de substring)p:first-of-type
mas não *:first-of-type
)Os seguintes seletores ainda não foram implementados:
<style>
no HTML – incluindo (mas não necessariamente limitado a) o seguinte: As regras que envolvem os seletores a seguir não podem ser aplicadas como estilos embutidos. Eles serão, entretanto, preservados e copiados para um elemento <style>
no HTML:
:hover
)::after
) @media
aplicáveis. As consultas de mídia podem ser muito úteis no design responsivo de e-mail. Consulte suporte para consulta de mídia. No entanto, para que sejam eficazes, pode ser necessário adicionar !important
a algumas das declarações dentro deles para que substituam os estilos CSS que foram incorporados. Por exemplo, com o CSS a seguir, a declaração font-size
na regra @media
não substituiria o tamanho da fonte para p
elementos da regra anterior depois de ter sido embutido como <p style="font-size: 16px;">
no HTML, sem a diretiva !important
(embora !important
não fosse necessário se o CSS não estivesse embutido): p {
font-size : 16 px ;
}
@media ( max-width : 640 px ) {
p {
font-size : 14 px !important ;
}
}
@media
não podem ser aplicadas a valores de propriedades CSS que foram incorporados e avaliados. No entanto, as regras @media
que usam propriedades personalizadas (com var()
) ainda seriam capazes de obter seus valores (a partir das definições embutidas ou das regras @media
) em clientes de e-mail que suportam propriedades personalizadas.::after
) ou pseudoclasses dinâmicas (como :hover
) – é impossível. No entanto, tais regras serão preservadas e copiadas para um elemento <style>
, como acontece com as regras @media
, aplicando-se as mesmas advertências.<style>
do seu HTML, mas não irá capturar arquivos CSS referenciados em elementos <link>
ou regras @import
(embora os deixe intactos para clientes de email que os suportam).Dê uma olhada em nossa API e política de descontinuação.
Contribuições na forma de relatórios de bugs, solicitações de recursos ou solicitações pull são mais que bem-vindas. Por favor, dê uma olhada em nossas diretrizes de contribuição para saber mais sobre como contribuir para o Emogrifier.
branch-alias
para apontar para o lançamento após o próximo lançamento.