CSS Functions

Native CSS functions and conditional logic for dynamic styling

Overview

Shift CSS includes a powerful set of native CSS functions using the @function rule and if() conditional logic. These enable dynamic, self-healing components without JavaScript or preprocessors.

Browser Support

BrowserVersionSupport
Chrome139+✅ Full
Edge139+✅ Full
FirefoxExperimental🔄 Behind flag
SafariExperimental🔄 Behind flag

Import

/* Full framework (includes all utilities) */
@import "@shift-css/core";

/* Or import just functions */
@import "@shift-css/core/utils/functions";

Color Functions

—s-alpha

Add transparency to any color.

.overlay {
  background: --s-alpha(var(--s-primary-500), 0.5);
}

Parameters:

  • --color: The base color
  • --opacity: Opacity value (0-1)

—s-lighten / —s-darken

Adjust the lightness of a color using OKLCH.

.hover-state {
  background: --s-lighten(var(--s-primary-500), 0.1);
}

.pressed-state {
  background: --s-darken(var(--s-primary-500), 0.1);
}

Parameters:

  • --color: The base color
  • --amount: Amount to adjust (0-1, e.g., 0.1 = 10%)

—s-saturate / —s-desaturate

Adjust the chroma (saturation) of a color.

.vibrant {
  color: --s-saturate(var(--s-primary-500), 0.1);
}

.muted {
  color: --s-desaturate(var(--s-primary-500), 0.1);
}

—s-hue-rotate

Shift the hue of a color by degrees.

.shifted {
  background: --s-hue-rotate(var(--s-primary-500), 30);
}

—s-complement

Get the complementary color (180° hue shift).

.accent {
  border-color: --s-complement(var(--s-primary-500));
}

Effect Functions

—s-glow

Generate a multi-layered glowing box-shadow.

.glowing-card {
  box-shadow: --s-glow(var(--s-primary-500), 2);
}

.intense-glow {
  box-shadow: --s-glow(var(--s-accent-500), 4);
}

Parameters:

  • --color: The glow color
  • --intensity: Intensity multiplier (1-5)

—s-text-shadow-glow

Generate a text glow effect.

.neon-text {
  text-shadow: --s-text-shadow-glow(var(--s-accent-500), 2);
}

Contrast Functions

—s-contrast-text

Automatically return black or white text based on background lightness. Uses a 0.6 OKLCH lightness threshold as a pragmatic heuristic for contrast.

Note: WCAG contrast ratios use relative luminance (sRGB) with a different crossover point (~0.179). This function provides a practical OKLCH-based approximation, not a true WCAG luminance calculation.

.auto-text {
  background: var(--dynamic-bg);
  color: --s-contrast-text(var(--dynamic-bg));
}

—s-readable-on

Ensure text is readable on a given background by adjusting its lightness.

.readable {
  color: --s-readable-on(var(--bg-color), var(--text-color));
}

Conditional Styling with if()

The if() function enables inline conditional logic based on media queries, style queries, or feature queries.

Responsive Values

Replace media queries with inline conditionals:

[s-responsive-padding] {
  padding: if(
    media(width < 640px): var(--s-space-2) ;
      media(width < 1024px): var(--s-space-4) ; else: var(--s-space-6) ;
  );
}

Motion Preferences

Respect user motion preferences inline:

[s-motion-safe] {
  transition-duration: if(
    media(prefers-reduced-motion: reduce): 0ms; else: var(--s-duration-200) ;
  );
}

Dark Mode Awareness

Adapt to color scheme preferences:

[s-dark-aware] {
  background-color: if(
    media(prefers-color-scheme: dark): var(--s-surface-sunken) ;
      else: var(--s-surface-raised) ;
  );
}

Size Variants with Style Queries

Create size-aware components using custom property state:

[s-size-aware] {
  --size: md; /* default */

  padding: if(
    style(--size: sm): var(--s-space-2) ; style(--size: lg): var(--s-space-6) ;
      else: var(--s-space-4) ;
  );

  font-size: if(
    style(--size: sm): var(--s-text-sm) ; style(--size: lg): var(--s-text-lg) ;
      else: var(--s-text-base) ;
  );
}
<div s-size-aware style="--size: lg">Large size variant</div>
<div s-size-aware style="--size: sm">Small size variant</div>

