承接 alnaggar/php-css-builder 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

alnaggar/php-css-builder

最新稳定版本:1.0

Composer 安装命令:

composer require alnaggar/php-css-builder

包简介

A simple, fluent, structured CSS builder for PHP.

README 文档

README

I Stand With Palestine Badge

I Stand With Palestine Banner

Latest Stable Version Total Downloads License

PHP CSS Builder allows you to programmatically generate CSS using a fluent, chainable API.

It supports:

  • Standard CSS rulesets (selectors + declarations)
  • Statement at-rules (e.g. @import, @charset)
  • Block at-rules (e.g. @media, @supports, @layer)
  • Nested CSS statements
  • CSS comments
  • Embedded CSS (<style> blocks)

Warning

This package does not perform any form of sanitization, validation, escaping, or filtering of input values.

It is designed purely as a CSS construction and formatting tool and will output exactly what the developer provides.

All responsibility for security, correctness, and safety of the generated output lies with the developer using this package, especially when handling user-provided or untrusted data.

Table of Contents

Requirements

  • PHP 7.3+
  • ext-pcre PHP extension

Installation

Install the package using Composer:

composer require alnaggar/php-css-builder

Usage & Architecture

This package is a programmatic CSS builder, not a parser, validator, or sanitizer. It allows you to compose CSS using PHP objects, mirroring the actual CSS grammar.

The design is intentionally split into small, focused classes, each representing a real CSS concept.

Core Concepts

  1. Every statement is a Cssable

    Every statement class implements the Cssable interface, meaning it can independently render CSS via toCss().

    namespace Alnaggar\PhpCssBuilder\Interfaces;
    
    interface Cssable
    {
        public function toCss(): string;
    }
  2. CSS Is Built From Statements

    The package models CSS as a tree of statements.

    All CSS statements implement:

    namespace Alnaggar\PhpCssBuilder\Interfaces;
    
    interface CssStatement extends Cssable
    {
        
    }

Statement Types

  1. CssRuleset (Selector Blocks)

    Represents a standard CSS selector block (e.g. :root, *::before, h1).

    Example:

    use Alnaggar\PhpCssBuilder\Statements\CssRuleset;
    
    CssRuleset::make('.card')
        ->comment('Card base styles')
        ->declaration('padding', '1rem')
        ->declaration('border-radius', '6px')
        ->toCss();

    Outputs:

    /* Card base styles */
    .card {
        padding: 1rem;
        border-radius: 6px;
    }

    Nesting support:

    A ruleset can nest:

    • Other rulesets

    • Block at-rules

    This allows output suitable for CSS preprocessors:

    use Alnaggar\PhpCssBuilder\Statements\CssRuleset;
    
    CssRuleset::make('.card')
        ->declaration('padding', '1rem')
        ->nestedStatement(
            CssRuleset::make('&:hover')
                ->declaration('background', '#eee')
        )
        ->toCss();

    Outputs:

    .card {
        padding: 1rem;
        &:hover {
            background: #eee;
        }
    }
  2. CssBlockAtRule

    Represents at-rules that contain blocks (e.g. @media, @supports, @layer, @page, @top-right).

    Example:

    use Alnaggar\PhpCssBuilder\Statements\CssBlockAtRule;
    use Alnaggar\PhpCssBuilder\Statements\CssRuleset;
    
    CssBlockAtRule::make('media', '(max-width: 768px)')
        ->nestedStatement(
            CssRuleset::make('.card')
                ->declaration('font-size', '14px')
        )
        ->toCss();

    Outputs:

    @media (max-width: 768px) {
        .card {
            font-size: 14px;
        }
    }

    Nesting support:

    A block at-rule can nest:

    • Rulesets

    • Other block at-rules

    Example:

    use Alnaggar\PhpCssBuilder\Statements\CssBlockAtRule;
    use Alnaggar\PhpCssBuilder\Statements\CssRuleset;
    
    CssBlockAtRule::make('layout', 'components')
    ->nestedStatement(
        CssBlockAtRule::make('supports', '(backdrop-filter: blur(10px))')
            ->nestedStatement(
                CssRuleset::make('.card-glass')
                    ->declaration('backdrop-filter', 'blur(10px)')
                    ->declaration('background', 'rgba(2, 6, 23, 0.7)')
            )
    )->toCss()

    Outputs:

    @layer components {
        @supports (backdrop-filter: blur(10px)) {
            .card-glass {
                backdrop-filter: blur(10px);
                background: rgba(2, 6, 23, 0.7);
            }
        }
    }
  3. CssStatementAtRule (Single-Line At-Rules)

    Represents non-block at-rules (e.g. @import @charset @namespace).

    Example:

    use Alnaggar\PhpCssBuilder\Statements\CssStatementAtRule;
    
    CssStatementAtRule::make('import', 'url("theme.css")')->toCss();

    Outputs:

    @import url("theme.css");

