Forward Semantic CSS Refactoring & Modernization

CSSForge is a blazing-fast, 100% cascade-safe, multi-platform CSS transformation engine and interactive terminal workbench written in Rust. Refactor flat legacy CSS into modern native nesting, :is() clusters, and Range media queries with zero declaration loss and mathematical specificity proof guarantees.

📦 Installation

Install CSSForge globally across all major platforms using Cargo or download pre-compiled standalone binary releases:

If you have Rust installed, install CSSForge directly from crates.io:

cargo install cssforge

This places cssforge directly into your ~/.cargo/bin directory.

1. Download the archive for your architecture from GitHub Releases.

2. Extract and copy to your local user binary directory (no sudo required):

tar -xvf cssforge-v0.3.1-linux-x64.tar.gz
cp cssforge-v0.3.1-linux-x64/cssforge ~/.local/bin/
chmod +x ~/.local/bin/cssforge

3. Verify installation: cssforge --version

1. Download cssforge-v0.3.1-macos-arm64.tar.gz from GitHub Releases.

2. Extract and copy to user path:

tar -xvf cssforge-v0.3.1-macos-arm64.tar.gz
cp cssforge-v0.3.1-macos-arm64/cssforge ~/.local/bin/
chmod +x ~/.local/bin/cssforge

3. Verify installation: cssforge --version

1. Download cssforge-v0.3.1-windows-x64.zip or cssforge-v0.3.1-windows-arm64.zip from GitHub Releases.

2. Extract cssforge.exe and add its folder to your system Path.

# In PowerShell or CMD:
cssforge.exe --version

🚀 Quick Start & Usage

CSSForge automatically discovers CSS files in the current working directory where you execute it:

1. Run in Any Project Directory (Automatic Discovery)

# 1. Navigate to your project folder:
cd /path/to/my-web-app

# 2. Launch interactive modernization:
cssforge

2. Target a Specific Folder or File

# Target specific styles folder:
cssforge interactive ./src/css

# Or target a single file:
cssforge interactive ./src/styles.css

3. Fast Headless CLI for CI/CD & Automation

# Analyze CSS files and report modernization opportunities:
cssforge analyze ./src

# Analyze and emit structured JSON for pipelines:
cssforge analyze ./src --json

# Apply modern preset to new (*.modern.css) files:
cssforge apply ./src/app.css --preset modern --output new-file

# In-place overwrite with automatic safety backup (.bak):
cssforge apply ./src/app.css --output overwrite-with-backup --yes

📁 Smart File Discovery & Default Ignored Conventions

When scanning directories recursively, CSSForge applies zero-config safety ignore filters to prevent accidental corruption of generated files or vendor libraries:

  • Build & Dependency Folders (node_modules/, vendor/, target/, dist/, build/, out/, .next/, .nuxt/, .turbo/, .svelte-kit/): Ignored to protect compiled bundles and 3rd-party dependencies.
  • Version Control Internals (.git/, .hg/, .svn/, .cache/): Ignored to keep repo metadata safe.
  • Generated Modern Files (*.modern.css): Ignored to prevent recursive re-modernization loops on newly generated output.
  • Minified & Chunks (*.min.css, *.bundle.css, *.chunk.css, *.map.css): Ignored because minified code is not meant for source AST refactoring.
  • Safety Backups (*.bak.css, *.backup.css): Preserved as untouched recovery snapshots.

Note: If you explicitly pass a file path (e.g. cssforge interactive ./dist/custom.min.css), CSSForge honors your explicit request. Standard .gitignore and .ignore files are also respected automatically.

🖥️ Interactive TUI Visual Workbench

CSSForge features a full-screen, responsive terminal interface powered by Ratatui and Crossterm:

cssforge — Step 1 of 4: Select Files
  ____ ____ ____  _____ ___  ____   ____ _____ 
 / ___/ ___/ ___||  ___/ _ \|  _ \ / ___| ____|
| |   \___ \___ \| |_ | | | | |_) | |  _|  _|  
| |___ ___) |__) |  _|| |_| |  _ <| |_| | |___ 
 \____|____/____/|_|   \___/|_| \_\\____|_____|
Forward semantic CSS modernization • nest • refactor • review

Choose the CSS files you want to modernize. Press [Space] to toggle, [a] for all:

[x] src/components/card.css
[x] src/components/button.css
[x] src/styles/theme.css

