Class: Sass::Script::Value::Color

Inherits:
Base
  • Object
show all
Defined in:
lib/sass/script/value/color.rb

Overview

A SassScript object representing a CSS color.

A color may be represented internally as RGBA, HSLA, or both. It's originally represented as whatever its input is; if it's created with RGB values, it's represented as RGBA, and if it's created with HSL values, it's represented as HSLA. Once a property is accessed that requires the other representation -- for example, #red for an HSL color -- that component is calculated and cached.

The alpha channel of a color is independent of its RGB or HSL representation. It's always stored, as 1 if nothing else is specified. If only the alpha channel is modified using #with, the cached RGB and HSL values are retained.

Constant Summary collapse

ALTERNATE_COLOR_NAMES =
Sass::Util.map_vals({
    'aqua'                 => 0x00FFFFFF,
    'darkgrey'             => 0xA9A9A9FF,
    'darkslategrey'        => 0x2F4F4FFF,
    'dimgrey'              => 0x696969FF,
    'fuchsia'              => 0xFF00FFFF,
    'grey'                 => 0x808080FF,
    'lightgrey'            => 0xD3D3D3FF,
    'lightslategrey'       => 0x778899FF,
    'slategrey'            => 0x708090FF,
}, &method(:int_to_rgba))
COLOR_NAMES =

A hash from color names to [red, green, blue] value arrays.

