Giter Site home page Giter Site logo

tijsverkoyen / csstoinlinestyles Goto Github PK

View Code? Open in Web Editor NEW
5.8K 5.8K 185.0 216 KB

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.

License: BSD 3-Clause "New" or "Revised" License

PHP 55.41% HTML 7.40% CSS 37.19%

csstoinlinestyles's People

Contributors

barryvdh avatar bftrick avatar big-shark avatar c960657 avatar carusogabriel avatar davidprevot avatar dmaicher avatar driesvints avatar fkupper avatar gigagg avatar grahamcampbell avatar hikariii avatar jasonwain avatar jbboehr avatar lifo101 avatar marclaporte avatar mdio avatar mhujer avatar nicolas-grekas avatar nyholm avatar richardkeep avatar romainmenke avatar rvock avatar scrutinizer-auto-fixer avatar stadly avatar stof avatar techi602 avatar theluk avatar tijsverkoyen avatar ugoku avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

csstoinlinestyles's Issues

CSS Attribute merging

Gmail is reordering Style attribute - so it would be great if attributes get merged.

example Original:
<h3 style="margin: 0; padding: 0; font-family: 'Helvetica Neue', 'Helvetica', Arial, sans-serif; color: #000; line-height: 1.1; margin-bottom: 15px; font-size: 27px;">

Gmail rendering - with new attribute ordering:
<h3 style="line-height:1.1;font-size:27px;margin-bottom:15px;font-family:'Helvetica Neue','Helvetica',Arial,sans-serif;margin:0;padding:0">

The Problem here is that the reset code "margin: 0" gets to the end and overwrites "margin-bottom".

Suggested Solution would be the merging of multiple attributes:
margin: 0 0 15px 0;

Parameters out of order

If i have a CSS like this:
div {
width: 200px;
_width: 211px;
}

The rules will be inserted out of order:
div style="_width:211px;width:200px;"

If you comment out the lines below the order is respected:
// sort the pairs
ksort($pairs);

Is there any reason to sort the pairs?

Thx,
Carlos

buildXPathQuery doesn't properly handle multiple classes

