ScreenshotNeo

BlogGuides

HSL Colors in CSS: Syntax and Examples

Learn modern CSS hsl() syntax, what hue, saturation, lightness, and alpha mean, and how to use transparent and relative HSL colors.

By the ScreenshotNeo team4 October 20265 min read

Use CSS hsl() with hue, saturation, and lightness values separated by spaces: color: hsl(120 75% 25%);. Add optional transparency after a slash: color: hsl(120 75% 25% / 60%);. HSL is a way to specify an sRGB color by its hue, saturation, and lightness channels.

This guide covers the channel values, modern and legacy syntax, practical examples, relative colors, and common mistakes. For the specification, see the W3C CSS Color Module Level 4 and the MDN hsl() reference.

1. How do I use HSL colors in CSS?

Put an hsl() color anywhere a CSS color is accepted, such as color, background-color, border-color, or box-shadow.

button {
  color: hsl(0 0% 100%);
  background-color: hsl(220 80% 45%);
  border: 2px solid hsl(220 80% 35%);
  box-shadow: 0 2px 8px hsl(220 80% 20% / 25%);
}

In modern CSS syntax, the three channels are space-separated. If you need transparency, add / and an alpha value. Without alpha, an absolute HSL color is fully opaque.

2. What do the numbers in hsl() mean?

Channel What it controls Examples
Hue (H) Position around the color wheel. 0 or 0deg, 120deg, 0.3turn
Saturation (S) Strength of the hue. Zero is grayscale; 100% is fully saturated. 0%, 60%, 100%
Lightness (L) Position from black to white. Zero is black, 50% is the midpoint, and 100% is white. 0%, 45%, 100%
Alpha (A) Optional opacity. Zero is transparent and one is opaque. / 0.5, / 50%, / 1

For example, hsl(120 75% 25%) means a hue of 120 degrees, saturation of 75%, and lightness of 25%. Hue is an angle: a bare number is interpreted as degrees, and you can use angle units such as deg or turn. Saturation and lightness are most clearly written as percentages.

HSL is not a perceptually uniform color space. A change of the same numeric amount in lightness or hue does not necessarily look equally large across colors. A lightness value also does not guarantee sufficient text contrast; check the actual foreground and background combination.

3. Modern HSL syntax and alpha transparency

The current, readable form is space-separated, with a slash before optional alpha:

.accent { color: hsl(120 75% 25%); }
.soft-accent { background: hsl(120deg 75% 25% / 60%); }
.warm-overlay { background: hsl(0.3turn 60% 45% / 0.7); }

Alpha may be a number from 0 to 1 or a percentage. For example, / 0.5 and / 50% both express half opacity. An alpha value of 1 (or 100%) is fully opaque; 0 is fully transparent.

Transparency blends the color with what is behind it, so the visible result depends on the background. If you need a fixed final color, use an opaque color rather than assuming a translucent foreground will look the same everywhere.

4. Legacy comma syntax and hsla()

Comma-separated syntax remains supported:

.legacy { color: hsl(120, 75%, 25%); }
.legacy-with-alpha { color: hsla(120deg, 75%, 25%, 0.8); }
Form Structure Notes
Modern absolute hsl(H S L / A) Space-separated channels; slash alpha is optional.
Legacy absolute hsl(H, S%, L%) or hsla(H, S%, L%, A) Comma-separated; saturation and lightness require percentages, and none is not allowed.
Relative hsl(from <color> H S L / A) Starts from an origin color and can reuse or calculate its channels.

hsla() is an alias for hsl(); they are equivalent. Prefer hsl() in new code for consistency. Avoid mixing comma and space syntax in one function: choose one complete form.

5. Practical HSL examples

Define a reusable color and variants

:root {
  --brand-hue: 222;
  --brand: hsl(var(--brand-hue) 78% 48%);
  --brand-dark: hsl(var(--brand-hue) 78% 35%);
  --brand-wash: hsl(var(--brand-hue) 78% 48% / 12%);
}

.button {
  background: var(--brand);
  color: hsl(0 0% 100%);
}
.button:hover {
  background: var(--brand-dark);
}

Create a complementary hue

Adding 180 degrees gives the opposite hue on the color wheel. For example, 10 degrees and 190 degrees are complementary hue positions:

:root {
  --warm: hsl(10 70% 50%);
  --complement: hsl(190 70% 50%);
}

This is a color-wheel relationship, not a guarantee of accessible contrast or a harmonious design. Evaluate the rendered colors in context.

Use grayscale

Set saturation to zero to remove the hue and produce a gray value controlled by lightness:

.muted { color: hsl(0 0% 40%); }
.panel { background: hsl(0 0% 96%); }

6. Relative HSL colors

Relative color syntax derives channel values from an origin color. The general form is hsl(from <color> H S L / A). This is useful when you want to adjust one channel while preserving the others.

.lifted-red {
  color: hsl(from red h s calc(l + 20));
}

Here h, s, and l refer to the origin color’s channels, and the calculation raises lightness. Relative color syntax is a newer feature than basic HSL; check the browser support relevant to your project’s audience before relying on it. For broad compatibility, provide a basic color declaration first and a relative-color override after it, then verify the fallback behavior in your target browsers.

7. Troubleshooting common HSL mistakes

Symptom Likely cause Fix
The declaration is ignored. Mixed separators, missing percentages on S or L, or malformed alpha syntax. Use a complete modern form such as hsl(210 70% 40% / 50%), or a complete legacy form such as hsl(210, 70%, 40%).
The color looks grayscale. Saturation is zero or very low. Raise the saturation percentage if a stronger hue is intended.
The result is unexpectedly black or white. Lightness is near 0% or 100%. Move lightness toward the range that suits the design; 50% is the midpoint, not a promise of a vivid or accessible color.
The translucent color looks different over another component. Alpha blends with the background beneath it. Check the actual stacking/background context or use an opaque value.
A relative color declaration fails in one browser. That browser may not support the newer relative syntax. Keep an absolute HSL fallback before the relative declaration and check compatibility for the required browsers.
Legacy code rejects none. The comma-separated form does not permit none. Use the modern space-separated form if a missing channel is needed, or specify a concrete channel value.

8. Reliability, performance, and cost notes

Basic HSL colors are part of CSS and need no external service, library, or network request. The syntax is stable across modern browsers; MDN records broad browser availability for hsl() since July 2015. Relative color syntax is newer, so confirm support against your browser requirements. Avoid treating HSL values as a substitute for visual testing: verify contrast and appearance with the backgrounds where the colors will actually be used.

If you are documenting a CSS component and need a screenshot of the rendered page, a screenshot API can capture it for a preview or reference. That is separate from how CSS color values are parsed.

9. Or skip the browser setup

When you need a rendered page image rather than a local browser capture script, ScreenshotNeo takes a screenshot from one API request. See the API documentation for request options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Its MCP server lets AI agents use screenshot tools, including take_screenshot. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, with no card required.

10. FAQ

Is hsl() the same as hsla()?

Yes. hsla() is an alias for hsl(). Use hsl() for new styles.

Does a hue of 360 degrees differ from 0 degrees?

They refer to the same position after one full turn around the hue wheel.

Does HSL guarantee accessible contrast?

No. HSL channels describe a color; they do not guarantee readable contrast. Evaluate the chosen foreground and background together.