Reputation: 31
In SASS I can do:
!pink = #ff43a7
!darker_pink = !pink - #333333
I'd like to the same in Ruby.
Upvotes: 3
Views: 1375
Reputation: 1421
I just came across something where I wanted to distribute colors for a set across different hues. The SASS source didn't help much because I didn't see a way to get RGB from HSV.
The color gem had what I needed.
I wrote this helper:
def region_color(index, size)
h = (index.to_f / (size - 1).to_f)
Color::HSL.from_fraction(h, 0.95, 0.3).html
end
Upvotes: 0
Reputation: 10623
The basic approach of adding/subtracting colors in Sass is nonsense and only really works when using a gray adjustment. That's why in Sass 3 we now have full support of operations in the HSL domain which maps closely to the way people think about colors.
Since Sass is written in Ruby, you can at least read our code to see what's going on.
Here's the Color class, and the functions that operate on them.
It really is non-trivial code. Why not just use Sass?
Upvotes: 2
Reputation: 77778
Hex can be represented in Ruby by prefixing your value with 0x
:
pink = 0xff43a7
darker_pink = pink - 0x333333
def color(hex)
"#%06x" % hex
end
.container {
color: <%= color pink %>;
border: 1px solid <%= color darker_pink %>;
}
.container {
color: #ff43a7;
border: 1px solid #cc1074;
}
Upvotes: 4
Reputation: 125882
If you already have the Sass library, you can instantiate and work with its objects.
For instance:
red = Sass::Script::Color.new([255, 0, 0])
gray = Sass::Script::Color.new([128, 128, 128])
red.lightness < gray.lightness # => true
There must be a built-in way to turn hexadecimal strings like #00FF00
into Color
objects, but not seeing one, I wrote this function:
# @param color_string - hex string, like '#22FF22'. MUST be 6 characters,
# because I don't feel like dealing with the use-case for 3. :)
def color_from_hex_string(color_string)
# Drop the leading '#', if any
color_string = color_string[1..-1] if color_string.start_with?('#')
raise ArgumentError.new('Hex string must be 6 characters') unless color_string.length == 6
# Turn into array of 2-digit decimal numbers.
# Eg, '808080' becomes [128, 128, 128]; '#ff0000' becomes [255, 0, 0]
rgb_array = color_string.split('').each_slice(2).map do |slice|
slice.join('').to_i(16).to_s(10)
end
# Use that to build a new Color object
color = Sass::Script::Color.new(rgb_array)
# Set this option so it won't complain (?)
color.options = {:style => :compressed}
return color
end
Upvotes: 2
Reputation: 505
To refine @macek's answer, following @drawnownward's and @lpsquiggle's wishes:
You can make two helpers, like so:
def color(color)
"#%06x" % color
end
def darker_color(color)
x = color.match(/0x(..)(..)(..)/)
r = x[1].sub(/[0-3]/, '5')
g = x[2].sub(/[0-3]/, '5')
b = x[3].sub(/[0-3]/, '5')
rgb = "0x#{r}#{g}#{b}"
"#%06x" % (rgb.hex - 0x444444)
end
The advantage: if you've defined a color hex with low values (between 0 and 3, here), these will be bumped up before the subtraction, so that they end up as 0 afterward, instead of wrapping around and becoming c, d, e, or f (which would give you a color you didn't expect). It only does this for the first value in each #rrggbb pair, so #313131 becomes #0d0d0d, which isn't technically correct, but it's much better than #fdfdfd, so it seems like a good enough compromise, since you'll want to keep those second values in other cases.
In your Erb template, then, you would write this:
.container {
color: <%= color pink %>;
border: 1px solid <%= darker_color pink %>;
}
Instead of:
.container {
color: <%= color pink %>;
border: 1px solid <%= color darker_pink %>;
}
Hope that helps someone.
Upvotes: 0