Class Sass::Script::Color
In: lib/sass/script/color.rb
Parent: Literal
Haml::Util Engine Color SyntaxError UnitConversionError StandardError AbstractSequence CommaSequence Sequence SimpleSequence Simple Parent Universal Class Negation Id Pseudo Attribute Interpolation Element Node Operation Literal UnaryOperation StringInterpolation Funcall Variable Interpolation Lexer CssLexer Number String Bool Parser Parser CssParser EvaluationContext StaticParser SassParser CssParser Node DebugNode IfNode CommentNode ForNode PropNode MixinNode DirectiveNode VariableNode RootNode WarnNode ExtendNode RuleNode MixinDefNode WhileNode Enumerable ImportNode Merb::BootLoader MerbBootLoader Repl CSS Environment Rack StalenessChecker lib/sass/repl.rb lib/sass/css.rb lib/sass/environment.rb lib/sass/error.rb lib/sass/engine.rb lib/sass/selector/simple_sequence.rb lib/sass/selector/abstract_sequence.rb lib/sass/selector/sequence.rb lib/sass/selector/comma_sequence.rb lib/sass/selector/simple.rb lib/sass/selector.rb Selector lib/sass/script/css_parser.rb lib/sass/script/lexer.rb lib/sass/script/color.rb lib/sass/script/string.rb lib/sass/script/unary_operation.rb lib/sass/script/variable.rb lib/sass/script/funcall.rb lib/sass/script/string_interpolation.rb lib/sass/script/operation.rb lib/sass/script/bool.rb lib/sass/script/parser.rb lib/sass/script/node.rb lib/sass/script/literal.rb lib/sass/script/interpolation.rb lib/sass/script/css_lexer.rb lib/sass/script/number.rb lib/sass/script/functions.rb Functions Script lib/sass/scss/sass_parser.rb lib/sass/scss/static_parser.rb lib/sass/scss/parser.rb lib/sass/scss/css_parser.rb ScriptParser ScriptLexer RX SCSS Files Callbacks lib/sass/tree/while_node.rb lib/sass/tree/if_node.rb lib/sass/tree/mixin_def_node.rb lib/sass/tree/debug_node.rb lib/sass/tree/root_node.rb lib/sass/tree/for_node.rb lib/sass/tree/import_node.rb lib/sass/tree/prop_node.rb lib/sass/tree/node.rb lib/sass/tree/comment_node.rb lib/sass/tree/extend_node.rb lib/sass/tree/mixin_node.rb lib/sass/tree/warn_node.rb lib/sass/tree/directive_node.rb lib/sass/tree/rule_node.rb lib/sass/tree/variable_node.rb Tree lib/sass/plugin/rack.rb lib/sass/plugin/staleness_checker.rb lib/sass/plugin/merb.rb Plugin Sass dot/m_61_0.png

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.

Methods

alpha   alpha?   blue   div   eq   green   hex_str   hsl   hsl_to_rgb!   hue   hue_to_rgb   inspect   lightness   minus   mod   new   piecewise   plus   red   rgb   rgb_to_hsl!   rgba_str   saturation   smallest   times   to_s   to_sass   value   with  

Included Modules

Haml::Util

Constants

