How Do HSL and OKLCH Differ? How to Approach Adjusting Web Colors

TIPS

Suppose you are adjusting blue and yellow backgrounds on a website and want them to appear similarly bright. Giving both colors the same lightness number does not always produce a balanced result. HSL and OKLCH offer different ways to control colors, especially their apparent lightness. Neither is automatically best for every task: the useful choice depends on whether you need a quick adjustment to one color or a consistent balance across several hues.

How do HSL and OKLCH differ, and when should you use each?

HSL stands for Hue, Saturation, and Lightness. Hue describes the color family, saturation describes how vivid the color is, and lightness controls its numerical lightness. In CSS (Cascading Style Sheets, the rules for a webpage’s appearance), a value looks like hsl(220 75% 45%). HSL is calculated within sRGB, the RGB color space commonly used for screen colors. Because its lightness is not based on how bright people perceive different hues to be, a blue and a yellow both set to 45% can appear quite different.

OKLCH expresses a color using Lightness (perceived brightness), Chroma (color intensity), and Hue (color family) in the Oklab color space. Its CSS syntax is oklch(72% 0.10 250), with perceived lightness, chroma, and hue in that order. This representation is designed around human color perception, making it useful when you want the apparent lightness of several hues to be more consistent. Even so, equal OKLCH lightness does not guarantee an equal text contrast ratio.

Choose HSL when you want to adjust the hue or saturation of a single color quickly. Consider OKLCH when balancing the apparent lightness of multiple colors. HSL saturation and OKLCH chroma are not interchangeable scales, and their hue angles do not correspond exactly either. You cannot copy the numerical components from one function directly into the other and expect the same color.

Example: compare blue and yellow for two event categories

Imagine a page where workshops and consultations have different colored labels. First, use HSL with 75% saturation and 45% lightness for both colors. The blue hsl(220 75% 45%) produces #1D56C9, while the yellow hsl(45 75% 45%) produces #C99E1D. Their contrast ratios against white #FFFFFF are approximately 6.51:1 and 2.50:1 respectively. Identical HSL lightness values clearly do not guarantee a similar visual or contrast result.

Next, set OKLCH lightness to 72% and chroma to 0.10 for both hues. The blue oklch(72% 0.10 250) converts to approximately #73A9E1 in sRGB, while the ochre-yellow oklch(72% 0.10 85) converts to approximately #C1A057. Their contrast ratios against white are around 2.47:1 and 2.49:1. These are a separate pair designed to illustrate each color model’s approach to lightness, not direct conversions of the two HSL example colors.

<section class="color-compare">
  <h3>Compare two approaches to color</h3>
  <p>HSL: 45% lightness, 75% saturation</p>
  <div class="color-compare__row">
    <span class="color-chip hsl-blue">Blue</span>
    <span class="color-chip hsl-gold">Yellow</span>
  </div>
  <p>OKLCH: 72% lightness, C = 0.10</p>
  <div class="color-compare__row">
    <span class="color-chip oklch-blue">Workshop</span>
    <span class="color-chip oklch-gold">Consultation</span>
  </div>
  <a class="color-compare__link" href="/events/">View upcoming events</a>
</section>
.color-compare {
  max-width: 38rem;
  padding: 24px;
  background-color: rgb(255 255 255);
  color: rgb(23 32 51);
}
.color-compare__row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 10px 0 16px;
}
.color-chip {
  display: inline-block;
  padding: 10px 16px;
  border-radius: 10px;
  font-weight: 700;
  color: rgb(23 32 51);
}
.hsl-blue {
  background-color: hsl(220 75% 45%);
  color: rgb(255 255 255);
}
.hsl-gold { background-color: hsl(45 75% 45%); }
.oklch-blue {
  background-color: rgb(115 169 225);
  background-color: oklch(72% 0.10 250);
}
.oklch-gold {
  background-color: rgb(193 160 87);
  background-color: oklch(72% 0.10 85);
}
.color-compare__link {
  display: inline-block;
  padding: 12px 16px;
  border-radius: 8px;
  background-color: rgb(33 78 124);
  color: rgb(255 255 255);
  text-decoration: underline;
}
.color-compare__link:hover {
  background-color: rgb(23 57 89);
}
.color-compare__link:focus-visible {
  outline: 3px solid rgb(23 32 51);
  outline-offset: 3px;
}

The comparison card has a white #FFFFFF background and dark navy #172033 text. The HSL blue label uses white #FFFFFF lettering; the HSL yellow and both OKLCH labels use dark-navy text. The “View upcoming events” link uses a deep-blue #214E7C background and white text. The written category labels remain visible alongside the colors, so the category does not depend on color alone. Replace the sample /events/ address with the appropriate destination for your site.

After adjusting colors, check contrast and display gamut

For the actual text-and-background combinations, white on HSL blue #1D56C9 has a contrast ratio of approximately 6.51:1. Dark navy #172033 on HSL yellow #C99E1D reaches about 6.50:1. Dark navy on the two OKLCH colors—blue #73A9E1 and ochre #C1A057—reaches about 6.58:1 and 6.53:1 respectively. White #FFFFFF against the deep-blue link #214E7C measures about 8.59:1, and white against the darker hover color #173959 reaches about 11.89:1. All these chosen text pairs exceed the 4.5:1 WCAG (Web Content Accessibility Guidelines) minimum for normal-sized text. By contrast, white text on the HSL yellow measures only about 2.50:1 and fails that threshold.

Some OKLCH combinations of lightness, chroma, and hue fall outside the range a standard sRGB display can reproduce. The browser must map such colors into the display’s supported gamut, which may change their appearance. Check vivid colors on real screens. In the CSS example, an approximate rgb() fallback appears before each oklch() declaration so that browsers without OKLCH support can use the earlier value. Always choose the text color by checking the actual background rather than assuming that the same lightness number makes any text color safe.

HueRoll displays HSL and six-digit HEX (hexadecimal) codes for selected colors. Its documented features do not include automatic OKLCH conversion, and its built-in contrast check compares the selected color with white or black, not every arbitrary color pair. Treat choosing a starting color and verifying the completed interface’s readability as separate steps.