Sass::Util.map_vals({
   'aliceblue'            => 0xF0F8FFFF,
   'antiquewhite'         => 0xFAEBD7FF,
   'aquamarine'           => 0x7FFFD4FF,
   'azure'                => 0xF0FFFFFF,
   'beige'                => 0xF5F5DCFF,
   'bisque'               => 0xFFE4C4FF,
   'black'                => 0x000000FF,
   'blanchedalmond'       => 0xFFEBCDFF,
   'blue'                 => 0x0000FFFF,
   'blueviolet'           => 0x8A2BE2FF,
   'brown'                => 0xA52A2AFF,
   'burlywood'            => 0xDEB887FF,
   'cadetblue'            => 0x5F9EA0FF,
   'chartreuse'           => 0x7FFF00FF,
   'chocolate'            => 0xD2691EFF,
   'coral'                => 0xFF7F50FF,
   'cornflowerblue'       => 0x6495EDFF,
   'cornsilk'             => 0xFFF8DCFF,
   'crimson'              => 0xDC143CFF,
   'cyan'                 => 0x00FFFFFF,
   'darkblue'             => 0x00008BFF,
   'darkcyan'             => 0x008B8BFF,
   'darkgoldenrod'        => 0xB8860BFF,
   'darkgray'             => 0xA9A9A9FF,
   'darkgreen'            => 0x006400FF,
   'darkkhaki'            => 0xBDB76BFF,
   'darkmagenta'          => 0x8B008BFF,
   'darkolivegreen'       => 0x556B2FFF,
   'darkorange'           => 0xFF8C00FF,
   'darkorchid'           => 0x9932CCFF,
   'darkred'              => 0x8B0000FF,
   'darksalmon'           => 0xE9967AFF,
   'darkseagreen'         => 0x8FBC8FFF,
   'darkslateblue'        => 0x483D8BFF,
   'darkslategray'        => 0x2F4F4FFF,
   'darkturquoise'        => 0x00CED1FF,
   'darkviolet'           => 0x9400D3FF,
   'deeppink'             => 0xFF1493FF,
   'deepskyblue'          => 0x00BFFFFF,
   'dimgray'              => 0x696969FF,
   'dodgerblue'           => 0x1E90FFFF,
   'firebrick'            => 0xB22222FF,
   'floralwhite'          => 0xFFFAF0FF,
   'forestgreen'          => 0x228B22FF,
   'gainsboro'            => 0xDCDCDCFF,
   'ghostwhite'           => 0xF8F8FFFF,
   'gold'                 => 0xFFD700FF,
   'goldenrod'            => 0xDAA520FF,
   'gray'                 => 0x808080FF,
   'green'                => 0x008000FF,
   'greenyellow'          => 0xADFF2FFF,
   'honeydew'             => 0xF0FFF0FF,
   'hotpink'              => 0xFF69B4FF,
   'indianred'            => 0xCD5C5CFF,
   'indigo'               => 0x4B0082FF,
   'ivory'                => 0xFFFFF0FF,
   'khaki'                => 0xF0E68CFF,
   'lavender'             => 0xE6E6FAFF,
   'lavenderblush'        => 0xFFF0F5FF,
   'lawngreen'            => 0x7CFC00FF,
   'lemonchiffon'         => 0xFFFACDFF,
   'lightblue'            => 0xADD8E6FF,
   'lightcoral'           => 0xF08080FF,
   'lightcyan'            => 0xE0FFFFFF,
   'lightgoldenrodyellow' => 0xFAFAD2FF,
   'lightgreen'           => 0x90EE90FF,
   'lightgray'            => 0xD3D3D3FF,
   'lightpink'            => 0xFFB6C1FF,
   'lightsalmon'          => 0xFFA07AFF,
   'lightseagreen'        => 0x20B2AAFF,
   'lightskyblue'         => 0x87CEFAFF,
   'lightslategray'       => 0x778899FF,
   'lightsteelblue'       => 0xB0C4DEFF,
   'lightyellow'          => 0xFFFFE0FF,
   'lime'                 => 0x00FF00FF,
   'limegreen'            => 0x32CD32FF,
   'linen'                => 0xFAF0E6FF,
   'magenta'              => 0xFF00FFFF,
   'maroon'               => 0x800000FF,
   'mediumaquamarine'     => 0x66CDAAFF,
   'mediumblue'           => 0x0000CDFF,
   'mediumorchid'         => 0xBA55D3FF,
   'mediumpurple'         => 0x9370DBFF,
   'mediumseagreen'       => 0x3CB371FF,
   'mediumslateblue'      => 0x7B68EEFF,
   'mediumspringgreen'    => 0x00FA9AFF,
   'mediumturquoise'      => 0x48D1CCFF,
   'mediumvioletred'      => 0xC71585FF,
   'midnightblue'         => 0x191970FF,
   'mintcream'            => 0xF5FFFAFF,
   'mistyrose'            => 0xFFE4E1FF,
   'moccasin'             => 0xFFE4B5FF,
   'navajowhite'          => 0xFFDEADFF,
   'navy'                 => 0x000080FF,
   'oldlace'              => 0xFDF5E6FF,
   'olive'                => 0x808000FF,
   'olivedrab'            => 0x6B8E23FF,
   'orange'               => 0xFFA500FF,
   'orangered'            => 0xFF4500FF,
   'orchid'               => 0xDA70D6FF,
   'palegoldenrod'        => 0xEEE8AAFF,
   'palegreen'            => 0x98FB98FF,
   'paleturquoise'        => 0xAFEEEEFF,
   'palevioletred'        => 0xDB7093FF,
   'papayawhip'           => 0xFFEFD5FF,
   'peachpuff'            => 0xFFDAB9FF,
   'peru'                 => 0xCD853FFF,
   'pink'                 => 0xFFC0CBFF,
   'plum'                 => 0xDDA0DDFF,
   'powderblue'           => 0xB0E0E6FF,
   'purple'               => 0x800080FF,
   'red'                  => 0xFF0000FF,
   'rosybrown'            => 0xBC8F8FFF,
   'royalblue'            => 0x4169E1FF,
   'saddlebrown'          => 0x8B4513FF,
   'salmon'               => 0xFA8072FF,
   'sandybrown'           => 0xF4A460FF,
   'seagreen'             => 0x2E8B57FF,
   'seashell'             => 0xFFF5EEFF,
   'sienna'               => 0xA0522DFF,
   'silver'               => 0xC0C0C0FF,
   'skyblue'              => 0x87CEEBFF,
   'slateblue'            => 0x6A5ACDFF,
   'slategray'            => 0x708090FF,
   'snow'                 => 0xFFFAFAFF,
   'springgreen'          => 0x00FF7FFF,
   'steelblue'            => 0x4682B4FF,
   'tan'                  => 0xD2B48CFF,
   'teal'                 => 0x008080FF,
   'thistle'              => 0xD8BFD8FF,
   'tomato'               => 0xFF6347FF,
   'transparent'          => 0x00000000,
   'turquoise'            => 0x40E0D0FF,
   'violet'               => 0xEE82EEFF,
   'wheat'                => 0xF5DEB3FF,
   'white'                => 0xFFFFFFFF,
   'whitesmoke'           => 0xF5F5F5FF,
   'yellow'               => 0xFFFF00FF,
   'yellowgreen'          => 0x9ACD32FF
}, &method(:int_to_rgba))
COLOR_NAMES_REVERSE =

