class Sass::Script::Value::Color

the cached RGB and HSL values are retained.
If only the alpha channel is modified using {#with},
It’s always stored, as 1 if nothing else is specified.
The alpha channel of a color is independent of its RGB or HSL representation.
that component is calculated and cached.
for example, {#red} for an HSL color –
Once a property is accessed that requires the other representation –
and if it’s created with HSL values, it’s represented as HSLA.
if it’s created with RGB values, it’s represented as RGBA,
It’s originally represented as whatever its input is;
A color may be represented internally as RGBA, HSLA, or both.
A SassScript object representing a CSS color.

def self.from_hex(hex_string, alpha = nil)

Returns:
  • (Color) -
def self.from_hex(hex_string, alpha = nil)
  unless hex_string =~ /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i ||
         hex_string =~ /^#?([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])?$/i
    raise ArgumentError.new("#{hex_string.inspect} is not a valid hex color.")
  end
  red   = $1.ljust(2, $1).to_i(16)
  green = $2.ljust(2, $2).to_i(16)
  blue  = $3.ljust(2, $3).to_i(16)
  alpha = $4.ljust(2, $4).to_i(16).to_f / 0xff if $4
  hex_string = "##{hex_string}" unless hex_string[0] == ?#
  attrs = {:red => red, :green => green, :blue => blue, :representation => hex_string}
  attrs[:alpha] = alpha if alpha
  new(attrs)
end

def self.int_to_rgba(color)

Returns:
  • (Array) - Array of 4 numbers representing r,g,b and alpha

Parameters:
  • color (Integer) --

Other tags:
    Private: -
def self.int_to_rgba(color)
  rgba = (0..3).map {|n| color >> (n << 3) & 0xff}.reverse
  rgba[-1] = rgba[-1] / 255.0
  rgba
end

def alpha

Returns:
  • (Integer) -
def alpha
  @attrs[:alpha].to_f
end

def alpha?

Returns:
  • (Boolean) -
def alpha?
  alpha < 1
end

def blue

Returns:
  • (Integer) -
def blue
  hsl_to_rgb!
  @attrs[:blue]
end

def div(other)

Raises:
  • (Sass::SyntaxError) - if `other` is a number with units

Returns:
  • (Color) - The resulting color

Parameters:
  • other (Value) -- The right-hand side of the operator
def div(other)
  if other.is_a?(Sass::Script::Value::Number) ||
      other.is_a?(Sass::Script::Value::Color)
    piecewise(other, :/)
  else
    super
  end
end

def eq(other)

Returns:
  • (Bool) - True if this value is the same as the other,

Parameters:
  • other (Value) -- The right-hand side of the operator
def eq(other)
  Sass::Script::Value::Bool.new(
    other.is_a?(Color) && rgb == other.rgb && alpha == other.alpha)
end

def green

Returns:
  • (Integer) -
def green
  hsl_to_rgb!
  @attrs[:green]
end

def hash

def hash
  [rgb, alpha].hash
end

def hex_str

def hex_str
  red, green, blue = rgb.map {|num| num.to_s(16).rjust(2, '0')}
  "##{red}#{green}#{blue}"
end

def hsl

Returns:
  • (Array) - A frozen three-element array of the
def hsl
  [hue, saturation, lightness].freeze
end

def hsl_to_rgb!

def hsl_to_rgb!
  return if @attrs[:red] && @attrs[:blue] && @attrs[:green]
  h = @attrs[:hue] / 360.0
  s = @attrs[:saturation] / 100.0
  l = @attrs[:lightness] / 100.0
  # Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
  m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s
  m1 = l * 2 - m2
  @attrs[:red], @attrs[:green], @attrs[:blue] = [
    hue_to_rgb(m1, m2, h + 1.0 / 3),
    hue_to_rgb(m1, m2, h),
    hue_to_rgb(m1, m2, h - 1.0 / 3)
  ].map {|c| Sass::Util.round(c * 0xff)}
end

def hsla

Returns:
  • (Array) - A frozen four-element array of the hue,
def hsla
  [hue, saturation, lightness, alpha].freeze
end

def hue

Returns:
  • (Numeric) -
def hue
  rgb_to_hsl!
  @attrs[:hue]
end

def hue_to_rgb(m1, m2, h)

def hue_to_rgb(m1, m2, h)
  h += 1 if h < 0
  h -= 1 if h > 1
  return m1 + (m2 - m1) * h * 6 if h * 6 < 1
  return m2 if h * 2 < 1
  return m1 + (m2 - m1) * (2.0 / 3 - h) * 6 if h * 3 < 2
  m1
end

def initialize(attrs, representation = nil, allow_both_rgb_and_hsl = false)

Raises:
  • (ArgumentError) - if not enough attributes are specified
  • (ArgumentError) - if not enough attributes are specified,
  • (Sass::SyntaxError) - if any color value isn't in the specified range

Parameters:
  • representation (String) -- The original representation of the color
  • rgba (Array) -- A three- or four-element array
  • attrs ({Symbol => Numeric}) -- A hash of color attributes to values

Overloads:
  • initialize(rgba, [representation])
  • initialize(attrs)
def initialize(attrs, representation = nil, allow_both_rgb_and_hsl = false)
  super(nil)
  if attrs.is_a?(Array)
    unless (3..4).include?(attrs.size)
      raise ArgumentError.new("Color.new(array) expects a three- or four-element array")
    end
    red, green, blue = attrs[0...3].map {|c| Sass::Util.round(c)}
    @attrs = {:red => red, :green => green, :blue => blue}
    @attrs[:alpha] = attrs[3] ? attrs[3].to_f : 1
    @representation = representation
  else
    attrs = attrs.reject {|_k, v| v.nil?}
    hsl = [:hue, :saturation, :lightness] & attrs.keys
    rgb = [:red, :green, :blue] & attrs.keys
    if !allow_both_rgb_and_hsl && !hsl.empty? && !rgb.empty?
      raise ArgumentError.new("Color.new(hash) may not have both HSL and RGB keys specified")
    elsif hsl.empty? && rgb.empty?
      raise ArgumentError.new("Color.new(hash) must have either HSL or RGB keys specified")
    elsif !hsl.empty? && hsl.size != 3
      raise ArgumentError.new("Color.new(hash) must have all three HSL values specified")
    elsif !rgb.empty? && rgb.size != 3
      raise ArgumentError.new("Color.new(hash) must have all three RGB values specified")
    end
    @attrs = attrs
    @attrs[:hue] %= 360 if @attrs[:hue]
    @attrs[:alpha] ||= 1
    @representation = @attrs.delete(:representation)
  end
  [:red, :green, :blue].each do |k|
    next if @attrs[k].nil?
    @attrs[k] = Sass::Util.restrict(Sass::Util.round(@attrs[k]), 0..255)
  end
  [:saturation, :lightness].each do |k|
    next if @attrs[k].nil?
    @attrs[k] = Sass::Util.restrict(@attrs[k], 0..100)
  end
  @attrs[:alpha] = Sass::Util.restrict(@attrs[:alpha], 0..1)
end

def inspect

Returns:
  • (String) - The hex value
def inspect
  alpha? ? rgba_str : hex_str
end

def lightness

Returns:
  • (Numeric) -
def lightness
  rgb_to_hsl!
  @attrs[:lightness]
end

def minus(other)

Raises:
  • (Sass::SyntaxError) - if `other` is a number with units

Returns:
  • (Color) - The resulting color

Parameters:
  • other (Value) -- The right-hand side of the operator
def minus(other)
  if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color)
    piecewise(other, :-)
  else
    super
  end
end

def mod(other)

Raises:
  • (Sass::SyntaxError) - if `other` is a number with units

Returns:
  • (Color) - The resulting color

Parameters:
  • other (Number, Color) -- The right-hand side of the operator
def mod(other)
  if other.is_a?(Sass::Script::Value::Number) ||
      other.is_a?(Sass::Script::Value::Color)
    piecewise(other, :%)
  else
    raise NoMethodError.new(nil, :mod)
  end
end

def name

Returns:
  • (String, nil) -
def name
  COLOR_NAMES_REVERSE[rgba]
end

def operation_name(operation)

def operation_name(operation)
  case operation
  when :+
    "add"
  when :-
    "subtract"
  when :*
    "multiply"
  when :/
    "divide"
  when :%
    "modulo"
  end
end

def piecewise(other, operation)

def piecewise(other, operation)
  other_num = other.is_a? Number
  if other_num && !other.unitless?
    raise Sass::SyntaxError.new(
      "Cannot #{operation_name(operation)} a number with units (#{other}) to a color (#{self})."
    )
  end
  result = []
  (0...3).each do |i|
    res = rgb[i].to_f.send(operation, other_num ? other.value : other.rgb[i])
    result[i] = [[res, 255].min, 0].max
  end
  if !other_num && other.alpha != alpha
    raise Sass::SyntaxError.new("Alpha channels must be equal: #{self} #{operation} #{other}")
  end
  with(:red => result[0], :green => result[1], :blue => result[2])
end

def plus(other)

Raises:
  • (Sass::SyntaxError) - if `other` is a number with units

Returns:
  • (Color) - The resulting color

Parameters:
  • other (Value) -- The right-hand side of the operator
def plus(other)
  if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color)
    piecewise(other, :+)
  else
    super
  end
