tbela99/css
Composer 安装命令:
composer require tbela99/css
包简介
A CSS parser and minifier written in PHP
README 文档
README
CSS (A CSS parser and minifier written in PHP)
A CSS parser, beautifier and minifier written in PHP. It supports the following features
Features
- multibyte characters encoding
- sourcemap
- multiprocessing: process large CSS input very fast
- CSS Nesting module
- partially implemented CSS Syntax module level 3
- partial CSS validation
- CSS colors module level 4
- parse and render CSS
- optimize css:
- merge duplicate rules
- remove duplicate declarations
- remove empty rules
- compute css shorthand (margin, padding, outline, border-radius, font, background)
- process @import document to reduce the number of HTTP requests
- remove @charset directive
- query api with xpath like or class name syntax
- traverser api to transform the css and ast
- command line utility
Installation
install using Composer
PHP version >= 8.0
$ composer require tbela99/css
PHP version >= 5.6
$ composer require "tbela99/css:dev-php56-backport"
Requirements
- PHP version >= 8.0 on master branch.
- PHP version >= 5.6 supported in this branch
- mbstring extension
Usage:
h1 { color: green; color: blue; color: black; } h1 { color: #000; color: aliceblue; }
PHP Code
use \TBela\CSS\Parser; $parser = new Parser(); $parser->setContent(' h1 { color: green; color: blue; color: black; } h1 { color: #000; color: aliceblue; }'); echo $parser->parse();
Result
h1 { color: #f0f8ff; }
Parse the css file and generate the AST
use \TBela\CSS\Parser; use \TBela\CSS\Renderer; $parser = new Parser($css); $element = $parser->parse(); // append an existing css file $parser->append('https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css'); // append css string $parser->appendContent($css_string); // pretty print css $css = (string) $element; // minified output $renderer = new Renderer([ 'compress' => true, 'convert_color' => 'hex', 'css_level' => 4, 'sourcemap' => true, 'allow_duplicate_declarations' => false ]); // fast $css = $renderer->renderAst($parser); // or $css = $renderer->renderAst($parser->getAst()); // slow $css = $renderer->render($element); // generate sourcemap -> css/all.css.map $renderer->save($element, 'css/all.css'); // save as json file_put_contents('style.json', json_encode($element));
Load the AST and generate css code
use \TBela\CSS\Renderer; // fastest way to render css $beautify = (new Renderer())->renderAst($parser->setContent($css)->getAst()); // or $beautify = (new Renderer())->renderAst($parser->setContent($css)); // or $css = (new Renderer())->renderAst(json_decode(file_get_contents('style.json')));
use \TBela\CSS\Renderer; $ast = json_decode(file_get_contents('style.json')); $renderer = new Renderer([ 'convert_color' => true, 'compress' => true, // minify the output 'remove_empty_nodes' => true // remove empty css classes ]); $css = $renderer->renderAst($ast);
Sourcemap generation
$renderer = new Renderer([ 'sourcemap' => true ]); // call save and specify the file name // generate sourcemap -> css/all.css.map $renderer->save($element, 'css/all.css');
The CSS Query API
Example: get all background and background-image declarations that contain an image url
$element = Element::fromUrl('https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css'); foreach ($element->query('[@name=background][@value*="url("]|[@name=background-image][@value*="url("]') as $p) { echo "$p\n"; }
result
.form-select { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c /svg%3e") } .form-check-input:checked[type=checkbox] { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/s vg%3e") } ...
Example: Extract Font-src declaration
CSS source
@font-face { font-family: "Bitstream Vera Serif Bold"; src: url("/static/styles/libs/font-awesome/fonts/fontawesome-webfont.fdf491ce5ff5.woff"); } body { background-color: green; color: #fff; font-family: Arial, Helvetica, sans-serif; } h1 { color: #fff; font-size: 50px; font-family: Arial, Helvetica, sans-serif; font-weight: bold; } @media print { @font-face { font-family: MaHelvetica; src: local("Helvetica Neue Bold"), local("HelveticaNeue-Bold"), url(MgOpenModernaBold.ttf); font-weight: bold; } body { font-family: "Bitstream Vera Serif Bold", serif; } p { font-size: 12px; color: #000; text-align: left; } @font-face { font-family: Arial, MaHelvetica; src: local("Helvetica Neue Bold"), local("HelveticaNeue-Bold"), url(MgOpenModernaBold.ttf); font-weight: bold; } }
PHP source
use \TBela\CSS\Parser; $parser = new Parser(); $parser->setContent($css); $stylesheet = $parser->parse(); // get @font-face nodes by class names $nodes = $stylesheet->queryByClassNames('@font-face, .foo .bar'); // or // get all src properties in a @font-face rule $nodes = $stylesheet->query('@font-face/src'); echo implode("\n", array_map('trim', $nodes));
result
@font-face { src: url("/static/styles/libs/font-awesome/fonts/fontawesome-webfont.fdf491ce5ff5.woff"); } @media print { @font-face { src: local("Helvetica Neue Bold"), local("HelveticaNeue-Bold"), url(MgOpenModernaBold.ttf); } } @media print { @font-face { src: local("Helvetica Neue Bold"), local("HelveticaNeue-Bold"), url(MgOpenModernaBold.ttf); } }
render optimized css
$stylesheet->setChildren(array_map(function ($node) { return $node->copy()->getRoot(); }, $nodes)); $stylesheet->deduplicate(); echo $stylesheet;
result
@font-face { src: url(/static/styles/libs/font-awesome/fonts/fontawesome-webfont.fdf491ce5ff5.woff) } @media print { @font-face { src: local("Helvetica Neue Bold"), local(HelveticaNeue-Bold), url(MgOpenModernaBold.ttf) } }
CSS Nesting
table.colortable { & td { text-align:center; &.c { text-transform:uppercase } &:first-child, &:first-child + td { border:1px solid black } } & th { text-align:center; background:black; color:white; } }
render CSS nesting
use TBela\CSS\Parser; echo new Parser($css);
result
table.colortable { & td { text-align: center; &.c { text-transform: uppercase } &:first-child, &:first-child+td { border: 1px solid #000 } } & th { text-align: center; background: #000; color: #fff } }
convert nesting CSS to older representation
use TBela\CSS\Parser; use \TBela\CSS\Renderer; $renderer = new Renderer( ['legacy_rendering' => true]); echo $renderer->renderAst(new Parser($css));
result
table.colortable td { text-align: center } table.colortable td.c { text-transform: uppercase } table.colortable td:first-child, table.colortable td:first-child+td { border: 1px solid #000 } table.colortable th { text-align: center; background: #000; color: #fff }
The Traverser Api
The traverser will iterate over all the nodes and process them with the callbacks provided. It will return a new tree Example using ast
use TBela\CSS\Ast\Traverser; use TBela\CSS\Parser; use TBela\CSS\Renderer; $parser = (new Parser())->load('ast/media.css'); $traverser = new Traverser(); $renderer = new Renderer(['remove_empty_nodes' => true]); $ast = $parser->getAst(); // remove @media print $traverser->on('enter', function ($node) { if ($node->type == 'AtRule' && $node->name == 'media' && $node->value == 'print') { return Traverser::IGNORE_NODE; } }); $newAst = $traverser->traverse($ast); echo $renderer->renderAst($newAst);
Example using an Element instance
use TBela\CSS\Ast\Traverser; use TBela\CSS\Parser; use TBela\CSS\Renderer; $parser = (new Parser())->load('ast/media.css'); $traverser = new Traverser(); $renderer = new Renderer(['remove_empty_nodes' => true]); $element = $parser->parse(); // remove @media print $traverser->on('enter', function ($node) { if ($node->type == 'AtRule' && $node->name == 'media' && $node->value == 'print') { return Traverser::IGNORE_NODE; } }); $newElement = $traverser->traverse($element); echo $renderer->renderAst($newElement);
Build a CSS Document
use \TBela\CSS\Element\Stylesheet; $stylesheet = new Stylesheet(); $rule = $stylesheet->addRule('div'); $rule->addDeclaration('background-color', 'white'); $rule->addDeclaration('color', 'black'); echo $stylesheet;
output
div { background-color: #fff; color: #000; }
$media = $stylesheet->addAtRule('media', 'print'); $media->append($rule);
output
@media print { div { background-color: #fff; color: #000; } }
$div = $stylesheet->addRule('div'); $div->addDeclaration('max-width', '100%'); $div->addDeclaration('border-width', '0px');
output
@media print { div { background-color: #fff; color: #000; } } div { max-width: 100%; border-width: 0; }
$media->append($div);
output
@media print { div { background-color: #fff; color: #000; } div { max-width: 100%; border-width: 0; } }
$stylesheet->insert($div, 0);
output
div { max-width: 100%; border-width: 0; } @media print { div { background-color: #fff; color: #000; } }
Adding existing css
// append css string $stylesheet->appendCss($css_string); // append css file $stylesheet->append('style/main.css'); // append url $stylesheet->append('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/brands.min.css');
Performance
Utility methods
The renderer class provides utility methods to format css data
$css = \TBela\CSS\Renderer::fromFile($url_or_file, $renderOptions = [], $parseOptions = []); # $css = \TBela\CSS\Renderer::fromString($css, $renderOptions = [], $parseOptions = []);
Manual parsing and rendering
parsing and rendering ast is 3x faster than parsing an element.
use \TBela\CSS\Element\Parser; use \TBela\CSS\Element\Renderer; $parser = new Parser($css); // parse and render echo (string) $parser; // or render minified css $renderer = new Renderer(['compress' => true]); echo $renderer->renderAst($parser); # or echo $renderer->renderAst($parser->getAst()); # or // slower - will build a stylesheet object echo $renderer->render($parser->parse());
Parser Options
- flatten_import: process @import directive and import the content into the css document. default to false.
- allow_duplicate_rules: allow duplicated rules. By default, duplicate rules except @font-face are merged
- allow_duplicate_declarations: allow duplicated declarations in the same rule.
- capture_errors: silently capture parse error if true, otherwise throw a parse exception. Default to true
Renderer Options
- remove_comments: remove comments.
- preserve_license: preserve comments starting with '/*!'
- compress: minify output, will also remove comments
- remove_empty_nodes: do not render empty css nodes
- compute_shorthand: compute shorthand declaration
- charset: preserve @charset. default to false
- glue: the line separator character. default to '\n'
- indent: character used to pad lines in css, default to a space character
- convert_color: convert colors to a format between hex, hsl, rgb, hwb and device-cmyk
- css_level: produce CSS color level 3 or 4. default to 4
- allow_duplicate_declarations: allow duplicate declarations.
- legacy_rendering: convert nesting css. default false
Command line utility
the command line utility is located at './cli/css-parser'
$ ./cli/css-parser -h Usage: $ css-parser [OPTIONS] [PARAMETERS] -v, --version print version number -h print help --help print extended help Parse options: -e, --capture-errors ignore parse error -f, --file input css file or url -m, --flatten-import process @import -I, --input-format input format: json (ast), serialize (PHP serialized ast) -d, --parse-allow-duplicate-declarations allow duplicate declaration -p, --parse-allow-duplicate-rules allow duplicate rule -P, --parse-children-process maximum children process -M, --parse-multi-processing enable multi-processing parser Render options: -a, --ast dump ast as JSON -S, --charset remove @charset -c, --compress minify output -u, --compute-shorthand compute shorthand properties -t, --convert-color convert colors -l, --css-level css color module -G, --legacy-rendering convert nested css syntax -o, --output output file name -F, --output-format output export format. string (css), json (ast), serialize (PHP serialized ast), json-array, serialize-array, requires --input-format -L, --preserve-license preserve license comments -C, --remove-comments remove comments -E, --remove-empty-nodes remove empty nodes -r, --render-allow-duplicate-declarations render duplicate declarations -R, --render-multi-processing enable multi-processing renderer -s, --sourcemap generate sourcemap, requires --file
Minify inline css
$ ./cli/css-parser 'a, div {display:none} b {}' -c # $ echo 'a, div {display:none} b {}' | ./cli/css-parser -c
Minify css file
$ ./cli/css-parser -f nested.css -c # $ ./cli/css-parser -f 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/brands.min.css' -c
Dump ast
$ ./cli/css-parser -f nested.css -f 'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css' -c -a # $ ./cli/css-parser 'a, div {display:none} b {}' -c -a # $ echo 'a, div {display:none} b {}' | ./cli/css-parser -c -a
The full documentation can be found here
Thanks to Jetbrains for providing a free PhpStorm license
This was originally a PHP port of https://github.com/reworkcss/css
tbela99/css 适用场景与选型建议
tbela99/css 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 479 次下载、GitHub Stars 达 15, 最近一次更新时间为 2019 年 12 月 02 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「php」 「css」 「parser」 「minifier」 「stylesheet」 「ast」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 tbela99/css 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 tbela99/css 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 tbela99/css 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
A Twig extension to insert css as inline styles with a tag
Easy to use SDK with grabber for multiple platforms at once like YouTube, Dailymotion, Facebook and more.
Caching and compression for Twig assets (JavaScript and CSS).
An MT940 bank statement parser for PHP
Laravel integration for the jsonapi.org parser
Define your own css rule-sets for the TYPO3 CMS backend.
统计信息
- 总下载量: 479
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 15
- 点击次数: 3
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2019-12-02