I noticed that the buildXPathQuery function inserts stray asterisks (*'s) in the middle of the xpath it generates from css that includes multiple classes.

For example, "div.a.b" is incorrectly turned into

//div[ contains( concat( " ", @class, " " ), concat( " ", "a", " " ) ) ]*[ contains( concat( " ", @class, " " ), concat( " ", "b", " " ) ) ]

instead of

//div[ contains( concat( " ", @class, " " ), concat( " ", "a", " " ) ) ][ contains( concat( " ", @class, " " ), concat( " ", "b", " " ) ) ]

It seems the same problem would exist with a number of other syntaxes, such as ".a.b.c".

This class from Zend Framwork is more robust and worth taking a look at, although it doesn't look like it handles any pseudo classes.

Use !important

The !imporant tag is ignored right now. Any ideas how to fix this? The specificity is calculated per group of rules right? So perhaps create an extra array with the important rules and overwrite them later on?

Running the inliner twice

When I run the CSS in-liner again on HTML/CSS that has already been inlined. It seems to duplicate existing css that are already inline?

Responsive issues

turned on media queries feature but it didn't worked.
look like it doesn't take into account screen size of media queries.
Tried the same thing with ruby's premailer. It appends media queries in head of html page.
any work around for similar output ?

Non-breaking spaces are converted to "Â"

Non-breaking spaces (&nbsp;) are converted to "Â" (ANSI value 160).
I used this workaround

$bodyhtml = str_replace("&nbsp;"," ",$bodyhtml);
$cssToInlineStyles->setHTML($bodyhtml);

but spaces may be broken.

Preserve media/pseudo, remove rest

Inlining works great, and I know it is already possible to remove inline styles (#16), but it would be even better if some parts are kept, like mediaqueries and :pseudo selectors (:hover, :active etc).
This will reduce the size of the email but keep all styles intact.
An example is http://zurb.com/ink/inliner.php but that isn't opensource.

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 

Semicolon and base64

Hi,

I have style with base64:

.bg {
background-image: url('data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAA//Z');
}

After convert it's looks like that:

<table class="bg" style="background-image: url('data:image/jpg;">

the head tag should not be styled

I noticed that the "head" tag and its descendants (meta, etc) are all styled, for example:

<head style="margin: 0; padding: 0;">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" style="margin: 0; padding: 0;">

Shouldn't the script be clever enough to ignore the head completely and instead only style the body?

Thank you.

Remove style block after processing

Tnx for your class!

Is is possible to let the class remove the css, after it is done inlining?
$inliner = new CSSToInlineStyles($htmlcss); $inliner->setUseInlineStylesBlock(true); $output = $inliner->convert();
This transforms my style block to inlinecss, but it now the styles are double. Is is possible to remove them automatically?

utf8 input

when I give an html sting in utf8 special characters get not well parsed.

Exclamaition mark

Hi,

I have got some exclamation marks in my output from csstoinline styles.

Is it a known issue ? How to correct it ?

Thank's,

extra '>' while processing

I just used this lib with:
$cI = new CssToInlineStyles\CssToInlineStyles($html,$css);
$cI->setCleanup(false);
$cI->setStripOriginalStyleTags(false);
$html = $cI->convert(true);

th result is an extra '>' on top of html;

I needed to replace:

// remove the XML-header
$html = ltrim(substr($html, $endPosition + 1));

by

// remove the XML-header
$html = ltrim(substr($html, $endPosition + 2));

Segmentation fault

I started getting segmentation faults this morning in my app after having added some UTF-8 support yesterday. The change I made was that I began passing in a full html document starting with the doctype and , as opposed to just dropping in my main

.

This issue didn't happen in my local environment, only in prod and only some of the time.

After an hour of troubleshooting, turns out that including <!DOCTYPE html> in the HTML causes this.

When I removed it, the issue went away:

    $html = "
-   <!DOCTYPE html>
    <html>
        <head>
            <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
            <style type='text/css'>" . $this->_getCssInStyleTags() . "</style>
        </head>
        <body>
            $body
        </body>
    </html>
    ";

Specificity sort reversed

<style>
a { color: #000001; }
#foo { color: #cccccc; }
</style>
<a href="#" id="#foo"></a>

becomes

<a href="#" id="#foo" style="color: #cccccc">Foobar</a>

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);
            }
        }

Inserting A with circumflex character before spans

There is an issue whereby the following code:

 <p>This is a test heading with various things such as <strong>bold</strong>, <span style="text-decoration: underline;"><strong>bold-underline</strong></span><strong></strong>, <em>italics</em>, and various other cool things.</p>

Gets converted to the following:

<p>This is a test heading with various things such as <strong>bold</strong>, <span style="text-decoration: underline;"><strong>bold-underline</strong></span><strong></strong>, <em>italics</em>, and various other cool things.</p>

Note the addition of the odd A with circumflex characters. I'm not sure why this occurs.

Character Encoding

Hi,

I think there is an issue with Character encoding. If you pass in HTML that has characters like this i.e äöüßä.

It doesn't handle them very well.

Any ideas why?

Laravel 5.2

Your package breaks on install with Laravel 5.2. Specifically the dependency for symfony/css-selector 2.x is no longer valid. symfony/css-selector is now on version 3.x

E_WARNING: array_map(): An error occurred while invoking the map callback

Hi,

We constantly get the error in the subject on our production server. We have NewRelic monitoring on which is how we see it. We recently updated to 1.5.4 version of the library to see if that resolves it, but it doesn't. Here is the error and stack trace (minus our code's part of the stack):

Error message
E_WARNING: array_map(): An error occurred while invoking the map callback

Stack trace
…vendor/symfony/css-selector/Symfony/Component/CssSelector/XPath/
Translator.php (0)
…gate/vendor/symfony/css-selector/Symfony/Component/CssSelector/
CssSelector.php (65)
….4/navigate/vendor/tijsverkoyen/css-to-inline-styles/src/
CssToInlineStyles.php (165)