[Enter] Next: Rules → [Space] Toggle [p] Preset: Modern [d] Live Diff [q] Quit
Keybinding Action
[Enter]Advance to next step / Apply & Finish
[Space]Toggle highlighted file, rule, or setting
[a]Select / Deselect All
[p]Cycle presets (ConservativeModernRefactorAggressive)
[d] / [v]Open live full-screen split/unified code diff viewer
[Esc] / [b]Go back to previous step
[1][4]Jump directly to Step 1 (Files), 2 (Rules), 3 (Output), 4 (Done)
[q]Quit workbench

⚙️ 26 Transformation Rules Catalog

Explore the complete inventory of 26 automated refactoring and modernization rules:

Showing all 26 transformation rules
nest-pseudo-class Safe
Nests adjacent pseudo-states (:hover, :focus, :active, :focus-visible) into the parent rule using &.
- .card:hover { border-color: blue; }
+ .card { &:hover { border-color: blue; } }
nest-pseudo-element Safe
Nests pseudo-elements (::before, ::after, ::placeholder) into the parent rule using &.
- .btn::before { content: ""; }
+ .btn { &::before { content: ""; } }
nest-attribute Safe
Nests attribute selectors ([disabled], [aria-*]) into the parent rule cleanly.
- input[disabled] { opacity: 0.5; }
+ input { &[disabled] { opacity: 0.5; } }
nest-compound Safe
Nests compound class variants (.item.active, .btn.primary) into the parent rule.
- .item.active { font-weight: bold; }
+ .item { &.active { font-weight: bold; } }
nest-descendant Safe
Nests descendant selectors into the parent rule without redundant string prefixes.
- .card .title { font-size: 1.5rem; }
+ .card { .title { font-size: 1.5rem; } }
nest-combinator Safe
Nests child (>), adjacent sibling (+), and general sibling (~) selectors.
- .nav > .item { display: inline-block; }
+ .nav { > .item { display: inline-block; } }
factor-selector-list Safe
Factors comma-separated selector lists sharing a base selector into a unified nested block.
- .dot, .dot::before { color: red; }
+ .dot { &, &::before { color: red; } }
nest-media Safe
Inlines matching @media queries directly into the parent selector block without breaking cascade.
- @media (min-width: 768px) { .box { padding: 2rem; } }
+ .box { @media (min-width: 768px) { padding: 2rem; } }
nest-supports Safe
Inlines @supports feature queries directly into the parent selector block.
- @supports (display: grid) { .box { display: grid; } }
+ .box { @supports (display: grid) { display: grid; } }
nest-container Safe
Inlines container queries (@container) directly into the target component block.
- @container (min-width: 400px) { .card { flex-direction: row; } }
+ .card { @container (min-width: 400px) { flex-direction: row; } }
nest-starting-style Safe
Inlines @starting-style transition entry rules directly into the target selector.
- @starting-style { dialog { opacity: 0; } }
+ dialog { @starting-style { opacity: 0; } }
consolidate-not Modernize
Consolidates chained legacy :not() selectors into a single comma-separated :not(a, b).
- .btn:not(.primary):not(.secondary)
+ .btn:not(.primary, .secondary)
modernize-is Modernize
Factors multi-selector clusters sharing identical bases into unified :is(...) blocks with nested rules.
- .a .title, #hero .title { font-size: 1.2rem; }
+ :is(.a, #hero) { .title { font-size: 1.2rem; } }
modernize-where Modernize
Factors default rules into :where(...) blocks for zero-specificity design system defaults.
- .card, .panel, .dialog { border: 1px solid #ccc; }
+ :where(.card, .panel, .dialog) { border: 1px solid #ccc; }
modernize-media-range-syntax Modernize
Converts legacy min/max-width queries to modern CSS Range syntax.
- @media (min-width: 768px) and (max-width: 1024px)
+ @media (768px <= width <= 1024px)
merge-same-named-layer Refactor
Consolidates separated blocks of the same named @layer into their canonical first block.
- @layer comps { ... } /* later */ @layer comps { ... }
+ @layer comps { /* unified block */ }
merge-adjacent-media Refactor
Combines consecutive @media blocks sharing identical query conditions into a single block.
- @media (min-width: 600px) { .a {} } @media (min-width: 600px) { .b {} }
+ @media (min-width: 600px) { .a {} .b {} }
merge-adjacent-supports Refactor
Combines consecutive @supports blocks sharing identical feature conditions into a single block.
- @supports (display: grid) { ... } @supports (display: grid) { ... }
+ @supports (display: grid) { /* combined */ }
merge-adjacent-container Refactor
Combines consecutive @container blocks sharing identical query conditions.
- @container (min-width: 400px) { .x {} } @container (min-width: 400px) { .y {} }
+ @container (min-width: 400px) { .x {} .y {} }
merge-identical-scope Refactor
Combines consecutive @scope blocks sharing identical root and limit parameters.
- @scope (.card) { ... } @scope (.card) { ... }
+ @scope (.card) { /* combined */ }
merge-identical-starting-style Refactor
Combines consecutive top-level @starting-style blocks into a single block.
- @starting-style { ... } @starting-style { ... }
+ @starting-style { /* combined */ }
merge-adjacent-identical-selector Refactor
Combines consecutive style rules sharing the exact same selector into a single declaration block.
- .btn { color: red; } .btn { padding: 1rem; }
+ .btn { color: red; padding: 1rem; }
merge-identical-rule-bodies Refactor
Combines selectors sharing identical declaration bodies into a unified comma-separated rule.
- .a { color: red; } .b { color: red; }
+ .a, .b { color: red; }
factor-identical-states-with-is Refactor
Combines multiple states of the same element sharing identical declarations into &:is(:hover, :focus).
- .btn:hover, .btn:focus { background: blue; }
+ .btn { &:is(:hover, :focus) { background: blue; } }
gather-related-selector-rules Refactor
Gathers scattered non-adjacent occurrences of the same selector into the canonical first rule block.
- .box { padding: 1rem; } /* later */ .box { margin: 0; }
+ .box { padding: 1rem; margin: 0; }
prune-overridden-declarations Refactor
Removes dead properties and entire rules overridden unconditionally later in the cascade.
- color: red;
+ color: blue; /* kept winning override */

🔬 The 8-Point Safety & Proof Engine

CSS is order-sensitive and specificity-fragile. CSSForge verifies 8 strict mathematical invariants before applying any mutation:

Invariant Proof Check Guarantee & Protection
specificity_equivalent Guarantees that :is() factoring does not lift branch weights or break later cascade overrides.
declarations_preserved 100% exact retention of property names, values, vendor prefixes, and custom properties.
important_preserved Strict retention of all !important flags across nested or refactored rules.
cascade_order_equivalent Ensures no intervening rules are crossed during non-adjacent nesting or grouping.
at_rule_equivalent Ensures query expressions in @media, @supports, and @container are unchanged.
layer_precedence_equivalent Safeguards normal and important declaration ordering inside @layer blocks.
scope_boundary_equivalent Prevents invalid automatic conversion into @scope without explicit design boundaries.
syntax_lossless Splices replacements strictly into target byte spans. Untouched lines remain 100% byte-for-byte identical.

💡 Why CSSForge? & The Gaps We Filled

The CSS tooling ecosystem has long suffered from a structural asymmetry:

Direction Ecosystem State Existing Tools The Dilemma
Nested ➔ Flat Lowering Mature Lightning CSS, PostCSS Nesting, esbuild, LibSass Deterministic, mechanical compiler lowering. Desugaring & into flat rules or :is() is grammatically straightforward.
Flat ➔ Modern Nested Fragmented NestYourCSS, stylelint-use-nesting, css-nesting-converter Cascade-sensitive refactoring problem. Existing tools either produce invalid CSS, break specificity, destroy code formatting, or only fold basic :hover states.

Critical Gaps Solved by CSSForge

🛡️
Dual-Layer Zero-Regression Engine
LightningCSS AST parser is used purely for grammatical validation. All file mutations are performed by a surgical Byte Patch Engine that replaces strictly target byte spans. Untouched lines, developer comments, custom indentation, and quote styles remain 100% byte-for-byte identical.
🔬
Mathematical Specificity Proofs
Calculates exact specificity vectors (a, b, c) for every input and modernized selector branch. Zero specificity drift guarantee ensures elements match with identical priority across browsers.
🚫
Refusal as a Core Safety Feature
When an AST transform would violate native CSS semantics (such as :is() lifting specificity on lower branches or invalid BEM string concatenation), CSSForge explicitly refuses the transformation instead of generating broken stylesheets.
Multi-Selector Cluster Factoring
The first and only tool capable of gathering multi-branch rules sharing identical bases (e.g. .card .title, #hero .title + .card, #hero) into unified, clean :is() blocks with nested children.
🖥️
Zero-Config Terminal TUI Workbench
A full-screen, responsive keyboard-driven interactive workbench powered by Ratatui & Crossterm with live unified diff viewing ([d]), preset cycling ([p]), and 4-step guided refactoring.
🔒
Dirty Git Working Tree Guard
Detects uncommitted Git modifications before writing and automatically blocks destructive in-place replacements unless explicitly confirmed by the user.

🚫 Strict Non-Goals: What We Do NOT & Will NOT Do

To preserve 100% cascade safety and developer trust, CSSForge enforces clear architectural boundaries and will never attempt unsound heuristics:

❌ Anti-Goal

No BEM String Concatenation (&__element)

In native CSS, & is a selector token (desugars to :is()), NOT a Sass string concatenator. Writing .card { &__title { } } is invalid in native CSS. CSSForge strictly refuses BEM token concatenation.

❌ Anti-Goal

No Specificity Inflation / Lifting

:is(A, B) takes the maximum specificity of all branches. If wrapping rules into :is() would artificially lift the specificity of a lower-specificity branch and alter cascade matching priority, CSSForge refuses the refactor.

❌ Anti-Goal

No Destructive Minification or Re-Serialization

CSSForge is a semantic modernizer, not a destructive minifier. We will never re-format untouched code, strip developer comments, convert colors, or drop intentional browser fallback duplicate declarations.

❌ Anti-Goal

No Pseudo-Element Nesting Traps

Native CSS & cannot legally nest under parent selectors containing pseudo-elements (e.g. ::before, ::after, ::marker). CSSForge strictly identifies and prevents invalid pseudo-element nesting.

❌ Anti-Goal

No Arbitrary At-Rule Moving Across Barriers

We will never hoist or pack @media / @supports blocks across intervening selector barriers if moving them would invert the source-order cascade for overlapping properties.

❌ Anti-Goal

No Runtime Heuristic Guesswork

We do not guess at runtime JavaScript class additions or dynamically toggled DOM hierarchies. All refactoring operations are statically verifiable and mathematically provable.

📊 Global Market Comparison Matrix

A comprehensive architectural comparison of CSSForge against existing industry tools:

Tool / Project Primary Focus Strengths Critical Gaps & Weaknesses CSSForge Advantage
Lightning CSS
(Parcel / Rust)
Nested ➔ Flat & Lowering Blazing fast (2.7M lines/s), browser-target aware. Not an aesthetic refactorer. Does not modernize flat CSS to nested CSS; reserializes entire AST. Lossless Modernizer Dual-layer patch engine preserving untouched lines & comments.
NestYourCSS
(@nycss)
Flat ⇄ Nested Balanced/Max depth strategies, Web GUI + CLI. Uses character lexer without semantic proof engine; cannot prove non-adjacent safety or at-rule safety. Mathematical Proofs Full 8-point invariant proof engine with zero specificity drift.
stylelint-use-nesting
(CSSTools)
Flat ➔ Nested Linter Safe, incremental autofix. Narrow scope: only folds immediate adjacent pseudo-classes (:hover). No :is() factoring or at-rule restructuring. 26 Rules Catalog Handles complex combinators, multi-branch clustering, and at-rule merging.
css-nesting-converter Flat ⇄ Nested CLI PostCSS plugin, layer wrapping. Strips SCSS variables blindly; lacks specificity verification and cluster factoring. Safe Clustering Preserves all variables, prefixes, and declarations with zero loss.
postcss-nested
(Evil Martians)
Nested ➔ Flat (Sass-like) 14M+ weekly downloads, popular in build setups. Violates native CSS semantics. Employs Sass-style string concatenation rather than :is() tokens. Native W3C Standard Strictly emits spec-compliant native CSS nesting and modern selectors.
cssnano Minification Merges adjacent rules, discards dead code. Destructive by default: drops comments, strips intentional duplicate fallback declarations. Lossless Refactoring Retains duplicate declarations, custom properties, and fallback fall-throughs.

💾 7 Output Modes

CSSForge provides flexible output strategies for testing, safe local refactoring, and automated CI pipelines:

Mode Flag Description Recommended For
--output dry-run Calculates all plans and displays diffs without touching any files on disk. Audits, exploratory reviews
--output new-file Writes modernized stylesheets to sibling *.modern.css files. Safe local trial (Default)
--output out-dir <path> Mirrors project folder structure into a designated build directory. Build tools, bundlers
--output overwrite-with-backup Overwrites the source file while creating an automatic *.bak copy. Local refactoring
--output overwrite Atomic in-place replacement (Requires Git clean tree check). Version-controlled codebases
--output patch Generates a unified *.patch file compatible with git apply. Code reviews, PR workflows
--output stdout Outputs modernized CSS directly to stdout for Unix pipeline piping. Command-line piping

📦 Crate Architecture

CSSForge is organized as a modular Rust workspace published across three official packages:

Crate Name crates.io Documentation Role
cssforge v0.3.1 Docs.rs Standalone multi-platform CLI and TUI workbench executable.
cssforge-core v0.3.1 Docs.rs Pure Rust AST parser, specificity engine, and 26 transformation rules library.
cssforge-tui v0.3.1 Docs.rs Ratatui-powered terminal user interface component and visual diff viewer.