A hash from [red, green, blue, alpha] value arrays to color names.

COLOR_NAMES.invert.freeze

Instance Attribute Summary

Attributes inherited from Base

#options, #source_range, #value

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#==, #_perform, #assert_int!, #eql?, #neq, #null?, #separator, #single_eq, #to_a, #to_bool, #to_h, #to_i, #unary_div, #unary_minus, #unary_not, #unary_plus

Constructor Details

#initialize(attrs) ⇒ Color #initialize(rgba) ⇒ Color

Constructs an RGB or HSL color object, optionally with an alpha channel.

The RGB values must be between 0 and 255. The saturation and lightness values must be between 0 and 100. The alpha value must be between 0 and 1.

Overloads:

  • #initialize(attrs) ⇒ Color

    The attributes are specified as a hash. This hash must contain either :hue, :saturation, and :value keys, or :red, :green, and :blue keys. It cannot contain both HSL and RGB keys. It may also optionally contain an :alpha key.

    Parameters:

    • attrs ({Symbol => Numeric})

      A hash of color attributes to values

    Raises:

    • (ArgumentError)

      if not enough attributes are specified, or both RGB and HSL attributes are specified

  • #initialize(rgba) ⇒ Color

    The attributes are specified as an array. This overload only supports RGB or RGBA colors.

    Parameters:

    • rgba (Array<Numeric>)

      A three- or four-element array of the red, green, blue, and optionally alpha values (respectively) of the color

    Raises:

    • (ArgumentError)

      if not enough attributes are specified

Raises:



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/sass/script/value/color.rb', line 218

def initialize(attrs, 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| c.to_i}
    @attrs = {:red => red, :green => green, :blue => blue}
    @attrs[:alpha] = attrs[3] ? attrs[3].to_f : 1
  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
  end

  [:red, :green, :blue].each do |k|
    next if @attrs[k].nil?
    @attrs[k] = @attrs[k].to_i
    Sass::Util.check_range("#{k.to_s.capitalize} value", 0..255, @attrs[k])
  end

  [:saturation, :lightness].each do |k|
    next if @attrs[k].nil?
    value = Number.new(@attrs[k], ['%']) # Get correct unit for error messages
    @attrs[k] = Sass::Util.check_range("#{k.to_s.capitalize}", 0..100, value, '%')
  end

  @attrs[:alpha] = Sass::Util.check_range("Alpha channel", 0..1, @attrs[:alpha])
end

Class Method Details

.from_hex(hex_string, alpha = nil) ⇒ Color

Create a new color from a valid CSS hex string.

The leading hash is optional.

Returns:



268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/sass/script/value/color.rb', line 268

def self.from_hex(hex_string, alpha = nil)
  unless hex_string =~ /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i ||
         hex_string =~ /^#?([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)
  attrs = {:red => red, :green => green, :blue => blue}
  attrs[:alpha] = alpha if alpha
  new(attrs)
end

Instance Method Details

#alphaFixnum

The alpha channel (opacity) of the color. This is 1 unless otherwise defined.

Returns:

  • (Fixnum)


333
334
335
# File 'lib/sass/script/value/color.rb', line 333

def alpha
  @attrs[:alpha].to_f
end

#alpha?Boolean

Returns whether this color object is translucent; that is, whether the alpha channel is non-1.