Warning: Unexpected character in input: '\' (ASCII=92) state=1

I was getting these errors until I removed the slash from $document = new \DOMDocument('1.0', $this->getEncoding());

What was the reason for including this back slash?

Warning: Unexpected character in input: '' (ASCII=92) state=1 in /library/shared/CssToInlineStyles/CssToInlineStyles.php on line 234

Warning: Unexpected character in input: '' (ASCII=92) state=1 in /library/shared/CssToInlineStyles/CssToInlineStyles.php on line 243

Exclude Mediaqueries didn't catch.

Hello,
I was wondering why my Mediaqueries weren't excluded from inlining.
it was something like this:

@media only screen and (max-width: 480px){ }

and

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

didn't catch.

So I found another regex snippet that worked, in responsiv.js

so this works now:

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

I didn't break down the regex because I needed a quick fix.

Btw. I used the MailChimp Responsive E-Mail Templates in this case.

UTF-8 support

Hello,

I am migrating my application from ISO-8859-1 to UTF-8

I have troubles with your class. I do:

// On intègre le CSS à l'HTML
$cssToInlineStyles = new CSSToInlineStyles($CodeHTML, $CodeCSS);
$CodeHTML = $cssToInlineStyles->convert();

I make mb_detect_encoding($CodeHTML) before and after the CSSToInlineStyles.

Before charset is UTF-8
After, it is detected as ASCII

Do you have any idea why?

regards

outputXHTML leave starting <xml> tag

When we want XHTML in output, we call
$document->saveXML(null, LIBXML_NOEMPTYTAG)
This results in adding on my machine the following starting tag:

So, the line
$html = str_replace(''."\n", '', $html);
does not removes this starting xml tag.
The solution could be to replace the above line with:
$i = strpos($html, '<?xml');
if($i !== false)
{
$i = strpos($html, '>', $i);
if($i !== false)
{
$html = ltrim(substr($html, $i + 1));
}
}

Styles in media query overwriting base styles

I have the following CSS:

<style type="text/css">
    @media only screen and (max-width: 480px) {
        /* mobile-specific CSS styles go here */
        table.container {
            width: 460px !important;
        }
    }
    table.container {
        width: 600px;
    }
</style>

The idea is that table.container is 600px on normal devices, and 460px on mobile devices. When I run this code through CssToInlineStyles, it is using the 460px version inline. For example:

<table class="container" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 460px !important;">
.....

How can I structure my media query so that the 600px version is used inline?

Bug: Class match doesn't occur unless HTML element is specified in CSS

Given the following HTML

<table border="0" cellspacing="5" cellpadding="5" id="calendar">
    <tr class="titleRow">
        <td>Header</td>
    </tr>
</table>

Styles contained in this selector do not match:

#calendar .titleRow td { }

Styles in this selector do match:

#calendar tr.titleRow td { }