end

def red

Returns:
  • (Integer) -
def red
  hsl_to_rgb!
  @attrs[:red]
end

def rgb

Returns:
  • (Array) - A frozen three-element array of the red, green, and blue
def rgb
  [red, green, blue].freeze
end

def rgb_to_hsl!

def rgb_to_hsl!
  return if @attrs[:hue] && @attrs[:saturation] && @attrs[:lightness]
  r, g, b = [:red, :green, :blue].map {|k| @attrs[k] / 255.0}
  # Algorithm from http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
  max = [r, g, b].max
  min = [r, g, b].min
  d = max - min
  h =
    case max
    when min; 0
    when r; 60 * (g - b) / d
    when g; 60 * (b - r) / d + 120
    when b; 60 * (r - g) / d + 240
    end
  l = (max + min) / 2.0
  s =
    if max == min
      0
    elsif l < 0.5
      d / (2 * l)
    else
      d / (2 - 2 * l)
    end
  @attrs[:hue] = h % 360
  @attrs[:saturation] = s * 100
  @attrs[:lightness] = l * 100
end

def rgba

Returns:
  • (Array) - A frozen four-element array of the red, green,
def rgba
  [red, green, blue, alpha].freeze
end

def rgba_str

def rgba_str
  split = options[:style] == :compressed ? ',' : ', '
  "rgba(#{rgb.join(split)}#{split}#{Number.round(alpha)})"