Returns:

  • (Boolean)


341
342
343
# File 'lib/sass/script/value/color.rb', line 341

def alpha?
  alpha < 1
end

#blueFixnum

The blue component of the color.

Returns:

  • (Fixnum)


300
301
302
303
# File 'lib/sass/script/value/color.rb', line 300

def blue
  hsl_to_rgb!
  @attrs[:blue]
end

#div(other) ⇒ Color

The SassScript / operation. Its functionality depends on the type of its argument:

Number : Divides each of the RGB color channels by the number.

Sass::Script::Value::Color : Divides each of this color's RGB color channels by the other color's.

Sass::Script::Value : See Base#div.

Parameters:

  • other (Value)

    The right-hand side of the operator

Returns:

  • (Color)

    The resulting color

Raises:



515
516
517
518
519
520
521
522
# File 'lib/sass/script/value/color.rb', line 515

def div(other)
  if other.is_a?(Sass::Script::Value::Number) ||
      other.is_a?(Sass::Script::Value::Color)
    piecewise(other, :/)
  else
    super
  end
end

#eq(other) ⇒ Bool

The SassScript == operation. Note that this returns a Bool object, not a Ruby boolean.

Parameters:

  • other (Value)

    The right-hand side of the operator

Returns:

  • (Bool)

    True if this value is the same as the other, false otherwise



384
385
386
387
# File 'lib/sass/script/value/color.rb', line 384

def eq(other)
  Sass::Script::Value::Bool.new(
    other.is_a?(Color) && rgb == other.rgb && alpha == other.alpha)
end

#greenFixnum

The green component of the color.

Returns:

  • (Fixnum)


292
293
294
295
# File 'lib/sass/script/value/color.rb', line 292

def green
  hsl_to_rgb!
  @attrs[:green]
end

#hash



389
390
391
# File 'lib/sass/script/value/color.rb', line 389

def hash
  [rgb, alpha].hash
end

#hslArray<Fixnum>

Returns the hue, saturation, and lightness components of the color.

Returns:

  • (Array<Fixnum>)

    A frozen three-element array of the hue, saturation, and lightness values (respectively) of the color



365
366
367
# File 'lib/sass/script/value/color.rb', line 365

def hsl
  [hue, saturation, lightness].freeze
end

#hslaArray<Fixnum>

Returns the hue, saturation, lightness, and alpha components of the color.

Returns:

  • (Array<Fixnum>)

    A frozen four-element array of the hue, saturation, lightness, and alpha values (respectively) of the color



373
374
375
# File 'lib/sass/script/value/color.rb', line 373

def hsla
  [hue, saturation, lightness].freeze
end

#hueNumeric

The hue component of the color.

Returns:

  • (Numeric)


308
309
310
311
# File 'lib/sass/script/value/color.rb', line 308

def hue
  rgb_to_hsl!
  @attrs[:hue]
end

#inspectString

Returns a string representation of the color.

Returns:



560
561
562
# File 'lib/sass/script/value/color.rb', line 560

def inspect
  alpha? ? rgba_str : hex_str
end

#lightnessNumeric

The lightness component of the color.

Returns:

  • (Numeric)


324
325
326
327
# File 'lib/sass/script/value/color.rb', line 324

def lightness
  rgb_to_hsl!
  @attrs[:lightness]
end

#minus(other) ⇒ Color

The SassScript - operation. Its functionality depends on the type of its argument:

Number : Subtracts the number from each of the RGB color channels.

Sass::Script::Value::Color : Subtracts each of the other color's RGB color channels from this color's.

Sass::Script::Value : See Base#minus.

Parameters:

  • other (Value)

    The right-hand side of the operator

Returns:

  • (Color)

    The resulting color

Raises:



472
473
474
475
476
477
478
# File 'lib/sass/script/value/color.rb', line 472

def minus(other)
  if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color)
    piecewise(other, :-)
  else
    super
  end
end

#mod(other) ⇒ Color

The SassScript % operation. Its functionality depends on the type of its argument:

Number : Takes each of the RGB color channels module the number.

Sass::Script::Value::Color : Takes each of this color's RGB color channels modulo the other color's.

Parameters:

  • other (Number, Color)

    The right-hand side of the operator

Returns:

  • (Color)

    The resulting color

Raises:



536
537
538
539
540
541
542
543
# File 'lib/sass/script/value/color.rb', line 536

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

#plus(other) ⇒ Color

The SassScript + operation. Its functionality depends on the type of its argument:

Number : Adds the number to each of the RGB color channels.

Sass::Script::Value::Color : Adds each of the RGB color channels together.

Sass::Script::Value : See Base#plus.

Parameters:

  • other (Value)

    The right-hand side of the operator

Returns:

  • (Color)

    The resulting color

Raises:



449
450
451
452
453
454
455
# File 'lib/sass/script/value/color.rb', line 449

def plus(other)
  if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color)
    piecewise(other, :+)
  else
    super
  end
end

#redFixnum

The red component of the color.

Returns:

  • (Fixnum)


284
285
286
287
# File 'lib/sass/script/value/color.rb', line 284

def red
  hsl_to_rgb!
  @attrs[:red]
end

#rgbArray<Fixnum>

Returns the red, green, and blue components of the color.

Returns:

  • (Array<Fixnum>)

    A frozen three-element array of the red, green, and blue values (respectively) of the color



349
350
351
# File 'lib/sass/script/value/color.rb', line 349

def rgb
  [red, green, blue].freeze
end

#rgbaArray<Fixnum>

Returns the red, green, blue, and alpha components of the color.

Returns:

  • (Array<Fixnum>)

    A frozen four-element array of the red, green, blue, and alpha values (respectively) of the color



357
358
359
# File 'lib/sass/script/value/color.rb', line 357

def rgba
  [red, green, blue, alpha].freeze
end

#saturationNumeric

The saturation component of the color.

Returns:

  • (Numeric)


316
317
318
319
# File 'lib/sass/script/value/color.rb', line 316

def saturation
  rgb_to_hsl!
  @attrs[:saturation]
end

#times(other) ⇒ Color

The SassScript * operation. Its functionality depends on the type of its argument:

Number : Multiplies the number by each of the RGB color channels.

Sass::Script::Value::Color : Multiplies each of the RGB color channels together.

Parameters:

  • other (Number, Color)

    The right-hand side of the operator

Returns:

  • (Color)

    The resulting color

Raises:



492
493
494
495
496
497
498
# File 'lib/sass/script/value/color.rb', line 492

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

#to_s(opts = {}) ⇒ String Also known as: to_sass

Returns a string representation of the color. This is usually the color's hex value, but if the color has a name that's used instead.

Returns:

  • (String)

    The string representation



550
551
552
553
554
# File 'lib/sass/script/value/color.rb', line 550

def to_s(opts = {})
  return smallest if options[:style] == :compressed
  return COLOR_NAMES_REVERSE[rgba] if COLOR_NAMES_REVERSE[rgba]
  alpha? ? rgba_str : hex_str
end

#with(attrs) ⇒ Color

Returns a copy of this color with one or more channels changed. RGB or HSL colors may be changed, but not both at once.

For example:

Color.new([10, 20, 30]).with(:blue => 40)
  #=> rgb(10, 40, 30)
Color.new([126, 126, 126]).with(:red => 0, :green => 255)
  #=> rgb(0, 255, 126)
Color.new([255, 0, 127]).with(:saturation => 60)
  #=> rgb(204, 51, 127)
Color.new([1, 2, 3]).with(:alpha => 0.4)
  #=> rgba(1, 2, 3, 0.4)

Parameters:

  • attrs ({Symbol => Numeric})

    A map of channel names (:red, :green, :blue, :hue, :saturation, :lightness, or :alpha) to values

Returns:

  • (Color)

    The new Color object

Raises:

  • (ArgumentError)

    if both RGB and HSL keys are specified



412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
# File 'lib/sass/script/value/color.rb', line 412

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, :allow_both_rgb_and_hsl)
end