(If this is not possinle to be fixed I would suggest authors to write their CSS with elements instead of "loose" class names" e.g. always write p.className and not just .className)

$cssRules Memory Leak

I'm using this to inline emails in bulk, and I noticed while profiling that each email I inlined took longer to convert than the last. I traced it back to the "cssRules" variable, which gets appended to every time "processCSS" is called, even if the css and html are exactly the same as the last time it was called.

Is there a reason for this variable to live outside the "convert" function scope? Would it make sense to change the code so that processCSS returns a list of rules rather than modifying any state?

$cssRules = $this->processCSS();

Tag new version

Is it possible to tag a new version? As I'm running in to the specificity issue fixed in #49.

Residual > left behind by code to remove XML tag

If outputXML is chosen, then:

if($startPosition !== false)
{
// get end of the xml-declaration
$endPosition = strpos($html, '?>', $startPosition);

// remove the XML-header
$html = ltrim(substr($html, $endPosition + 1));

}

runs, but it should be $endPosition + 2.

Syntax error on latest master

I used the latest commit and got a syntax error when using it.

PHP Parse error: syntax error, unexpected T_STRING in /var/www/vhosts/.../CssToInlineStyles/CssToInlineStyles.php on line 2

Commit: 2844666

including external stylesheets

I've written additional snippet for including external stylesheets if somebody is interrested..

usage: add this piece at the end of html content:

the library:

<?php

require_once __DIR__ . '/vendor/autoload.php';

use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;

class InlineCss
{

    /**
     * @var CssToInlineStyles
     */
    private $cssToInlineStyles;

    /**
     * @var string
     */
    private $html;

    /**
     * @var string
     */
    private $css = '';

    public function __construct()
    {
        $this->cssToInlineStyles = new CssToInlineStyles();
    }

    public function loadHtml()
    {
        $html = ob_get_clean();
        if (!$html) {
            throw new Exception('No Content to process. This method must be called after HTML is outputted.');
        }

        $this->html = $html;
    }

    public function includeExternalStylesheets()
    {
        preg_match_all('/<link[^>]+>/mi', $this->html, $matches);
        $linkElements = $matches[0];

        if ($linkElements) {
            foreach ($linkElements as $linkElement) {
                $cssContent = $this->getCssContent($linkElement);
                $this->html = str_replace($linkElement, '
                    <style type="text/css">
                        ' . $cssContent . '
                    </style>
                ', $this->html);
            }
        }
    }

    /**
     * @param $linkElement
     * @return string
     */
    private function getCssContent($linkElement)
    {
        // load data from html element
        preg_match_all("/href=['\"]([^'\"]+)['\"]/", $linkElement, $matches);
        $url = $matches[1][0];

        $absUrl = __DIR__ . '/../' . $url;

        // this needs to be changed to search in all include paths
        $cssContent = @file_get_contents($absUrl);

        if (!$cssContent) {
            trigger_error('Error loading stylesheet from ' . $absUrl, E_USER_NOTICE);
        }

        return $cssContent;
    }

    public function convert()
    {
        $this->cssToInlineStyles->setHTML($this->html);
        $this->cssToInlineStyles->setCSS($this->css);
        $this->cssToInlineStyles->setUseInlineStylesBlock();
        $this->cssToInlineStyles->setCleanup();
        $this->cssToInlineStyles->setStripOriginalStyleTags();

        // output
        $output = $this->cssToInlineStyles->convert();

        // additional style tags cleaning
        $output = str_replace('<style type="text/css"></style>', '', $output);

        return $output;
    }

    public static function process()
    {
        $inlineCss = new InlineCss;
        $inlineCss->loadHtml();
        $inlineCss->includeExternalStylesheets();

        echo $inlineCss->convert();
    }

}

probably needs fixing the paths etc..

Empty tags are incorrectly formatted

Feeding a <br /> tag in with the html will result in a <br></br> which seems to confuse most UAs.

The same happens with <hr /> but that isn't quite as confusing apparently.

processing should not append html markup

foo
<style>
    div#container { margin: 1em auto; }
    h1 { font-weight: bold; font-size: 2em; }
</style>
<div id="container">
    <h1>Sample Page Title</h1>
    <p class="small">Some small note!</p>
</div>
bar

becomes

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p style="font-family: sans-serif; margin-bottom: 1em; text-align: justify;">foo</p>
<div id="container" style="margin: 1em auto;">
    ...
</div>
bar</body></html>

But I would expect it to return only the div container and foo/bar strings around

The reason I need this: We render only small snippets for a template

Suck in linked style sheets?

Perhaps I am using the module wrong, but is CssToInlintStyles supposed to read in the CSS stylesheets linked in the HTML automatically, or do I have to do that up front?

Looking for a gulp-inline-css like capability for PHP.

Bug with same selectors

Hello ;)

The CSS to inline styles class handles double definitions of the same selectors e.g. resetting an element first and then redefening it erroneously.

E.g. the following CSS:

p { margin: 0; padding; 0; }
p { margin: 0 0 12px; }

returns
<p style="margin: 0; padding: 0;"></p>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.