CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very usefull when you're sending emails.

Last update: Aug 11, 2022

CssToInlineStyles class

Build Status Scrutinizer Code Quality Code Coverage SensioLabsInsight

Installation

CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.

About

PHP CssToInlineStyles is a class to convert HTML into HTML with inline styles.

Installation

The recommended installation way is through Composer.

$ composer require tijsverkoyen/css-to-inline-styles

Example

use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;

// create instance
$cssToInlineStyles = new CssToInlineStyles();

$html = file_get_contents(__DIR__ . '/examples/sumo/index.htm');
$css = file_get_contents(__DIR__ . '/examples/sumo/style.css');

// output
echo $cssToInlineStyles->convert(
    $html,
    $css
);

Known issues

  • no support for pseudo selectors
  • no support for css-escapes
  • UTF-8 charset is not always detected correctly. Make sure you set the charset to UTF-8 using the following meta-tag in the head: <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />. (Note: using <meta charset="UTF-8"> does NOT work!)

Sites using this class

GitHub

https://github.com/tijsverkoyen/CssToInlineStyles
Comments
  • 1. 2.0 (WIP)

    The 2.0 version is a major overhaul, which is not backwards compatible.

    • From now on you can re-use the class for multiple mails.
    • A lot less complicated options, as in: no more options at all.
    • More separate classes which handle their own (tested) methods.
    • A lot more tests

    The reason why I did this was to make the class more usable.

    Reviewed by tijsverkoyen at 2015-11-20 16:29
  • 2. excludeMediaQueries regexp not works on some servers

    https://github.com/tijsverkoyen/CssToInlineStyles/blob/master/src/CssToInlineStyles.php#L436

    $css = preg_replace('/@media [^{]*{([^{}]|{[^{}]*})*}/', '', $css);
    var_dump($css); // is NULL in some servers
    

    I don't know because of what it, but i modify regexp to

    $css = preg_replace('/@media [^{]*{([^{}]|{.*})*}/', '', $css);
    

    and it works fine

    Server config

    mbstring.func_overload = 0
    mbstring.internal_encoding = utf-8
    Multibyte (japanese) regex support  = enabled
    Multibyte regex (oniguruma) version =   5.9.1 
    
    Reviewed by Londeren at 2014-12-10 13:43
  • 3. Replaced the regex-based transformation of CSS to XPath

    The library now uses the Symfony CssSelector component, which supports more cases than the custom logic used previously. Closes #34

    I updated the doc to mention composer as the recommended installation way, as this takes care of including the CssSelector component automatically. Btw, don't forget to update the composer.json again when bumping the version after this change :)

    Reviewed by stof at 2014-05-28 09:12
  • 4. Always have CSS styles overwrite inline styles

    We might have different use cases but for us it is important that already existing inline styles are always overwritten when the same property is in the CSS. Right now (looking at version 2.0) they are only overwritten, if you add !important to your CSS property.

    Let's say you have a button as a standard component that comes with a default look defined as inline styles and you want to give it a different background color as well as font-size. With this you'd have to write:

    .my-button { 
    background-color: #f00 !important;
    font-size: 16px !important;
    }
    

    So basically you need !important everywhere. I know that this is how CSS specificity works, but for us, doing our mails, it's not so useful.

    So if there are no objections, I would love to have the "isImportant" check removed.

    But maybe you have a use case for that so perhaps it should be an option instead.

    Reviewed by mdio at 2015-11-24 10:48
  • 5. Problem on load HTML UTF-8 file

    Hello, I fixed a problem to load HTML replacing:

            // create new DOMDocument
            $document = new \DOMDocument('1.0', $this->getEncoding());
    
            // set error level
            libxml_use_internal_errors(true);
    
            // load HTML
            $document->loadHTML($this->html);
    

    With:

            // create new DOMDocument
            $document = new \DOMDocument();
            $document->encoding = 'UTF-8';
    
            // set error level
            libxml_use_internal_errors(true);
    
            // load HTML with hack
            $document->loadHTML('<?xml encoding="UTF-8">' . $this->html);
    
            // dirty fix
            foreach ($document->childNodes as $item) {
                if ($item->nodeType == XML_PI_NODE) {
                    // remove hack
                    $document->removeChild($item);
                }
            }
    
    Reviewed by netinhoteixeira at 2014-07-09 18:45
  • 6. Refactor specificity

    Don't use a value, but compare the 3 values in a seperate class. And don't add the order to the specificity, only use it when the specificity is equal. This will prevent cases where the specificity is increased too much because many rules. This replaces #56

    This is following the spec better, so that 2,0,1 > 1,12,1 (vs 201 < 221, which is incorrect)

    /cc @stof What do you think, something like this compare also for the CssSelector component?

    Reviewed by barryvdh at 2014-07-16 18:50
  • 7. reset css rules when new css is set

    Hello,

    This PR fixes issue when reusing same instance of CssToInlineStyles class for inlining, e.g. in bulk emails option. Also it speeds up inlining css a bit for bulk emails by parsing css only once.

    Regards, Alex

    Reviewed by mente at 2014-11-06 16:24
  • 8. Not properly parsing out comments.

    Hi, I found that this plugin wasn't properly parsing out HTML comments which may exist in some inline <style> blocks, such as this one for example:

    <style type="text/css">
    <!--
    .bwalignc {text-align: center}
    // ...more classes...
    -->
    </style>
    

    As a result, ->processCSS() will end up thinking that the first class above is <!--.bwalignc instead of .bwalignc. I'll submit a quick PR in a moment to patch this up!

    Reviewed by patricknelson at 2016-03-30 01:05
  • 9. Give workaround example for known issue: not supporting pseudo-selectors or fix it

    Hello Tijs,

    thanks for the good work on CssToInlineStyles. You mention the known issue "no support for pseudo selectors" in README.md

    From my point of view, this is no big deal, even if styles are stripped out, because CssToInlineStyles will keep media queries in the style block. So you could give an example for the workaround in README.md just where the known issue gets mentioned:

    If you need pseudo selectors, wrap them in @media all{ }
    

    On the other hand: Why not support it? If there's no conceptional reason for not supporting it, I'd offer you to help. Let me know if you're interested.

    Reviewed by tpraxl at 2016-02-17 12:17
  • 10. Tweak tests

    Require phpunit for --dev, use the vendor bin, remove the composer.lock file. Also composer update before running tests and use travis_retry, in case it fails.

    BTW, I don't know if you have setup your Travis webhook for Git? That can be added easily and will make the tests run on every PR/commit.

    Reviewed by barryvdh at 2014-07-25 13:01
  • 11. Add support for symfony/css-selector:6.0

    First of all, thank you for this great library ♥

    Symfony 6.0 has been released recently, but any projects that depend on tijsverkoyen/css-to-inline-styles can't be upgraded because the dependency on symfony/css-selector is limited to ^2.7 || ^3.0 || ^4.0 || ^5.0.

    Reviewed by victorstanciu at 2021-12-07 09:37
  • 12. PHP 8.2 compatibility

    This line has been deprecated in PHP 8.2: $document->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); (/src/CssToInlineStyles.php on line 116)

    Symfony fixed it like this, but YMMV:

    mb_encode_numericentity($html, [0x80, 0xFFFF, 0, 0xFFFF], 'UTF-8');

    I'll try this and will submit a PR if it works :)

    Reviewed by Ugoku at 2022-08-05 09:53
  • 13. Undefined property: DOMDocument::$documentElement

    Hi, i have a problem with this package on shared-hosting while i haven't this problem on localhost

    gives me the error:

    { "message": "Undefined property: DOMDocument::$documentElement", "exception": "ErrorException", "file": "/home/h189025/public_html/system/vendor/tijsverkoyen/css-to-inline-styles/src/CssToInlineStyles.php", "line": 132, "trace": [ { "file": "/home/h189025/public_html/system/vendor/tijsverkoyen/css-to-inline-styles/src/CssToInlineStyles.php", "line": 132, "function": "handleError", "class": "Illuminate\Foundation\Bootstrap\HandleExceptions", "type": "->" }, { "file": "/home/h189025/public_html/system/vendor/tijsverkoyen/css-to-inline-styles/src/CssToInlineStyles.php", "line": 50, "function": "getHtmlFromDocument", "class": "TijsVerkoyen\CssToInlineStyles\CssToInlineStyles", "type": "->" }, { "file": "/home/h189025/public_html/system/vendor/laravel/framework/src/Illuminate/Mail/Markdown.php", "line": 74, "function": "convert", "class": "TijsVerkoyen\CssToInlineStyles\CssToInlineStyles", "type": "->" }, .... ] }

    Screenshot (391)

    please help...

    Reviewed by m-shariatzadeh at 2022-08-05 09:09
  • 14. DL and DT-tags workaround for HTML e-mail viewing?

    I'm trying to use a certain CSS on my HTML markup with dl and dt tags, and I want to convert it in to inline styles for showing the dl-list correctly in a e-mail message.

    HTML:

    <dl id="summary_description_list"><dt>Aantal</dt><dd>50</dd><dt>Formaat</dt><dd>A5 (148mm x 210mm)</dd><dt>Beprinting</dt><dd>Dubbelzijdig full color</dd><dt>Papiersoort</dt><dd>Mat xerox 120 grs</dd><dt>Betaling</dt><dd>Tikkie (iDeal/Revolut)</dd><dt>Aflevering</dt><dd>Ophalen in studio</dd><dt>Indicatief gewicht</dt><dd class="mb-15">186,48 gram</dd></dl>

    CSS: dl{display:grid;grid-template-columns:max-content auto}dt{grid-column-start:1;font-weight:bold}dt:after{content:":"}dd{grid-column-start:2}/*# sourceMappingURL=lists.css.map */

    PHP:

    $cssToInlineStyles = new CssToInlineStyles();
    $summary = $cssToInlineStyles->convert(
        $summary,
        file_get_contents('https://fonts.googleapis.com/css?family=Nova+Square').' '.
        file_get_contents('https://fonts.googleapis.com/css?family=Noto+Sans:400,400i,700,700i').' '.
        file_get_contents('../css/main.css')
    );
    

    The CssToInlineStyles code works by applying the styles, but my mail client doesn't show the styles correctly. Is their a workaround possible, since the list is showing correctly in the webversion.

    Reviewed by JeroenSteen at 2022-07-19 16:47
  • 15. Disable inlinling of certail style tags

    Hi!

    I'm working on a problem with certain versions of Outlook email client, and came to a solution where I need to apply styles to every email client, except Microsoft Outlook.

    There's a conditional comment that can do that:

    <!--[if !mso]><!-->
    <style>...</style>
    <!--<![endif]-->
    

    But the problem is that it's being inlined, as it's a valid non-commented <style> attribute.

    I've been thinking that having a way to disable inlining of styles from a specific style attribute could solve this. For example, the regular expression in Processor::getCssFromStyleTags() could ignore style tags that have do-not-inline attribute:

    https://github.com/tijsverkoyen/CssToInlineStyles/blob/master/src/Css/Processor.php#L38-L39

            $htmlNoComments = preg_replace('|<!--.*?-->|s', '', $html);
    +       $htmlNoComments = preg_replace('|<style(?:.*\sdo-not-inline\s?.*)?>(.*)</style>|s', '', $htmlNoComments);
            preg_match_all('|<style(?:\s.*)?>(.*)</style>|isU', $htmlNoComments, $matches);
    

    I can file a PR if you agree it's a good addition.

    Anyway, thank you for your great work! This package is helping us a lot with rendering emails :+1:

    Reviewed by e1himself at 2022-07-13 17:05
  • 16. Merging of Attributes

    I've done a port of Bootstrap-Email (https://github.com/bootstrap-email/bootstrap-email) to PHP.

    There's some different behavior between this package and the ruby inlining package.

    If I have lets say:

    .btn { border: 1px solid transparent; } .btn-colored { border-color: #fff; }

    I would expect the ruby result:

    border: 1px solid #fff;

    What this package generates:

    border: 1px solid transparent; border-color: #fff

    That will lead to a broken button without border in Outlook and it's duplicated anyway with "transparent" AND "#fff".

    Any thoughts?

    Reviewed by DemigodCode at 2022-06-15 10:17
The Mailer component helps sending emails

Mailer Component The Mailer component helps sending emails. Getting Started $ composer require symfony/mailer use Symfony\Component\Mailer\Transport;

Aug 8, 2022
Send beautiful HTML emails with Laravel
Send beautiful HTML emails with Laravel

Beautymail for Laravel Beautymail makes it super easy to send beautiful responsive HTML emails. It's made for things like: Welcome emails Password rem

Aug 13, 2022
Allows you to archive old emails from one Gmail mailbox to another Gmail mailbox

Gmail Archiver L'application Gmail archiver permet de déplacer automatiquement tous les vieux mails d'une boite Gmail vers une autre boite Gmail (ou é

Jan 27, 2022
Provides a clean and simple way to configure the WordPress-bundled PHPMailer library, allowing you to quickly get started sending mail through a local or cloud based service of your choice

WP PHPMailer provides a clean and simple way to configure the WordPress-bundled PHPMailer library, allowing you to quickly get started sending mail through a local or cloud based service of your choice.

Jul 21, 2022
Manage mailboxes, filter/get/delete emails in PHP (supports IMAP/POP3/NNTP)

PHP IMAP Initially released in December 2012, the PHP IMAP Mailbox is a powerful and open source library to connect to a mailbox by POP3, IMAP and NNT

Aug 8, 2022
Queue, preview and and send emails stored in the database.

Codeigniter4 email queue Queue, preview and and send emails stored in the database. This package provides an interface for creating emails on the fly

Apr 12, 2022
Offer an online version of your Laravel emails to users.
Offer an online version of your Laravel emails to users.

This is was a collaborative project with Ryan Chandler. Please consider supporting him for the hard work he put into this package! Help support the ma

Aug 6, 2022
An AngularJS / Laravel app - Keyword Based Email forwarder | read/write emails through IMAP
An AngularJS / Laravel app - Keyword Based Email forwarder | read/write emails through IMAP

@MailTree Simple mail forwarder. Based on the specific email body/subject keywords forward mails to the list of predefined users. Install Imap Install

Aug 21, 2018
Store outgoing emails in Laravel
Store outgoing emails in Laravel

Record and view all sent emails Watch a video walkthrough https://www.youtube.com/watch?v=Oj_OF5n4l4k&feature=youtu.be Documentation and install instr

Aug 7, 2022
Mail Web is a Laravel package which catches emails locally for debugging
 Mail Web is a Laravel package which catches emails locally for debugging

Mail Web is a Laravel package which catches emails locally for debugging Installation Use the package manager composer to install Mail Web. composer r

Jul 27, 2022
The classic email sending library for PHP
The classic email sending library for PHP

PHPMailer – A full-featured email creation and transfer class for PHP Features Probably the world's most popular code for sending email from PHP! Used

Aug 11, 2022
Mail sending module for Mezzio and Laminas MVC with support for file attachment and template email composition
Mail sending module for Mezzio and Laminas MVC with support for file attachment and template email composition

This module provides an easy and flexible way to send emails from Mezzio and Laminas MVC applications (formerly known as Zend Expressive and Zend MVC). It allows you to pre-configure emails and transports, and then send those emails at runtime.

Jan 16, 2022
Sending Email via Microsoft Exchange Web Services made Easy!

Send Mail via Exchange Web Services! Sending Email via Microsoft Exchange Web Services (EWS) made easy! Installation Install via Composer composer req

Jul 19, 2022
Simple mail sending by PHPMailer and Create your local system.

Simple mail sending by PHPMailer and Create your local system. Send mail zero of cost and also send Attachment like Photo, pdf and multiple files. You should be create a login and verify two steps authentication like OTP, verifications ?? link. PHPMailer make your dreams project eassy and simple also free of cost.

Dec 8, 2021
A simplified SMPP client lib for sending or receiving smses through SMPP v3.4.

PHP-based SMPP client lib This is a simplified SMPP client lib for sending or receiving smses through SMPP v3.4. In addition to the client, this lib a

Jul 26, 2022
Laravel IMAP is an easy way to integrate both the native php-imap module and an extended custom imap protocol into your Laravel app.

Laravel IMAP is an easy way to integrate both the native php-imap module and an extended custom imap protocol into your Laravel app. This enables your app to not only respond to new emails but also allows it to read and parse existing mails and much more.

Aug 10, 2022
PHPMailer – A full-featured email creation and transfer class for PHP
 PHPMailer – A full-featured email creation and transfer class for PHP

PHPMailer – A full-featured email creation and transfer class for PHP Features Probably the world's most popular code for sending email from PHP! Used

Aug 16, 2022
This application (class) does the sending of emails used in the phpmailer library

emailsender - PHP Notification library via email using phpMailer This library has the function of sending email using the phpmailer library. Doing thi

Feb 9, 2022
Contains a few tools usefull for making your test-expectations agnostic to operating system specifics

PHPUnit Tools to ease cross operating system Testing make assertEquals* comparisons end-of-line (aka PHP_EOL) character agnostic Make use of EolAgnost

Jan 3, 2022