Addressing Conditional Logic in CSS: A Practical Approach
KAMAL KISHOR
Posted on August 17, 2024
CSS authors have long sought a way to implement conditional logic directly within their stylesheets. Despite numerous proposals and discussions, a universally accepted solution remains elusive. Key ideas that have emerged include:
- Enhanced Custom Properties: Creating higher-level custom properties to control multiple CSS declarations more effectively.
- Concise Conditional Values: Developing a method to express conditional values in a more compact and readable format.
-
Emulating Conditionals: Using discontinuous functions within
calc()
to simulate conditional logic. -
Iverson Bracket Functions: Implementing functions like
if()
,media()
,supports()
, anddefined()
to introduce conditional logic. -
Dedicated
if()
Function: Proposing a specificif()
function to handle conditional styling.
Current Workarounds
Until a robust solution is available, developers have relied on several workarounds to achieve conditional styling:
0/1 Switch with Linear Interpolation:
calc(var(--test) * var(--if-true) + (1 - var(--test)) * var(--if-false))
"Space Toggle":
Using presence/absence of a variable:
var(--test, var(--if-false))
Style Container Queries:
Effective for styling based on descendant elements, but limited in scope.
Cyclic Dependency Space Toggles
However, these methods fall short in some scenarios, such as transforming arbitrary keywords to specific values. For instance, CSS custom properties like the following remain challenging to implement:
--variant: auto | primary | success | neutral | warning | danger
--effect: none | pulse
--button-style: fill | outline
--shape: rect | pill
--avatar-shape: square | rounded | circle
--size: small | medium | large
--suffix: none | caret
--popup-placement: [top | right | bottom | left] [start | end]?
--popup-arrow-placement: center | start | end
Proposed Minimal Viable Product (MVP)
To address these challenges, we could introduce a Minimal Viable Product (MVP) that focuses on delivering essential conditional functionality while laying the groundwork for future enhancements.
Key Features for the MVP:
-
Limited Scope to
style()
Conditionals: Focus on conditionals based on style queries. - Restricted to Custom Properties: Limit functionality to custom properties for simplicity.
- Value Space Restriction: Initially restrict to single token values.
- Custom Property Values Only: Implement the feature specifically within custom property values.
Proposed Design
Based on recent discussions, a feasible design for the if()
function could look like this:
<if()> = if( <container-query>, [<declaration-value>]{1, 2} )
-
Links:
<container-query>
<declaration-value>
This function allows for nested values to produce multiple branches. If a third argument isnโt provided, it defaults to an empty token stream.
Enhanced Grammar for Better Usability
To improve usability, consider this enhanced grammar:
<if()> = if(
[ <container-query>, [<declaration-value>]{2} ]#{0, },
<container-query>, [<declaration-value>]{1, 2}
)
This format simplifies handling multiple conditions. For example:
Original Grammar Example:
background-color: if(
style(--variant: success), var(--color-success-60),
if(style(--variant: warning), var(--color-warning-60),
if(style(--variant: danger), var(--color-danger-60),
if(style(--variant: primary), var(--color-primary))
),
)
);
Enhanced Grammar Example:
background-color: if(
style(--variant: success), var(--color-success-60),
style(--variant: warning), var(--color-warning-60),
style(--variant: danger), var(--color-danger-60),
style(--variant: primary), var(--color-primary)
);
Behavior and Considerations
Any invalid value would cause the property to behave as IACVT (Invalid at Computed Value Time). Ideally, a fallback mechanism would revert to the default value if no condition matches, but implementing this is more complex.
Posted on August 17, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.