css-expr
v1.0.3
Published
Expression-driven CSS Property Binder - Dynamic CSS values using JavaScript expressions
Maintainers
Readme
css-expr
Dynamic CSS property binding using JavaScript expressions
Create responsive layouts that go beyond CSS media queries. Bind CSS properties to element dimensions, implement conditional styling, and build mathematical relationships between elements with declarative expressions.
Features
- Declarative Syntax - Express complex responsive behavior in HTML attributes
- Rich Expressions - Mathematical functions, conditionals, logical operators
- Unit Support - Seamless conversion between px, vw, vh, em, rem, %
Quick Start
Installation
npm install css-exprBasic Usage
<div id="container" style="width: 1000px; height: 600px;">
<div data-expression="
this.width = el('#container').width * 0.6;
this.height = el('#container').height * 0.4;
this.backgroundColor = this.width > 400 ? 'lightblue' : 'lightcoral';
">
Responsive content that adapts to its container
</div>
</div>CDN Usage
<script src="https://unpkg.com/css-expr@latest/dist/css-expr.min.js"></script>Documentation
- Getting Started - Installation, setup, and first examples
- Expression Syntax - Complete syntax guide with examples
- API Reference - Full programmatic API documentation
- Advanced Usage - Performance optimization and advanced techniques
Core Concepts
Element References
// Reference the current element
this.height = this.width * 0.618; // Golden ratio
// Reference other elements by selector
this.width = el('#sidebar').width + el('#content').width;
// Use base values (preserved from initial state)
this.fontSize = this.baseFontSize * 1.2;Available Properties
Access comprehensive element measurements:
Geometric Properties: width, height, top, left, right, bottom
Font Properties: fontSize, lineHeight, letterSpacing, fontWeight
Base Values: baseWidth, baseHeight, baseFontSize, etc.
Rich Expression Syntax
// Mathematical operations
this.width = Math.max(200, el('#container').width * 0.3);
// Conditional styling
this.display = el('#menu').width > 768 ? 'flex' : 'block';
// Logical operators
this.opacity = this.width > 500 && this.height > 300 ? 1 : 0.7;
// Automatic font fitting
this.fontSize = this.fitFont(12, 48);Use Cases
Responsive Design Beyond Media Queries
<!-- 3-column grid that adapts to container width -->
<div class="grid-item" data-expression="
this.width = el('#grid').width > 1200 ?
el('#grid').width / 4 - 20px :
el('#grid').width > 800 ?
el('#grid').width / 2 - 15px :
el('#grid').width - 10px;
">Grid Item</div>Element-Dependent Styling
<!-- Sidebar that affects main content layout -->
<main data-expression="
this.marginLeft = el('#sidebar').width + 'px';
this.padding = el('#sidebar').width > 0 ? '40px' : '20px';
">Content adapts to sidebar presence</main>Dynamic Typography
<!-- Text that scales with container and maintains readability -->
<h1 data-expression="
this.fontSize = Math.max(24, Math.min(72, this.width / 15));
this.lineHeight = this.fontSize * 1.2;
this.letterSpacing = this.fontSize > 48 ? '2px' : '1px';
">Responsive Heading</h1>API
Global API
import { cssExpr } from 'css-expr';
cssExpr.start(); // Initialize engine
cssExpr.reload(); // Restart and rediscover
cssExpr.addBinding(element, 'width', 'expression'); // Add binding programmatically
cssExpr.removeBindings(element); // Remove element bindings
cssExpr.getBindings(); // Get all bindings (debug)
cssExpr.destroy(); // CleanupProgrammatic Usage
import { BindingEngine, Parser, Interpreter } from 'css-expr';
// Custom engine instance
const engine = new BindingEngine();
engine.discover();
engine.updateAllBindings();
// Parse and evaluate expressions
const parser = new Parser('this.width = el("#container").width * 0.5');
const ast = parser.parse();Required APIs:
- ResizeObserver
- CSS Custom Properties
- ES Modules
Performance
css-expr is optimized for production use:
- Lightweight: ~20KB minified + gzipped
- Efficient: ResizeObserver-based updates, intelligent caching
- Non-blocking: Asynchronous expression evaluation
- Memory-conscious: WeakMap-based element tracking
Security
- No eval(): Expressions are parsed into AST and safely evaluated
- Sandboxed execution: Limited to predefined functions and properties
- CSP compatible: Works with Content Security Policy restrictions
- XSS protection: String values are properly escaped
Testing
npm test # Run test suite
npm run test:coverage # Run with coverage
npm run test:ui # Interactive test UIDevelopment
npm install # Install dependencies
npm run dev # Development build with watch
npm run build # Production build
npm run typecheck # TypeScript validationContributing
We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Submit a Pull Request
License
MIT License - see LICENSE file for details.
