2

I want extract all the used styles from a CSS file in a HTML document.

If there is a HTML like:

<div class="blue"></div>

And a CSS file like:

.blue {
  background-color: #2196F3 !important; }
.red {
  background-color: #F44336 !important; }

The PHP Code should produce an output as:

.blue {
  background-color: #2196F3 !important; }

The purpose is bring to CSS styles to the HTML document to prevent a render-blocking CSS.

I think it's needed a HTML and CSS parser.

6
  • 1
    Yes, I know how read a file in PHP. My question is extract from the CSS only the styles present in the HTML document. PHP should open the CSS file, parse every selector, look for it in the HTML document, if it's find, return the whole style. Commented May 23, 2015 at 19:32
  • why plug the css directly into the php, why not have the index file mesh the two together while using classes, then have different variations of the css file for what the user likes the site to look like through different includes? Commented May 23, 2015 at 19:34
  • @php_purest is not about custom styles for user, this is about optimize the CSS loading. I use materialize CSS, a CSS library with a big CSS file with styles defined for many purpose. I need extract from such file only the used styles in my HTML document. Commented May 23, 2015 at 19:44
  • Am I right in assuming that you don't just target classes but also complex CSS selectors? Commented May 23, 2015 at 20:01
  • @SamuelHerzog Yes, it is using complex CSS selectors. I will try programm a solution using this: code.google.com/p/ganon and this github.com/sabberworm/PHP-CSS-Parser Commented May 23, 2015 at 20:19

2 Answers 2

2

Just a rough idea,

supposed my html file is like:

<body class="container">
 <div class="row bg-red">
  <div class="col-md-12">
  </div>
 </div>
</body>
  1. Use regex to get string in the class in .html file like:

    <.... class="....." >|/>
    
  2. Substring and split by space

  3. Store it, in multi-dimensional array, (to prepare to store class nesting like: [0] = container, [0][0] = row, [0][0][0] = col-md-12, [0][1] = bg-red)

  4. Read .css file and all <style>

  5. Start read multi-dimensional array, like

    • Check for array [0] = container, then search css, <style> for .container
    • Check for array [0][0] = row, then search for .row
    • Check for array [0] [0][0] = .container .row
    • Check for array [0][0][0] = col-md-12, then search for .col-md-12
    • Check for array [0] [0][0] [0][0][0] = .container .row .col-md-12
    • If found, check it match for all 'dot' in css.

      • ex. '.container' = match
      • ex. '.container .row' = match
      • ex. '#main .container' = match
      • ex. '.container .row .detail' = not match
      • ex. '.container > .row' = match

Note: it just a very rough idea, you need to think more to handle the css that require continue such as .container > .row

Sign up to request clarification or add additional context in comments.

2 Comments

This is the begin of the solution, I need to be able to hand complex CSS selectors.
I'm just pointing, you need to handle just 4 more symbols; #, +, ~ and >. (another symbols such as :, or [xxx=""], or @media is no impossible to use since it is an action )
0

2021 updated: There are much better tools to perform this task, for example: https://github.com/FullHuman/purgecss

I achieved my exact result, I think this is going to help many people that want to optimize their website as suggested by Google Pagespeed Insights.

Dependencies: https://github.com/paquettg/php-html-parser https://github.com/sabberworm/PHP-CSS-Parser

use PHPHtmlParser\Dom;
ob_start();
?><!doctype html>
<html>
<head>
.....

</body>
</html><?PHP
$html = ob_get_contents();
ob_end_clean();
$md5 = md5($html);

    //add to HTML in style labels the CSS Used and minimized the result
    $dom = new Dom;
    $dom->load($html);
    $style = '';
    foreach($css_files as $css_file){
        $md5CSS = md5_file($css_file);
        
            $cssContent = file_get_contents($css_file);
            $oSettings = Sabberworm\CSS\Settings::create()->withMultibyteSupport(false)/*->beStrict()*/;
            $oCssParser = new Sabberworm\CSS\Parser($cssContent, $oSettings);
            $cssParsed = $oCssParser->parse();
            $memcached->set($md5CSS, $cssParsed);
        }
        foreach ($cssParsed->getContents() as $oItem) {
            if ($oItem instanceof Sabberworm\CSS\CSSList\KeyFrame)
                continue;
             if ($oItem instanceof Sabberworm\CSS\RuleSet\AtRuleSet)
                continue;
            if($oItem instanceof Sabberworm\CSS\RuleSet\DeclarationBlock){
                $oBlock = $oItem;
                $selectors = array();
                foreach($oBlock->getSelectors() as $oSelector)
                    $selectors[] = $oSelector->getSelector();
                if(count($dom->find(implode(",",$selectors))) > 0)
                    $style .= $oBlock->render(Sabberworm\CSS\OutputFormat::createCompact());
            }
            if ($oItem instanceof Sabberworm\CSS\CSSList\AtRuleBlockList) {
                foreach($oItem->getContents() as $oBlock) {
                    $selectors = array();
                    foreach($oBlock->getSelectors() as $oSelector)
                        $selectors[] = $oSelector->getSelector();
                    if(count($dom->find(implode(",",$selectors))) > 0){
                        $style .= $oItem->render(Sabberworm\CSS\OutputFormat::createCompact());
                        break;
                    }
                }
            }            
        }
    }
    $styleLabel = '<style type="text/css">'.$style.'</style>';
    $html = str_replace("</head>", $styleLabel."\n</head>",$html);

5 Comments

100/100 in both mobile and desktop. developers.google.com/speed/pagespeed/insights/…
No clear information was provided about the dependencies.
@Roy I added the dependencies, would you check your scoring for this answer, please?
Thank you for the update, I will try your solution. Also, to note, purgecss is not a Php solution but a JS (webpack) solution. But its a good one if someone wanna try.
@Roy I'm aware of that. You can call node process from PHP, as any other external process (cli)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.