Skip to content

Commit b0a6f25

Browse files
committed
Moved away from tijs' library to support media tags.
1 parent 315ec2c commit b0a6f25

File tree

9 files changed

+609
-51
lines changed

9 files changed

+609
-51
lines changed

README.md

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,2 @@
11
# page-specific-css
2-
Small php library in combination with a twig extention that allows you to annotate above-the-fold-html in your twig files which will than extract all the necessary CSS.
3-
4-
In combination with loadCSS you can setup a page-specific critcal CSS solution quite easy.
5-
6-
## Install
7-
```bash
8-
composer install page-specific-css
9-
```
10-
11-
## Usage
12-
```twig
13-
{% fold %}
14-
<button class=”your-css-class”>Button</button>
15-
{% endfold %}
16-
```
17-
18-
```twig
19-
<!-- output -->
20-
<head>
21-
<style>
22-
.your-css-class {
23-
color: pink;
24-
}
25-
</style>
26-
</head>
27-
```
2+
Php library which determines critical css on a per page basis.

composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
}
1313
],
1414
"require": {
15-
"tijsverkoyen/css-to-inline-styles": "^2.2",
16-
"twig/twig": "^1|^2"
15+
"php": "^5.5 || ^7",
16+
"symfony/css-selector": "^2.7|~3.0",
17+
"twig/twig": "^1.26"
1718
},
1819
"autoload": {
1920
"psr-4": {

src/Css/Processor.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
namespace PageSpecificCss\Css;
4+
5+
use PageSpecificCss\Css\Rule\Processor as RuleProcessor;
6+
use PageSpecificCss\Css\Rule\Rule;
7+
8+
class Processor
9+
{
10+
/**
11+
* Get the rules from a given CSS-string
12+
*
13+
* @param string $css
14+
* @param array $existingRules
15+
* @return Rule[]
16+
*/
17+
public function getRules($css, $existingRules = array())
18+
{
19+
$css = $this->doCleanup($css);
20+
$rulesProcessor = new RuleProcessor();
21+
$rules = $rulesProcessor->splitIntoSeparateRules($css);
22+
23+
return $rulesProcessor->convertArrayToObjects($rules, $existingRules);
24+
}
25+
26+
/**
27+
* Get the CSS from the style-tags in the given HTML-string
28+
*
29+
* @param string $html
30+
* @return string
31+
*/
32+
public function getCssFromStyleTags($html)
33+
{
34+
$css = '';
35+
$matches = array();
36+
preg_match_all('|<style(?:\s.*)?>(.*)</style>|isU', $html, $matches);
37+
38+
if (!empty($matches[1])) {
39+
foreach ($matches[1] as $match) {
40+
$css .= trim($match) . "\n";
41+
}
42+
}
43+
44+
return $css;
45+
}
46+
47+
/**
48+
* @param string $css
49+
* @return string
50+
*/
51+
private function doCleanup($css)
52+
{
53+
// remove charset
54+
$css = preg_replace('/@charset "[^"]++";/', '', $css);
55+
56+
$css = str_replace(array("\r", "\n"), '', $css);
57+
$css = str_replace(array("\t"), ' ', $css);
58+
$css = str_replace('"', '\'', $css);
59+
$css = preg_replace('|/\*.*?\*/|', '', $css);
60+
$css = preg_replace('/\s\s++/', ' ', $css);
61+
$css = trim($css);
62+
63+
return $css;
64+
}
65+
}

src/Css/Property/Processor.php

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?php
2+
3+
namespace PageSpecificCss\Css\Property;
4+
5+
use Symfony\Component\CssSelector\Node\Specificity;
6+
7+
class Processor
8+
{
9+
/**
10+
* Split a string into seperate properties
11+
*
12+
* @param string $propertiesString
13+
* @return array
14+
*/
15+
public function splitIntoSeparateProperties($propertiesString)
16+
{
17+
$propertiesString = $this->cleanup($propertiesString);
18+
19+
$properties = (array) explode(';', $propertiesString);
20+
$keysToRemove = array();
21+
$numberOfProperties = count($properties);
22+
23+
for ($i = 0; $i < $numberOfProperties; $i++) {
24+
$properties[$i] = trim($properties[$i]);
25+
26+
// if the new property begins with base64 it is part of the current property
27+
if (isset($properties[$i + 1]) && strpos(trim($properties[$i + 1]), 'base64,') === 0) {
28+
$properties[$i] .= ';' . trim($properties[$i + 1]);
29+
$keysToRemove[] = $i + 1;
30+
}
31+
}
32+
33+
if (!empty($keysToRemove)) {
34+
foreach ($keysToRemove as $key) {
35+
unset($properties[$key]);
36+
}
37+
}
38+
39+
return array_values($properties);
40+
}
41+
42+
/**
43+
* @param $string
44+
* @return mixed|string
45+
*/
46+
private function cleanup($string)
47+
{
48+
$string = str_replace(array("\r", "\n"), '', $string);
49+
$string = str_replace(array("\t"), ' ', $string);
50+
$string = str_replace('"', '\'', $string);
51+
$string = preg_replace('|/\*.*?\*/|', '', $string);
52+
$string = preg_replace('/\s\s+/', ' ', $string);
53+
54+
$string = trim($string);
55+
$string = rtrim($string, ';');
56+
57+
return $string;
58+
}
59+
60+
/**
61+
* Convert a property-string into an object
62+
*
63+
* @param string $property
64+
* @return Property|null
65+
*/
66+
public function convertToObject($property, Specificity $specificity = null)
67+
{
68+
if (strpos($property, ':') === false) {
69+
return null;
70+
}
71+
72+
list($name, $value) = explode(':', $property, 2);
73+
74+
$name = trim($name);
75+
$value = trim($value);
76+
77+
if ($value === '') {
78+
return null;
79+
}
80+
81+
return new Property($name, $value, $specificity);
82+
}
83+
84+
/**
85+
* Convert an array of property-strings into objects
86+
*
87+
* @param array $properties
88+
* @return Property[]
89+
*/
90+
public function convertArrayToObjects(array $properties, Specificity $specificity = null)
91+
{
92+
$objects = array();
93+
94+
foreach ($properties as $property) {
95+
$object = $this->convertToObject($property, $specificity);
96+
if ($object === null) {
97+
continue;
98+
}
99+
100+
$objects[] = $object;
101+
}
102+
103+
return $objects;
104+
}
105+
106+
/**
107+
* Build the property-string for multiple properties
108+
*
109+
* @param array $properties
110+
* @return string
111+
*/
112+
public function buildPropertiesString(array $properties)
113+
{
114+
$chunks = array();
115+
116+
foreach ($properties as $property) {
117+
$chunks[] = $property->toString();
118+
}
119+
120+
return implode(' ', $chunks);
121+
}
122+
}

src/Css/Property/Property.php

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
namespace PageSpecificCss\Css\Property;
4+
5+
use Symfony\Component\CssSelector\Node\Specificity;
6+
7+
final class Property
8+
{
9+
/**
10+
* @var string
11+
*/
12+
private $name;
13+
14+
/**
15+
* @var string
16+
*/
17+
private $value;
18+
19+
/**
20+
* @var Specificity
21+
*/
22+
private $originalSpecificity;
23+
24+
/**
25+
* Property constructor.
26+
* @param $name
27+
* @param $value
28+
* @param Specificity|null $specificity
29+
*/
30+
public function __construct($name, $value, Specificity $specificity = null)
31+
{
32+
$this->name = $name;
33+
$this->value = $value;
34+
$this->originalSpecificity = $specificity;
35+
}
36+
37+
/**
38+
* Get name
39+
*
40+
* @return string
41+
*/
42+
public function getName()
43+
{
44+
return $this->name;
45+
}
46+
47+
/**
48+
* Get value
49+
*
50+
* @return string
51+
*/
52+
public function getValue()
53+
{
54+
return $this->value;
55+
}
56+
57+
/**
58+
* Get originalSpecificity
59+
*
60+
* @return Specificity
61+
*/
62+
public function getOriginalSpecificity()
63+
{
64+
return $this->originalSpecificity;
65+
}
66+
67+
/**
68+
* Is this property important?
69+
*
70+
* @return bool
71+
*/
72+
public function isImportant()
73+
{
74+
return (stripos($this->value, '!important') !== false);
75+
}
76+
77+
/**
78+
* Get the textual representation of the property
79+
*
80+
* @return string
81+
*/
82+
public function toString()
83+
{
84+
return sprintf(
85+
'%1$s: %2$s;',
86+
$this->name,
87+
$this->value
88+
);
89+
}
90+
}

0 commit comments

Comments
 (0)