abachrome

How do I lighten or darken a color in Ruby?

Lightening and darkening sounds like something HSL should handle well, and in theory it does. In practice, though, HSL-based adjustments often cause hue drift and saturation loss that make the resulting colors look off. You might wonder why that happens: HSL is not perceptually uniform, so the numeric adjustment does not correspond evenly to what your eye perceives. Abachrome’s lighten method operates in OKLCH space instead, where the hue and chroma stay stable across the adjustment. What we get is a lighter or darker version of the same color, not a shifted one.

Basic Usage

require 'abachrome'

base    = Abachrome.from_hex('#e63946')
lighter = base.lighten(0.15)   # +15% lightness
darker  = base.lighten(-0.15)  # -15% lightness

puts Abachrome::Outputs::CSS.format(lighter.to_srgb)
puts Abachrome::Outputs::CSS.format(darker.to_srgb)

Positive values lighten; negative values darken. The argument is a delta in OKLCH lightness units, which run from 0 to 1.

Generating Tint/Shade Scales

base   = Abachrome.from_hex('#0077b6')
shades = (-4..4).map { |step| base.lighten(step * 0.08) }

shades.each_with_index do |color, i|
  hex = Abachrome::Outputs::CSS.format(color.to_srgb)
  puts "shade-#{i * 100}: #{hex}"
end

This produces a nine-step tint and shade scale from a single base color. The perceptual uniformity of OKLCH means the steps feel evenly spaced to the eye — which is harder to achieve reliably in HSL.

Adjusting Chroma Directly

At times you want to adjust vibrancy rather than lightness. For fine-grained control, convert to OKLCH and modify the coordinates directly before converting back:

color = Abachrome.from_hex('#06d6a0').to_oklch
coords = color.coordinates

# Boost chroma by 0.05
more_vivid = Abachrome.from_oklch(
  coords[0],          # keep lightness
  coords[1] + 0.05,  # increase chroma
  coords[2]           # keep hue
)

puts Abachrome::Outputs::CSS.format(more_vivid.to_srgb)

This approach gives you independent control over all three perceptual dimensions of the color. It is more verbose than lighten, but it is the right tool when you need precision.

Notes

  • lighten with a positive value makes the color lighter; negative values darken it.
  • Passing a value that pushes lightness above 1.0 or below 0.0 may produce out-of-gamut results — use gamut mapping before CSS output if you’re adjusting by large amounts.