如何在Ruby中像SASS一样使用颜色进行数学运算?

3
在SASS中,我可以这样做:
!pink = #ff43a7
!darker_pink = !pink - #333333

我想在Ruby中实现相同的功能。

我对这个应用程序的应用感到困惑;SASS是在Ruby中构建的。你是在谈论在ERb中做这件事吗? - Chuck Vose
5个回答

4

在 Ruby 中,可以通过在数值前加上 0x 前缀来表示十六进制:

pink = 0xff43a7
darker_pink = pink - 0x333333

颜色助手

def color(hex)
  "#%06x" % hex
end

在ERb模板中的用法

.container {
  color: <%= color pink %>;
  border: 1px solid <%= color darker_pink %>;
}

输出

.container {
  color: #ff43a7;
  border: 1px solid #cc1074;
}

3
你需要为通道值添加边界检查,将其固定在0和255之间。 - drawnonward
2
你应该使用#%06x而不是仅仅使用#%x。否则,以零开头的颜色将被格式化错误。例如,值为0x000fff将导致#fff(即CSS中的白色)。 - Todd Yandell
1
我同意@drawnonward的观点;如果没有通道夹紧,当意图是“从这种颜色中去除一点蓝色”时,0x010000 - 0x000001的结果可能不是预期的。 - Ipsquiggle

2

使用 Sass 模块

如果您已经拥有 Sass 库,您可以实例化并使用其对象。

例如:

red  = Sass::Script::Color.new([255, 0, 0])
gray = Sass::Script::Color.new([128, 128, 128])
red.lightness < gray.lightness # => true

必须有一种内置的方法将十六进制字符串(例如#00FF00)转换为Color对象,但我没有找到这种方法,因此我编写了以下函数:

# @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

如果 color_string# 开头,那么 color_string = color_string[1..-1] 可以简化为 color_string.sub!(/^(?:#|0?x)/, '') - the Tin Man
rgb_array = color_string.split('').each_slice(2).map 可以被改写为 color_string.scan(/../).map,而 slice.join('').to_i(16).to_s(10) 可以被改写为 slice.hex.to_s(10) - the Tin Man

2
在Sass中添加/减去颜色的基本方法是无意义的,只有在使用灰色调整时才能真正起作用。这就是为什么在Sass 3中,我们现在完全支持HSL域中的操作,该域与人们对颜色的思考方式密切相关。
由于Sass是用Ruby编写的,因此您至少可以阅读我们的代码以了解发生了什么。
这是Color类,以及对它们进行操作的函数
这确实是一个非平凡的代码。为什么不直接使用Sass呢?

0
为了完善@macek的答案,遵循@drawnownward和@lpsquiggle的要求:
你可以这样创建两个帮助程序:
  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

优点:如果您定义了低值(在此处为0到3之间)的颜色十六进制值,则在减法运算之前会将其提升,以便它们最终成为0,而不是环绕并变成c、d、e或f(这将给您带来意外的颜色)。它仅对每个#rrggbb对中的第一个值执行此操作,因此#313131变为#0d0d0d,这不是技术上正确的,但比#fdfdfd好得多,因此似乎是一个足够好的折衷方案,因为您将在其他情况下保留那些第二个值。
然后,在您的Erb模板中,您将编写以下内容:
.container {
  color: <%= color pink %>;
  border: 1px solid <%= darker_color pink %>;
}

不要:

.container {
  color: <%= color pink %>;
  border: 1px solid <%= color darker_pink %>;
}

希望这能帮助到某个人。

似乎可以用rgb = color[/^0x(.{6})/, 1].tr('0-3', '5')替换darker_color方法的前五行。 - the Tin Man

0

我刚刚遇到了一个问题,我想要将一组颜色分配到不同的色调中。SASS源代码并没有帮助我太多,因为我没有找到从HSV获取RGB的方法。

color gem提供了我需要的东西。

我编写了这个辅助函数:

def region_color(index, size)
  h = (index.to_f / (size - 1).to_f)
  Color::HSL.from_fraction(h, 0.95, 0.3).html
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接