norte. e•mog•ri•fi•er [ē-'mä-grƏ-,fī-Ər] - una utilidad para cambiar completamente la naturaleza o apariencia del correo electrónico HTML, especialmente. de una manera particularmente fantástica o extraña
Emogrifier convierte estilos CSS en atributos de estilo en línea en su código HTML. Esto garantiza una visualización adecuada en lectores de correo electrónico y dispositivos móviles que carecen de compatibilidad con hojas de estilo.
Esta utilidad fue desarrollada como parte de Intervals para abordar los problemas que plantean ciertos clientes de correo electrónico (en concreto, Outlook 2007 y GoogleMail) en lo que respecta a la forma en que manejan el estilo contenido en los correos electrónicos HTML. Como ya saben muchos desarrolladores y diseñadores web, ciertos clientes de correo electrónico son conocidos por su falta de compatibilidad con CSS. Si bien se están realizando intentos para desarrollar estándares comunes de correo electrónico, su implementación aún está lejos.
El principal problema con los clientes de correo electrónico que no cooperan es que la mayoría tiende a considerar únicamente CSS en línea, descartando todos los elementos <style>
y los enlaces a hojas de estilo en los elementos <link>
. Emogrifier resuelve este problema convirtiendo estilos CSS en atributos de estilo en línea en su código HTML.
Emogrifier transforma automáticamente su HTML al analizar su CSS e insertar sus definiciones de CSS en etiquetas dentro de su HTML según sus selectores de CSS.
Para instalar emogrifier, agregue pelago/emogrifier
a la sección require
en el composer.json
de su proyecto, o puede usar el compositor como se muestra a continuación:
composer require pelago/emogrifier
Consulte https://getcomposer.org/ para obtener más información y documentación.
La forma más básica de utilizar la clase CssInliner
es crear una instancia con el HTML original, incorporar el CSS externo y luego recuperar el HTML resultante:
use Pelago Emogrifier CssInliner ;
…
$ visualHtml = CssInliner:: fromHtml ( $ html )-> inlineCss ( $ css )-> render ();
Si no hay ningún archivo CSS externo y todo el CSS se encuentra dentro de los elementos <style>
del HTML, puede omitir el parámetro $css
:
$ visualHtml = CssInliner:: fromHtml ( $ html )-> inlineCss ()-> render ();
Si desea recuperar solo el contenido del elemento <body>
en lugar del documento HTML completo, puede utilizar el método renderBodyContent
:
$ bodyContent = $ visualHtml = CssInliner:: fromHtml ( $ html )-> inlineCss ()
-> renderBodyContent ();
Si desea modificar el proceso de inserción con cualquiera de las opciones disponibles, deberá llamar a los métodos correspondientes antes de insertar el CSS. El código entonces se vería así:
$ visualHtml = CssInliner:: fromHtml ( $ html )-> disableStyleBlocksParsing ()
-> inlineCss ( $ css )-> render ();
También hay otras clases de procesamiento de HTML disponibles (todas las cuales son subclases de AbstractHtmlProcessor
) que puede usar para cambiar aún más el HTML después de insertar el CSS. (Para obtener más detalles sobre las clases, consulte las secciones siguientes). CssInliner
y todas las clases de procesamiento HTML pueden compartir la misma instancia DOMDocument
para trabajar:
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 ();
La clase HtmlNormalizer
normaliza el HTML dado de las siguientes maneras:
La clase se puede utilizar así:
use Pelago Emogrifier HtmlProcessor HtmlNormalizer ;
…
$ cleanHtml = HtmlNormalizer:: fromHtml ( $ rawHtml )-> render ();
CssToAttributeConverter
convierte algunos valores de atributos de estilo en atributos visuales HTML. Esto permite obtener al menos un poco de estilo visual para clientes de correo electrónico que no soportan bien CSS. Por ejemplo, style="width: 100px"
se convertirá en width="100"
.
La clase se puede utilizar así:
use Pelago Emogrifier HtmlProcessor CssToAttributeConverter ;
…
$ visualHtml = CssToAttributeConverter:: fromHtml ( $ rawHtml )
-> convertCssToVisualAttributes ()-> render ();
También puedes hacer que CssToAttributeConverter
funcione en un DOMDocument
:
$ visualHtml = CssToAttributeConverter:: fromDomDocument ( $ domDocument )
-> convertCssToVisualAttributes ()-> render ();
La clase CssVariableEvaluator
se puede utilizar para aplicar los valores de las variables CSS definidas en los atributos de estilo en línea a las propiedades de estilo en línea que los utilizan.
Por ejemplo, el siguiente CSS define y utiliza una propiedad personalizada:
: root {
--text-color : green;
}
p {
color : var ( --text-color );
}
Después de que CssInliner
haya insertado ese CSS en el HTML (artificial) <html><body><p></p></body></html>
, se verá así:
< html style =" --text-color: green; " >
< body >
< p style =" color: var(--text-color); " >
< p >
</ body >
</ html >
El método CssVariableEvaluator
evaluateVariables
aplicará el valor de --text-color
para que el atributo style
de párrafo se convierta color: green;
.
Se puede utilizar así:
use Pelago Emogrifier HtmlProcessor CssVariableEvaluator ;
…
$ evaluatedHtml = CssVariableEvaluator:: fromHtml ( $ html )
-> evaluateVariables ()-> render ();
También puede hacer que CssVariableEvaluator
funcione en un DOMDocument
:
$ evaluatedHtml = CssVariableEvaluator:: fromDomDocument ( $ domDocument )
-> evaluateVariables ()-> render ();
La clase HtmlPruner
puede reducir el tamaño del HTML eliminando elementos con una declaración de estilo display: none
y/o eliminando clases de atributos class
que no son necesarios.
Se puede utilizar así:
use Pelago Emogrifier HtmlProcessor HtmlPruner ;
…
$ prunedHtml = HtmlPruner:: fromHtml ( $ html )-> removeElementsWithDisplayNone ()
-> removeRedundantClasses ( $ classesToKeep )-> render ();
El método removeRedundantClasses
acepta una lista permitida de nombres de clases que deben conservarse. Si este es un paso de posprocesamiento después de insertar CSS, también puede usar removeRedundantClassesAfterCssInlined
, pasándole la instancia CssInliner
que ha incorporado el CSS (y haciendo que HtmlPruner
funcione en DOMDocument
). Esto utilizará información de CssInliner
para determinar qué clases aún son necesarias (es decir, aquellas utilizadas en reglas no alineables que se han copiado en un elemento <style>
):
$ prunedHtml = HtmlPruner:: fromDomDocument ( $ cssInliner -> getDomDocument ())
-> removeElementsWithDisplayNone ()
-> removeRedundantClassesAfterCssInlined ( $ cssInliner )-> render ();
El método removeElementsWithDisplayNone
no eliminará ningún elemento que tenga la clase -emogrifier-keep
. Entonces, si, por ejemplo, hay elementos que por defecto tienen display: none
pero son revelados por una regla @media
, o que están pensados como un preencabezado, puedes agregar esa clase a esos elementos. El párrafo de este fragmento de HTML no se eliminará aunque tenga display: none
(que presumiblemente ha sido aplicado por CssInliner::inlineCss()
desde una regla CSS .preheader { display: none; }
):
< p class =" preheader -emogrifier-keep " style =" display: none; " >
Hello World!
</ p >
El método removeRedundantClassesAfterCssInlined
(o removeRedundantClasses
), si se invoca después de removeElementsWithDisplayNone
, eliminará la clase -emogrifier-keep
.
Hay varias opciones que puede configurar en la instancia CssInliner
antes de llamar al método inlineCss
:
->disableStyleBlocksParsing()
- De forma predeterminada, CssInliner
tomará todos los bloques <style>
en el HTML y aplicará los estilos CSS como atributos de "estilo" en línea al HTML. Los bloques <style>
se eliminarán del HTML. Si desea deshabilitar esta funcionalidad para que CssInliner
deje estos bloques <style>
en el HTML y no los analice, debe usar esta opción. Si usa esta opción, el contenido de los bloques <style>
no se aplicará como estilos en línea y cualquier CSS que desee que use CssInliner
debe pasarse como se describe en la sección Uso anterior.->disableInlineStyleAttributesParsing()
: de forma predeterminada, CssInliner
conserva todos los atributos de "estilo" en las etiquetas del HTML que le pasa. Sin embargo, si desea descartar todos los estilos en línea existentes en el HTML antes de aplicar el CSS, debe utilizar esta opción.->addAllowedMediaType(string $mediaName)
: de forma predeterminada, CssInliner
mantendrá solo los tipos de medios, all
, screen
e print
. Si desea conservar algunos otros, puede utilizar este método para definirlos.->removeAllowedMediaType(string $mediaName)
: puede utilizar este método para eliminar los tipos de medios que guarda Emogrifier.->addExcludedSelector(string $selector)
: evita que los elementos se vean afectados por la inserción de CSS. Tenga en cuenta que solo los elementos que coincidan con los selectores proporcionados se excluirán de la inserción de CSS, no necesariamente sus descendientes. Si desea excluir un subárbol completo, debe proporcionar selectores que coincidan con todos los elementos del subárbol, por ejemplo, utilizando el selector universal: $ cssInliner -> addExcludedSelector ( ' .message-preview ' );
$ cssInliner -> addExcludedSelector ( ' .message-preview * ' );
->addExcludedCssSelector(string $selector)
: a diferencia de addExcludedSelector
, que excluye los nodos HTML, este método excluye la incorporación de selectores CSS. Esto es útil, por ejemplo, si no desea que sus reglas de restablecimiento de CSS estén integradas en cada nodo HTML (por ejemplo, * { margin: 0; padding: 0; font-size: 100% }
). Tenga en cuenta que estos selectores deben coincidir exactamente con los selectores que desea excluir. Lo que significa que excluir .example
no excluirá p .example
. $ cssInliner -> addExcludedCssSelector ( ' * ' );
$ cssInliner -> addExcludedCssSelector ( ' form ' );
->removeExcludedCssSelector(string $selector)
: elimina los selectores excluidos agregados previamente, si los hay. $ cssInliner -> removeExcludedCssSelector ( ' form ' );
Emogrifier
eliminada a la clase CssInliner
Código antiguo usando Emogrifier
:
$ emogrifier = new Emogrifier ( $ html );
$ html = $ emogrifier -> emogrify ();
Nuevo código usando CssInliner
:
$ html = CssInliner:: fromHtml ( $ html )-> inlineCss ()-> render ();
NB: En este ejemplo, el código antiguo elimina elementos con display: none;
mientras que el nuevo código no, ya que los comportamientos predeterminados de la clase antigua y la nueva difieren en este sentido.
Código antiguo usando Emogrifier
:
$ emogrifier = new Emogrifier ( $ html , $ css );
$ emogrifier -> enableCssToHtmlMapping ();
$ html = $ emogrifier -> emogrify ();
Nuevo código usando CssInliner
y familia:
$ domDocument = CssInliner:: fromHtml ( $ html )-> inlineCss ( $ css )-> getDomDocument ();
HtmlPruner:: fromDomDocument ( $ domDocument )-> removeElementsWithDisplayNone ();
$ html = CssToAttributeConverter:: fromDomDocument ( $ domDocument )
-> convertCssToVisualAttributes ()-> render ();
Emogrifier actualmente admite los siguientes selectores CSS:
~
(una palabra dentro de una lista de palabras separadas por espacios en blanco)|
(ya sea una coincidencia de valor exacta o un prefijo seguido de un guión)^
(coincidencia de prefijo)$
(coincidencia de sufijo)*
(coincidencia de subcadena)p:first-of-type
pero no *:first-of-type
)Los siguientes selectores aún no están implementados:
<style>
en el HTML, incluido (pero no necesariamente limitado a) lo siguiente: Las reglas que involucran los siguientes selectores no se pueden aplicar como estilos en línea. Sin embargo, se conservarán y copiarán en un elemento <style>
del HTML:
:hover
)::after
) @media
aplicables. Las consultas de medios pueden resultar muy útiles en el diseño de correo electrónico responsivo. Consulte soporte para consultas de medios. Sin embargo, para que sean efectivos, es posible que deba agregar !important
a algunas de las declaraciones dentro de ellos para que anulen los estilos CSS que se han incluido. Por ejemplo, con el siguiente CSS, la declaración font-size
en la regla @media
no anularía el tamaño de fuente para p
elementos de la regla anterior después de que se haya insertado como <p style="font-size: 16px;">
en el HTML, sin la directiva !important
(aunque !important
no sería necesaria si el CSS no estuviera integrado): p {
font-size : 16 px ;
}
@media ( max-width : 640 px ) {
p {
font-size : 14 px !important ;
}
}
@media
no se puede aplicar a los valores de propiedad de CSS que se han incorporado y evaluado. Sin embargo, las reglas @media
que usan propiedades personalizadas (con var()
) aún podrían obtener sus valores (de las definiciones incorporadas o reglas @media
) en clientes de correo electrónico que admitan propiedades personalizadas.::after
) o pseudoclases dinámicas (como :hover
); es imposible. Sin embargo, dichas reglas se conservarán y copiarán en un elemento <style>
, como ocurre con las reglas @media
, con las mismas advertencias.<style>
de su HTML, pero no tomará archivos CSS a los que se hace referencia en elementos <link>
o reglas @import
(aunque los dejará intactos para los clientes de correo electrónico que los admitan).Eche un vistazo a nuestra API y política de obsolescencia.
Las contribuciones en forma de informes de errores, solicitudes de funciones o solicitudes de extracción son más que bienvenidas. Eche un vistazo a nuestras pautas de contribución para obtener más información sobre cómo contribuir a Emogrifier.
branch-alias
para que apunte a la versión posterior a la próxima versión.