@simbafs/lx
v0.7.5
Published
HTML attribute DSL for absolute positioning
Maintainers
Readme
lx
lx is a lightweight, dependency-free JavaScript layout engine designed to define geometric relationships through HTML attributes and convert them into absolute CSS positioning coordinates. It is particularly suitable for web applications requiring precise positional control, complex dependency chains, or dynamic layout adjustments based on content.
Key Features
- Declarative Geometric Syntax: Directly describe logic such as "my right edge is 10px from the left edge of Element A" in HTML.
- Performance Optimization: Decouples layout into "Setup" (initialization) and "Update" (numerical refresh) to minimize the computational burden during window resizing or content changes.
- Automatic Redraw: Includes
lx-auto.jsto automatically monitor window size, DOM structure, and content changes to trigger layout updates. - Solves Standard Layout Pain Points: Handles cross-container alignment needs that are difficult to achieve with standard CSS Flexbox or Grid.
Quick Start
Installation
Option 1: CDN (Recommended)
<script src="https://raw.githubusercontent.com/simbafs/lx/refs/heads/main/dist/lx.min.js"></script>
<script src="https://raw.githubusercontent.com/simbafs/lx/refs/heads/main/dist/lx-auto.min.js"></script>Option 2: Download
Download lx.min.js and lx-auto.min.js from the dist folder and include them in your project.
Option 3: npm
npm install simbafs/lxBasic Example
<div id="screen" lx lx-l="0" lx-t="0" lx-w="1920" lx-h="1080">
<div id="sidebar" lx-r="body.right-20" lx-t="50" lx-w="300" lx-h="200/500">
When this content changes, elements below move automatically.
</div>
<div id="content" lx-l="#sidebar.left" lx-r="#sidebar.right" lx-t="#sidebar.bottom+20" lx-h="100">
Follower element
</div>
</div>Syntax Specification
1. Position Attributes
Supports lx-left (lx-l), lx-right (lx-r), lx-top (lx-t), and lx-bottom (lx-b).
- Reference Mode:
#id.edge[+/-offset]orbody.edge[+/-offset]. - Numeric Shorthand: If only a number is provided (e.g.,
lx-l="10"), it defaults to a 10px offset from the nearestlxcontainer's edge. - Relative Selectors: Use
previous.edge[+/-offset]ornext.edge[+/-offset]to reference the logical previous or next sibling element within the same container. These are syntactic sugar that gets translated to concrete#idreferences during setup.
2. Size Attributes
Supports lx-width (lx-w) and lx-height (lx-h).
- Fixed Size: Enter a number directly (e.g.,
300). - Range Size: Use
min/maxsyntax (e.g.,200/500). The element grows based on content while staying within these limits. - Expression: Use
(expression)syntax (e.g.,({base}*2)).
3. Aspect Ratio
Supports lx-aspect (lx-a) to define width-to-height ratio.
<div id="video" lx-t="0" lx-l="0" lx-w="320" lx-a="16:9"></div>This creates a video element with fixed width 320px and height calculated as 320 / (16/9) = 180px.
Constraint Rules: With lx-aspect, each dimension needs only one position reference plus the aspect ratio:
- Horizontal Dominant: 2 horizontal constraints + 1 vertical reference + aspect
- Vertical Dominant: 2 vertical constraints + 1 horizontal reference + aspect
Restrictions:
- Cannot coexist with range sizes (e.g.,
200/500) - Both
WandHmust be positive numbers
3. Variables & Math
Define reusable values with data-lx-* attributes and use them in expressions:
<body data-lx-gap="20" data-lx-scale="0.8">
<div id="container" lx>
<div id="sidebar" lx-l="#main.right+({gap}*2)" lx-t="50" lx-w="300" lx-h="500">
Sidebar with gap spacing
</div>
<div id="content" lx-l="0" lx-t="#sidebar.bottom+({gap})" lx-w="100" lx-h="200">
Content positioned with variable gap
</div>
</div>
</body>Supported operators: +, -, *, /
Variable lookup: Variables bubble up from the current element to <body>. Child elements can override parent values.
Position expressions: Combine references with expressions like #id.edge+({gap}*2) or body.top-({offset}/2).
Dynamic updates: Changing any data-lx-* attribute automatically triggers lx.setup() to re-evaluate all expressions.
Note: All expressions are evaluated during setup() phase. Nested parentheses are not supported.
4. Constraint Rules
To ensure a unique solution, each element must satisfy one of these valid combinations:
- Standard (no aspect): Two constraints per dimension
- Horizontal: two from
left,right,width - Vertical: two from
top,bottom,height
- Horizontal: two from
- With aspect ratio (
lx-a): Cross-dimensional constraint- Horizontal dominant: 2 horizontal + 1 vertical + aspect
- Vertical dominant: 2 vertical + 1 horizontal + aspect
Execution Mechanism
lx.js (Core Engine)
- setup(): Scans the DOM, parses attributes, builds a dependency graph, and detects circular dependencies.
- update(): When the structure is unchanged but values need refreshing (e.g., on resize), it uses the cached dependency graph for pure geometric calculations, skipping DOM scanning for better performance.
lx-auto.js (Automatic Monitoring)
Trigger updates in the following scenarios:
- Window Resize: Listens to
window.resize. - Content Change: Uses
ResizeObserverto monitor physical size changes inrangeelements. - Structure/Text Change: Uses
MutationObserverto monitor DOM additions/deletions, text modifications, orlx-*attribute changes. It automatically filters out style changes generated by the engine to prevent infinite loops. - Variable Change: Any
data-lx-*attribute change triggerslx.setup()to re-evaluate all expressions.
Debug Mode
Add ?lx-debug to the URL to enable developer debug logs:
- View parsed Canonical nodes.
- Check the calculated dependency order.
- Monitor reasons for each automatic redraw (e.g.,
resize,text-content-change).
License
MIT