HTML4_COLORS = map_vals({ 'black' => 0x000000, 'silver' => 0xc0c0c0, 'gray' => 0x808080, 'white' => 0xffffff, 'maroon' => 0x800000, 'red' => 0xff0000, 'purple' => 0x800080, 'fuchsia' => 0xff00ff, 'green' => 0x008000, 'lime' => 0x00ff00, 'olive' => 0x808000, 'yellow' => 0xffff00, 'navy' => 0x000080, 'blue' => 0x0000ff, 'teal' => 0x008080, 'aqua' => 0x00ffff   A hash from color names to `[red, green, blue]` value arrays.
HTML4_COLORS_REVERSE = map_hash(HTML4_COLORS) {|k, v| [v, k]}   A hash from `[red, green, blue]` value arrays to color names.

Public Class methods

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.

@raise [Sass::SyntaxError] if any color value isn‘t in the specified range

@overload initialize(attrs)

  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.

  @param attrs [{Symbol => Numeric}] A hash of color attributes to values
  @raise [ArgumentError] if not enough attributes are specified,
    or both RGB and HSL attributes are specified

@overload initialize(rgba)

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

  @param rgba [Array<Numeric>] A three- or four-element array
    of the red, green, blue, and optionally alpha values (respectively)
    of the color
  @raise [ArgumentError] if not enough attributes are specified

[Source]

     # File lib/sass/script/color.rb, line 71
 71:     def initialize(attrs, allow_both_rgb_and_hsl = false)
 72:       super(nil)
 73: 
 74:       if attrs.is_a?(Array)
 75:         unless (3..4).include?(attrs.size)
 76:           raise ArgumentError.new("Color.new(array) expects a three- or four-element array")
 77:         end
 78: 
 79:         red, green, blue = attrs[0...3].map {|c| c.to_i}
 80:         @attrs = {:red => red, :green => green, :blue => blue}
 81:         @attrs[:alpha] = attrs[3] ? attrs[3].to_f : 1
 82:       else
 83:         attrs = attrs.reject {|k, v| v.nil?}
 84:         hsl = [:hue, :saturation, :lightness] & attrs.keys
 85:         rgb = [:red, :green, :blue] & attrs.keys
 86:         if !allow_both_rgb_and_hsl && !hsl.empty? && !rgb.empty?
 87:           raise ArgumentError.new("Color.new(hash) may not have both HSL and RGB keys specified")
 88:         elsif hsl.empty? && rgb.empty?
 89:           raise ArgumentError.new("Color.new(hash) must have either HSL or RGB keys specified")
 90:         elsif !hsl.empty? && hsl.size != 3
 91:           raise ArgumentError.new("Color.new(hash) must have all three HSL values specified")
 92:         elsif !rgb.empty? && rgb.size != 3
 93:           raise ArgumentError.new("Color.new(hash) must have all three RGB values specified")
 94:         end
 95: 
 96:         @attrs = attrs
 97:         @attrs[:hue] %= 360 if @attrs[:hue]
 98:         @attrs[:alpha] ||= 1
 99:       end
100: 
101:       [:red, :green, :blue].each do |k|
102:         next if @attrs[k].nil?
103:         @attrs[k] = @attrs[k].to_i
104:         next if (0..255).include?(@attrs[k])
105:         raise Sass::SyntaxError.new("#{k.to_s.capitalize} value must be between 0 and 255")
106:       end
107: 
108:       [:saturation, :lightness].each do |k|
109:         next if @attrs[k].nil?
110:         @attrs[k] = 0 if @attrs[k] < 0.00001 && @attrs[k] > -0.00001
111:         @attrs[k] = 100 if @attrs[k] - 100 < 0.00001 && @attrs[k] - 100 > -0.00001
112:         next if (0..100).include?(@attrs[k])
113:         raise Sass::SyntaxError.new("#{k.to_s.capitalize} must be between 0 and 100")
114:       end
115: 
116:       unless (0..1).include?(@attrs[:alpha])
117:         raise Sass::SyntaxError.new("Alpha channel must between 0 and 1")
118:       end
119:     end

Public Instance methods

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

@return [Fixnum]

[Source]

     # File lib/sass/script/color.rb, line 173
173:     def alpha
174:       @attrs[:alpha]
175:     end

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

@return [Boolean]

[Source]

     # File lib/sass/script/color.rb, line 181
181:     def alpha?
182:       alpha < 1
183:     end

The blue component of the color.

@return [Fixnum]

[Source]

     # File lib/sass/script/color.rb, line 140
140:     def blue
141:       hsl_to_rgb!
142:       @attrs[:blue]
143:     end

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

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

{Color} : Divides each of this color‘s RGB color channels by the other color‘s.

{Literal} : See {Literal#div}.

@param other [Literal] The right-hand side of the operator @return [Color] The resulting color @raise [Sass::SyntaxError] if `other` is a number with units

[Source]

     # File lib/sass/script/color.rb, line 347
347:     def div(other)
348:       if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
349:         piecewise(other, :/)
350:       else
351:         super
352:       end
353:     end

The SassScript `==` operation. **Note that this returns a {Sass::Script::Bool} object, not a Ruby boolean**.

@param other [Literal] The right-hand side of the operator @return [Bool] True if this literal is the same as the other,

  false otherwise

[Source]

     # File lib/sass/script/color.rb, line 220
220:     def eq(other)
221:       Sass::Script::Bool.new(
222:         other.is_a?(Color) && rgb == other.rgb && alpha == other.alpha)
223:     end

The green component of the color.

@return [Fixnum]

[Source]

     # File lib/sass/script/color.rb, line 132
132:     def green
133:       hsl_to_rgb!
134:       @attrs[:green]
135:     end

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

@return [Array<Fixnum>] A frozen three-element array of the

  hue, saturation, and lightness values (respectively) of the color

[Source]

     # File lib/sass/script/color.rb, line 209
209:     def hsl
210:       [hue, saturation, lightness].freeze
211:     end

The hue component of the color.

@return [Numeric]

[Source]

     # File lib/sass/script/color.rb, line 148
148:     def hue
149:       rgb_to_hsl!
150:       @attrs[:hue]
151:     end

Returns a string representation of the color.

@return [String] The hex value

[Source]

     # File lib/sass/script/color.rb, line 391
391:     def inspect
392:       alpha? ? rgba_str : hex_str
393:     end

The lightness component of the color.

@return [Numeric]

[Source]

     # File lib/sass/script/color.rb, line 164
164:     def lightness
165:       rgb_to_hsl!
166:       @attrs[:lightness]
167:     end

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

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

{Color} : Subtracts each of the other color‘s RGB color channels from this color‘s.

{Literal} : See {Literal#minus}.

@param other [Literal] The right-hand side of the operator @return [Color] The resulting color @raise [Sass::SyntaxError] if `other` is a number with units

[Source]

     # File lib/sass/script/color.rb, line 304
304:     def minus(other)
305:       if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
306:         piecewise(other, :-)
307:       else
308:         super
309:       end
310:     end

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

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

{Color} : Takes each of this color‘s RGB color channels modulo the other color‘s.

@param other [Number, Color] The right-hand side of the operator @return [Color] The resulting color @raise [Sass::SyntaxError] if `other` is a number with units

[Source]

     # File lib/sass/script/color.rb, line 367
367:     def mod(other)
368:       if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
369:         piecewise(other, :%)
370:       else
371:         raise NoMethodError.new(nil, :mod)
372:       end
373:     end

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

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

{Color} : Adds each of the RGB color channels together.

{Literal} : See {Literal#plus}.

@param other [Literal] The right-hand side of the operator @return [Color] The resulting color @raise [Sass::SyntaxError] if `other` is a number with units

[Source]

     # File lib/sass/script/color.rb, line 281
281:     def plus(other)
282:       if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
283:         piecewise(other, :+)
284:       else
285:         super
286:       end
287:     end

The red component of the color.

@return [Fixnum]

[Source]

     # File lib/sass/script/color.rb, line 124
124:     def red
125:       hsl_to_rgb!
126:       @attrs[:red]
127:     end

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

@return [Array<Fixnum>] A frozen three-element array of the red, green, and blue

  values (respectively) of the color

[Source]

     # File lib/sass/script/color.rb, line 201
201:     def rgb
202:       [red, green, blue].freeze
203:     end

The saturation component of the color.

@return [Numeric]

[Source]

     # File lib/sass/script/color.rb, line 156
156:     def saturation
157:       rgb_to_hsl!
158:       @attrs[:saturation]
159:     end

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

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

{Color} : Multiplies each of the RGB color channels together.

@param other [Number, Color] The right-hand side of the operator @return [Color] The resulting color @raise [Sass::SyntaxError] if `other` is a number with units

[Source]

     # File lib/sass/script/color.rb, line 324
324:     def times(other)
325:       if other.is_a?(Sass::Script::Number) || other.is_a?(Sass::Script::Color)
326:         piecewise(other, :*)
327:       else
328:         raise NoMethodError.new(nil, :times)
329:       end
330:     end

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.

@return [String] The string representation

[Source]

     # File lib/sass/script/color.rb, line 380
380:     def to_s(opts = {})
381:       return rgba_str if alpha?
382:       return smallest if options[:style] == :compressed
383:       return HTML4_COLORS_REVERSE[rgb] if HTML4_COLORS_REVERSE[rgb]
384:       hex_str
385:     end
to_sass(opts = {})

Alias for to_s

@deprecated This will be removed in version 3.2. @see rgb

[Source]

     # File lib/sass/script/color.rb, line 187
187:     def value
188:       Haml::Util.haml_warn "DEPRECATION WARNING:\nThe Sass::Script::Color #value attribute is deprecated and will be\nremoved in version 3.2. Use the #rgb attribute instead.\n"
189:       rgb
190:     end

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)

@param attrs [{Symbol => Numeric}]

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

@return [Color] The new Color object @raise [ArgumentError] if both RGB and HSL keys are specified

[Source]

     # File lib/sass/script/color.rb, line 244
244:     def with(attrs)
245:       attrs = attrs.reject {|k, v| v.nil?}
246:       hsl = !([:hue, :saturation, :lightness] & attrs.keys).empty?
247:       rgb = !([:red, :green, :blue] & attrs.keys).empty?
248:       if hsl && rgb
249:         raise ArgumentError.new("Color#with may not have both HSL and RGB keys specified")
250:       end
251: 
252:       if hsl
253:         [:hue, :saturation, :lightness].each {|k| attrs[k] ||= send(k)}
254:       elsif rgb
255:         [:red, :green, :blue].each {|k| attrs[k] ||= send(k)}
256:       else
257:         # If we're just changing the alpha channel,
258:         # keep all the HSL/RGB stuff we've calculated
259:         attrs = @attrs.merge(attrs)
260:       end
261:       attrs[:alpha] ||= alpha
262: 
263:       Color.new(attrs, :allow_both_rgb_and_hsl)
264:     end

Private Instance methods

[Source]

     # File lib/sass/script/color.rb, line 408
408:     def hex_str
409:       red, green, blue = rgb.map { |num| num.to_s(16).rjust(2, '0') }
410:       "##{red}#{green}#{blue}"
411:     end

[Source]

     # File lib/sass/script/color.rb, line 432
432:     def hsl_to_rgb!
433:       return if @attrs[:red] && @attrs[:blue] && @attrs[:green]
434: 
435:       h = @attrs[:hue] / 360.0
436:       s = @attrs[:saturation] / 100.0
437:       l = @attrs[:lightness] / 100.0
438: 
439:       # Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
440:       m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s
441:       m1 = l * 2 - m2
442:       @attrs[:red], @attrs[:green], @attrs[:blue] = [
443:         hue_to_rgb(m1, m2, h + 1.0/3),
444:         hue_to_rgb(m1, m2, h),
445:         hue_to_rgb(m1, m2, h - 1.0/3)
446:       ].map {|c| (c * 0xff).round}
447:     end

[Source]

     # File lib/sass/script/color.rb, line 449
449:     def hue_to_rgb(m1, m2, h)
450:       h += 1 if h < 0
451:       h -= 1 if h > 1
452:       return m1 + (m2 - m1) * h * 6 if h * 6 < 1
453:       return m2 if h * 2 < 1
454:       return m1 + (m2 - m1) * (2.0/3 - h) * 6 if h * 3 < 2
455:       return m1
456:     end

[Source]

     # File lib/sass/script/color.rb, line 413
413:     def piecewise(other, operation)
414:       other_num = other.is_a? Number
415:       if other_num && !other.unitless?
416:         raise Sass::SyntaxError.new("Cannot add a number with units (#{other}) to a color (#{self}).") 
417:       end
418: 
419:       result = []
420:       for i in (0...3)
421:         res = rgb[i].send(operation, other_num ? other.value : other.rgb[i])
422:         result[i] = [ [res, 255].min, 0 ].max
423:       end
424: 
425:       if !other_num && other.alpha != alpha
426:         raise Sass::SyntaxError.new("Alpha channels must be equal: #{self} #{operation} #{other}")
427:       end
428: 
429:       with(:red => result[0], :green => result[1], :blue => result[2])
430:     end

[Source]

     # File lib/sass/script/color.rb, line 458
458:     def rgb_to_hsl!
459:       return if @attrs[:hue] && @attrs[:saturation] && @attrs[:lightness]
460:       r, g, b = [:red, :green, :blue].map {|k| @attrs[k] / 255.0}
461: 
462:       # Algorithm from http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
463:       max = [r, g, b].max
464:       min = [r, g, b].min
465:       d = max - min
466: 
467:       h =
468:         case max
469:         when min; 0
470:         when r; 60 * (g-b)/d
471:         when g; 60 * (b-r)/d + 120
472:         when b; 60 * (r-g)/d + 240
473:         end
474: 
475:       l = (max + min)/2.0
476: 
477:       s =
478:         if max == min
479:           0
480:         elsif l < 0.5
481:           d/(2*l)
482:         else
483:           d/(2 - 2*l)
484:         end
485: 
486:       @attrs[:hue] = h % 360
487:       @attrs[:saturation] = s * 100
488:       @attrs[:lightness] = l * 100
489:     end

[Source]

     # File lib/sass/script/color.rb, line 404
404:     def rgba_str
405:       "rgba(#{rgb.join(', ')}, #{alpha % 1 == 0.0 ? alpha.to_i : alpha})"
406:     end

[Source]

     # File lib/sass/script/color.rb, line 397
397:     def smallest
398:       small_hex_str = hex_str.gsub(/^#(.)\1(.)\2(.)\3$/, '#\1\2\3')
399:       return small_hex_str unless (color = HTML4_COLORS_REVERSE[rgb]) &&
400:         color.size <= small_hex_str.size
401:       return color
402:     end

[Validate]