Nestable Statements

Only statements that implement NestableCssStatement can be nested.

namespace Alnaggar\PhpCssBuilder\Interfaces;

interface NestableCssStatement extends CssStatement
{
        
}

These are:

CssRuleset

CssBlockAtRule

This ensures:

  • Invalid CSS structures are not accidentally created
  • Nesting mirrors real CSS grammar
  • Output can safely target preprocessors

EmbeddedCss (HTML <style> Container)

EmbeddedCss is the final output container.

It:

  • Collects multiple CSS statements
  • Outputs a valid <style> HTML block
  • Supports optional <style> tag attributes

Complete Example:

use Alnaggar\PhpCssBuilder\Html\EmbeddedCss;

/*
|--------------------------------------------------------------------------
| Create embedded stylesheet
|--------------------------------------------------------------------------
*/

$embeddedCss = EmbeddedCss::make();

/*
|--------------------------------------------------------------------------
| Style tag attributes
|--------------------------------------------------------------------------
*/

$embeddedCss->attribute('nonce', 'nonce-123')
    ->attribute('id', 'embedded-css');

/*
|--------------------------------------------------------------------------
| Comment
|--------------------------------------------------------------------------
*/

$embeddedCss->comment(
    'Base document styles'
);

/*
|--------------------------------------------------------------------------
| Statement at-rules
|--------------------------------------------------------------------------
*/

$embeddedCss->statements([
    CssStatementAtRule::make('charset', '"UTF-8"'),
    CssStatementAtRule::make('import', 'url("https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap")')
]);

/*
|--------------------------------------------------------------------------
| Font face
|--------------------------------------------------------------------------
*/

$embeddedCss->newline();

$embeddedCss->statement(
    CssBlockAtRule::make('font-face', null)
        ->declaration('font-family', '"Panel Font"')
        ->declaration('src', 'url(\'assets/fonts/panel.woff2\') format(\'woff2\')')
        ->declaration('font-weight', 'normal')
        ->declaration('font-style', 'normal')
);

/*
|--------------------------------------------------------------------------
| Base styles
|--------------------------------------------------------------------------
*/

$embeddedCss->newline();

$embeddedCss->statements([
    CssRuleset::make(':root')
        ->declaration('--text-primary-color', '#DBEAFE')
        ->declaration('--bg-primary-color', '#2563EB')
        ->declaration('--text-secondary-color', '#111827')
        ->declaration('--bg-secondary-color', '#F3F4F6')
        ->declaration('--radius', '0.5rem'),

    CssRuleset::make('*, *::before, *::after')
        ->declaration('box-sizing', 'border-box'),

    CssRuleset::make('body')
        ->comment('Reset & typography')
        ->declaration('margin', '0')
        ->declaration('font-family', '"Panel Font", "Inter", system-ui, sans-serif')
        ->declaration('background', '#0f172a')
        ->declaration('color', '#e5e7eb')
        ->declaration('line-height', '1.6')
]);

/*
|--------------------------------------------------------------------------
| Utilities
|--------------------------------------------------------------------------
*/

$embeddedCss->newline();

$embeddedCss->statements([
    CssRuleset::make('.text-primary')
        ->declaration('color', 'var(--text-primary-color)'),
    CssRuleset::make('.bg-primary')
        ->declaration('background', 'var(--bg-primary-color)'),
    CssRuleset::make('.text-secondary')
        ->declaration('color', 'var(--text-secondary-color)'),
    CssRuleset::make('.bg-secondary')
        ->declaration('background', 'var(--bg-secondary-color)'),
]);

/*
|--------------------------------------------------------------------------
| Components
|--------------------------------------------------------------------------
*/

$embeddedCss->newline();

