Skip to content

Instantly share code, notes, and snippets.

@scmmishra
Created November 28, 2023 04:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scmmishra/fe28813f0b4d960d70df31a592e0aa2a to your computer and use it in GitHub Desktop.
Save scmmishra/fe28813f0b4d960d70df31a592e0aa2a to your computer and use it in GitHub Desktop.
module ColorHelper
def hex_to_rgb(hex_color)
# Remove the '#' character if it's there
hex_color = hex_color.tr('#', '')
# Split the hex color string into the RGB components
r = hex_color[0..1].to_i(16)
g = hex_color[2..3].to_i(16)
b = hex_color[4..5].to_i(16)
[r, g, b]
end
def rgb_to_hex(red, green, blue)
hex = [red, green, blue].map do |color|
color = 255 if color > 255
color = 0 if color.negative?
color.round.to_s(16).rjust(2, '0')
end.join.upcase
"##{hex}".downcase
end
def get_luminance(color)
return 0 if color == 'transparent'
r, g, b = hex_to_rgb(color)
(0.2126 * channel_to_luminance(r)) + (0.7152 * channel_to_luminance(g)) + (0.0722 * channel_to_luminance(b))
end
def get_contrast(color1, color2)
luminance1 = get_luminance(color1)
luminance2 = get_luminance(color2)
if luminance1 > luminance2
(luminance1 + 0.05) / (luminance2 + 0.05)
else
(luminance2 + 0.05) / (luminance1 + 0.05)
end
end
def mix(color1, color2, weight)
# Parse colors and normalize
r1, g1, b1 = hex_to_rgb(color1).map { |c| c / 255.0 }
r2, g2, b2 = hex_to_rgb(color2).map { |c| c / 255.0 }
# Mixing algorithm from Sass implementation
weight1, weight2 = get_weight_for_mixing(weight)
# Calculate final color values
r = ((r1 * weight1) + (r2 * weight2)) * 255
g = ((g1 * weight1) + (g2 * weight2)) * 255
b = ((b1 * weight1) + (b2 * weight2)) * 255
# Convert final values to a CSS RGBA color string
rgb_to_hex(r, g, b)
end
def adjust_color_for_contrast(color, background_color, target_ratio = 3.1)
max_iterations = 20
adjusted_color = color
max_iterations.times do
current_ratio = get_contrast(adjusted_color, background_color)
break if current_ratio >= target_ratio
adjustment_direction = get_luminance(adjusted_color) < 0.5 ? '#ffffff' : '#151718'
adjusted_color = mix(adjusted_color, adjustment_direction, 0.05)
end
adjusted_color
end
private
def get_weight_for_mixing(weight)
normalized_weight = (weight * 2) - 1
weight2 = (normalized_weight + 1) / 2
weight1 = 1 - weight2
[weight1, weight2]
end
def channel_to_luminance(channel)
channel /= 255.0
if channel <= 0.03928
channel / 12.92
else
((channel + 0.055) / 1.055)**2.4
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment