DEV Community

KAMAL KISHOR
KAMAL KISHOR

Posted on

Addressing Conditional Logic in CSS: A Practical Approach

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(), and defined() to introduce conditional logic.
  • Dedicated if() Function: Proposing a specific if() 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))
Enter fullscreen mode Exit fullscreen mode

"Space Toggle":
Using presence/absence of a variable:

   var(--test, var(--if-false))
Enter fullscreen mode Exit fullscreen mode

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} )
Enter fullscreen mode Exit fullscreen mode
  • 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} 
)
Enter fullscreen mode Exit fullscreen mode

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))
    ),
  )
);
Enter fullscreen mode Exit fullscreen mode

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)
);
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)