CSS Tactics for Modern Web Design

CSS Tactics

Controlling Transparency in Gradients with HSL Variables

When working with design systems, you often need to create variations of the same colors and gradients with different transparency levels. Here's a powerful approach using HSL color variables.

The Problem

Creating multiple versions of the same gradient with different transparency levels can lead to repetitive code and maintenance challenges. For example:
css
/* Repetitive approach */
:root {
  --gradient-100: radial-gradient(hsla(198, 72%, 51%, 1.0) 10%, hsla(270, 56%, 10%, 1.0) 45%, hsla(270, 79%, 21%, 1.0) 80%);
  --gradient-70: radial-gradient(hsla(198, 72%, 51%, 0.7) 10%, hsla(270, 56%, 10%, 0.7) 45%, hsla(270, 79%, 21%, 0.7) 80%);
  --gradient-40: radial-gradient(hsla(198, 72%, 51%, 0.4) 10%, hsla(270, 56%, 10%, 0.4) 45%, hsla(270, 79%, 21%, 0.4) 80%);
}
This approach is error-prone and difficult to maintain.

The Solution: HSL Component Variables

Break down each color into its HSL components and use those variables to create gradient variations:
css
/* Step 1: Define base colors with HSL components */
:root {
  /* Base color */
  --cerulean-blue: hsla(198, 72%, 51%, 1.00);
  
  /* HSL components for transparency manipulation */
  --cerulean-blue-h: 198;
  --cerulean-blue-s: 72%;
  --cerulean-blue-l: 51%;
  
  /* Repeat for other colors */
  --mirage-purple: hsla(270, 56%, 10%, 1.00);
  --mirage-purple-h: 270;
  --mirage-purple-s: 56%;
  --mirage-purple-l: 10%;
  
  --jagger-plum: hsla(270, 79%, 21%, 1.00);
  --jagger-plum-h: 270;
  --jagger-plum-s: 79%;
  --jagger-plum-l: 21%;
}

Creating Gradient Variations

Now you can create multiple gradient variations with different opacity levels:
css
:root {
  /* Full opacity gradient (100%) */
  --grd-cerulean-jagger-100: radial-gradient(
    hsla(var(--cerulean-blue-h), var(--cerulean-blue-s), var(--cerulean-blue-l), 1.0) 10%, 
    hsla(var(--mirage-purple-h), var(--mirage-purple-s), var(--mirage-purple-l), 1.0) 45%, 
    hsla(var(--jagger-plum-h), var(--jagger-plum-s), var(--jagger-plum-l), 1.0) 80%
  );
  
  /* 70% opacity gradient */
  --grd-cerulean-jagger-70: radial-gradient(
    hsla(var(--cerulean-blue-h), var(--cerulean-blue-s), var(--cerulean-blue-l), 0.7) 10%, 
    hsla(var(--mirage-purple-h), var(--mirage-purple-s), var(--mirage-purple-l), 0.7) 45%, 
    hsla(var(--jagger-plum-h), var(--jagger-plum-s), var(--jagger-plum-l), 0.7) 80%
  );
  
  /* 40% opacity gradient */
  --grd-cerulean-jagger-40: radial-gradient(
    hsla(var(--cerulean-blue-h), var(--cerulean-blue-s), var(--cerulean-blue-l), 0.4) 10%, 
    hsla(var(--mirage-purple-h), var(--mirage-purple-s), var(--mirage-purple-l), 0.4) 45%, 
    hsla(var(--jagger-plum-h), var(--jagger-plum-s), var(--jagger-plum-l), 0.4) 80%
  );
}

Quick Transparency Variations

For individual colors, you can also create transparency variants directly:
css
:root {
  --cerulean-blue: hsla(198, 72%, 51%, 1.00);
  --cerulean-blue-80p: hsla(198, 72%, 51%, 0.8);
  --cerulean-blue-50p: hsla(198, 72%, 51%, 0.5);
  --cerulean-blue-20p: hsla(198, 72%, 51%, 0.2);
  --cerulean-blue-10p: hsla(198, 72%, 51%, 0.1);
}

Benefits of This Approach

  1. Maintainability: Change the base color once, and all variants update automatically
  2. Consistency: Ensures all transparency variants use the exact same base color
  3. Flexibility: Easy to create new transparency levels as needed
  4. Readability: Makes the relationship between colors clear in your code
  5. Performance: Uses native CSS variables without requiring preprocessors

Usage in Your Design System

Apply these gradients to elements:
css
.card {
  background: var(--grd-cerulean-jagger-100);
}

.card-overlay {
  background: var(--grd-cerulean-jagger-70);
}

.modal-backdrop {
  background: var(--grd-cerulean-jagger-40);
}

Alternative: Using color-mix() for Modern Browsers

For browsers that support it, the color-mix() function provides another elegant solution:
css
.element {
  background: linear-gradient(
    to right,
    var(--cerulean-blue),
    color-mix(in hsl, var(--cerulean-blue), transparent 50%)
  );
}
This approach is more concise but has less browser support than the HSL component method.

Note: This technique works particularly well with HSL colors because the HSL color model is more intuitive for designers and makes it easier to understand how colors relate to each other.