Built-in Utility Attributes

s-auto-contrast

Cards with automatic text contrast based on background:

<article s-card s-auto-contrast style="--_card-bg: var(--s-primary-500)">
  Text automatically contrasts with the background
</article>

s-responsive-padding

Responsive padding without media queries:

<div s-responsive-padding>Padding adjusts based on viewport width</div>

s-motion-safe

Respects reduced motion preferences:

<div s-motion-safe>Transitions disabled for motion-sensitive users</div>

s-dark-aware

A sophisticated dark-awareness system that goes beyond simple color swaps. It provides:

  1. Container-Relative Theming - Uses CSS style queries to detect parent theme context, not just system preference
  2. OKLCH Perceptual Contrast - Auto-computes readable text color based on background lightness
  3. Visual Adaptations - Subtle border glow prevents bleeding, font weight adjusts for halation

Dark-Aware in Both Themes

Light

Self-Healing Card

Text contrast, border glow, and font weight all adapt automatically.

Dark

Self-Healing Card

Text contrast, border glow, and font weight all adapt automatically.

<div s-dark-aware style="padding: 1rem;">
<h4 style="margin-bottom: 0.5rem;">Self-Healing Card</h4>
<p>Text contrast, border glow, and font weight all adapt automatically.</p>
</div>

Theme Containers

Create “dark islands” on light pages (or vice versa) with s-theme:

<!-- Explicit dark container on a light page -->
<aside s-theme="dark">
  <div s-dark-aware>Inherits dark context from parent</div>
</aside>

<!-- Follows system preference -->
<div s-dark-aware>Falls back to OS preference</div>

Theme Islands

Light Island

Forced light context

Dark Island

Forced dark context

<div style="display: flex; gap: 1rem;">
<div s-theme="light" style="flex: 1; padding: 1rem; border: 1px solid oklch(0.8 0 0);">
  <div s-dark-aware style="padding: 1rem;">
    <strong>Light Island</strong>
    <p style="margin-top: 0.25rem;">Forced light context</p>
  </div>
</div>
<div s-theme="dark" style="flex: 1; padding: 1rem; border: 1px solid oklch(0.3 0 0);">
  <div s-dark-aware style="padding: 1rem;">
    <strong>Dark Island</strong>
    <p style="margin-top: 0.25rem;">Forced dark context</p>
  </div>
</div>
</div>

Variants

<!-- Default: background, text, glow, weight adjustment -->
<div s-dark-aware>Full adaptation</div>

<!-- Subtle: text and weight only, no background -->
<div s-dark-aware="subtle">For inline elements</div>

<!-- Strong: more pronounced glow for hero sections -->
<div s-dark-aware="strong">Maximum visual separation</div>

Technical Details

FeatureLight ModeDark Mode
Text ColorOKLCH L=0.15OKLCH L=0.95
Border GlowNone0.5px white @ 8%
Font WeightBaseBase - 50

The font weight reduction counters halation - the optical illusion where light text on dark backgrounds appears “fatter” due to light bleed in human vision.

Creating Custom Functions

Define your own reusable CSS functions:

@function --my-shadow(--color, --size) {
  result: 0 calc(var(--size) * 2px) calc(var(--size) * 4px)
    oklch(from var(--color) l c h / 0.3);
}

.custom-card {
  box-shadow: --my-shadow(var(--s-primary-500), 4);
}

Fallback Strategies

For browsers without @function or if() support, provide fallbacks:

/* Fallback value first, enhanced value second */
.element {
  color: var(--s-text-primary);
  /* Browsers without @function support ignore invalid values */
  color: --s-contrast-text(var(--bg));
}

Or use @supports to detect @function support:

@supports at-rule(@function) {
  .element {
    color: --s-contrast-text(var(--bg));
  }
}

Note: The cascade approach (fallback first, function second) is generally preferred as it’s simpler and doesn’t require feature detection.

Search