$embeddedCss->statements([
    CssRuleset::make('.panel')
        ->declaration('padding', '1.5rem')
        ->declaration('border-radius', 'var(--radius)')
        ->declaration('background', '#020617'),

    CssRuleset::make('.panel-title')
        ->declaration('font-size', '1.25rem')
        ->declaration('font-weight', '600')
        ->declaration('margin-bottom', '0.75rem'),

    CssRuleset::make('.btn')
        ->declaration('display', 'inline-flex')
        ->declaration('align-items', 'center')
        ->declaration('gap', '0.5rem')
        ->declaration('padding', '0.5rem 0.75rem')
        ->declaration('border-radius', 'var(--radius)')
        ->declaration('border', 'none')
        ->declaration('cursor', 'pointer')
]);

/*
|--------------------------------------------------------------------------
| Animations
|--------------------------------------------------------------------------
*/

$embeddedCss->newline();

$embeddedCss->statement(
    CssBlockAtRule::make('keyframes', 'fade-in')
        ->nestedStatement(
            CssRuleset::make('from')
                ->declaration('opacity', '0')
        )
        ->newline()
        ->nestedStatement(
            CssRuleset::make('to')
                ->declaration('opacity', '1')
        )
);

$embeddedCss->newline();

$embeddedCss->statement(
    CssRuleset::make('.fade-in')
        ->declaration('animation', 'fade-in 200ms ease-in-out')
);

/*
|--------------------------------------------------------------------------
| Media queries
|--------------------------------------------------------------------------
*/

$embeddedCss->newline();

$embeddedCss->statement(
    CssBlockAtRule::make('media', '(max-width: 768px)')
        ->nestedStatements([
            CssRuleset::make('.panel')
                ->declaration('padding', '1rem'),

            CssRuleset::make('.panel-title')
                ->declaration('font-size', '1.1rem')
        ])
);

/*
|--------------------------------------------------------------------------
| Feature queries
|--------------------------------------------------------------------------
*/

$embeddedCss->newline();

$embeddedCss->statement(
    CssBlockAtRule::make('supports', '(backdrop-filter: blur(10px))')
        ->nestedStatement(
            CssRuleset::make('.panel-glass')
                ->declaration('backdrop-filter', 'blur(10px)')
                ->declaration('background', 'rgba(2, 6, 23, 0.7)')
        )
);

return $embeddedCss->toHtml();

Outputs:

<style nonce="nonce-123" id="embedded-css">
    /* Base document styles */
    @charset "UTF-8";
    @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap");

    @font-face {
        font-family: "Panel Font";
        src: url('assets/fonts/panel.woff2') format('woff2');
        font-weight: normal;
        font-style: normal;
    }

    :root {
        --text-primary-color: #DBEAFE;
        --bg-primary-color: #2563EB;
        --text-secondary-color: #111827;
        --bg-secondary-color: #F3F4F6;
        --radius: 0.5rem;
    }
    *, *::before, *::after {
        box-sizing: border-box;
    }
    body {
        /* Reset & typography */
        margin: 0;
        font-family: "Panel Font", "Inter", system-ui, sans-serif;
        background: #0f172a;
        color: #e5e7eb;
        line-height: 1.6;
    }

    .text-primary {
        color: var(--text-primary-color);
    }
    .bg-primary {
        background: var(--bg-primary-color);
    }
    .text-secondary {
        color: var(--text-secondary-color);
    }
    .bg-secondary {
        background: var(--bg-secondary-color);
    }

    .panel {
        padding: 1.5rem;
        border-radius: var(--radius);
        background: #020617;
    }
    .panel-title {
        font-size: 1.25rem;
        font-weight: 600;
        margin-bottom: 0.75rem;
    }
    .btn {
        display: inline-flex;
        align-items: center;
        gap: 0.5rem;
        padding: 0.5rem 0.75rem;
        border-radius: var(--radius);
        border: none;
        cursor: pointer;
    }

    @keyframes fade-in {
        from {
            opacity: 0;
        }

        to {
            opacity: 1;
        }
    }

    .fade-in {
        animation: fade-in 200ms ease-in-out;
    }

    @media (max-width: 768px) {
        .panel {
            padding: 1rem;
        }
        .panel-title {
            font-size: 1.1rem;
        }
    }

    @supports (backdrop-filter: blur(10px)) {
        .panel-glass {
            backdrop-filter: blur(10px);
            background: rgba(2, 6, 23, 0.7);
        }
    }
</style>

Contributing

If you find any issues or have suggestions for improvements, feel free to open an issue or submit a pull request on the GitHub repository.

Credits

License

PhpCssBuilder is open-sourced software licensed under the MIT license.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-12-22