end

def saturation

Returns:
  • (Numeric) -
def saturation
  rgb_to_hsl!
  @attrs[:saturation]
end

def smallest

def smallest
  small_explicit_str = alpha? ? rgba_str : hex_str.gsub(/^#(.)\1(.)\2(.)\3$/, '#\1\2\3')
  [representation, COLOR_NAMES_REVERSE[rgba], small_explicit_str].
      compact.min_by {|str| str.size}
end

def times(other)

Raises:
  • (Sass::SyntaxError) - if `other` is a number with units

Returns:
  • (Color) - The resulting color

Parameters:
  • other (Number, Color) -- The right-hand side of the operator
def times(other)
  if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color)
    piecewise(other, :*)
  else
    raise NoMethodError.new(nil, :times)
  end
end

def to_s(opts = {})

Returns:
  • (String) - The string representation
def to_s(opts = {})
  return smallest if options[:style] == :compressed
  return representation if representation
  # IE10 doesn't properly support the color name "transparent", so we emit
  # generated transparent colors as rgba(0, 0, 0, 0) in favor of that. See
  # #1782.
  return rgba_str if Number.basically_equal?(alpha, 0)
  return name if name
  alpha? ? rgba_str : hex_str
end

def with(attrs)

Raises:
  • (ArgumentError) - if both RGB and HSL keys are specified

Returns:
  • (Color) - The new Color object

Parameters:
  • attrs ({Symbol => Numeric}) --
def with(attrs)
  attrs = attrs.reject {|_k, v| v.nil?}
  hsl = !([:hue, :saturation, :lightness] & attrs.keys).empty?
  rgb = !([:red, :green, :blue] & attrs.keys).empty?
  if hsl && rgb
    raise ArgumentError.new("Cannot specify HSL and RGB values for a color at the same time")
  end
  if hsl
    [:hue, :saturation, :lightness].each {|k| attrs[k] ||= send(k)}
  elsif rgb
    [:red, :green, :blue].each {|k| attrs[k] ||= send(k)}
  else
    # If we're just changing the alpha channel,
    # keep all the HSL/RGB stuff we've calculated
    attrs = @attrs.merge(attrs)
  end
  attrs[:alpha] ||= alpha
  Color.new(attrs, nil, :allow_both_rgb_and_hsl)
end