Simpler gradient output by discarding from() and to()

This commit is contained in:
Chris Eppstein 2010-02-21 22:44:38 -08:00
parent 34478112ba
commit ad4a486ea1
4 changed files with 212 additions and 97 deletions

View File

@ -1,44 +1,58 @@
=gradient(!type, !coords, !color_start, !color_end, !color_stop = false)
!gradient= "#{!coords}, from(#{!color_start}), to(#{!color_end})"
@if !color_stop
!gradient= !gradient + ", " + !color_stop
background: -webkit-gradient(#{!type}, #{!gradient})
background: -moz-#{!type}-gradient(#{!gradient})
//*
// This will yield a radial gradient with an apparent specular highlight
+radial-gradient("45 45, 10, 52 50, 30", Cyan, DodgerBlue)
=radial-gradient(!coords, !color1, !color2, !color_stop = false)
+gradient("radial", !coords, !color1, !color2, !color_stop)
//*
// This yields a linear gradient spanning from top to bottom
+linear-gradient(color_stops(white, black))
// This yields a linear gradient spanning from bottom to top
+linear-gradient(color_stops(white, black), "bottom")
// This yields a linear gradient spanning from left to right
+linear-gradient(color_stops(white, black), "left")
// This yields a linear gradient starting at white passing
// thru blue at 33% down and then to black
+linear-gradient(color_stops(white, blue 33%, black))
// This yields a linear gradient starting at white passing
// thru blue at 33% down and then to black at 67% until the end
+linear-gradient(color_stops(white, blue 33%, black 67%))
// This yields a linear gradient spanning from top to bottom
//
// +linear-gradient(color_stops(white, black))
//
// This yields a linear gradient spanning from bottom to top
//
// +linear-gradient(color_stops(white, black), "bottom")
//
// This yields a linear gradient spanning from left to right
//
// +linear-gradient(color_stops(white, black), "left")
//
// This yields a linear gradient starting at white passing
// thru blue at 33% down and then to black
//
// +linear-gradient(color_stops(white, blue 33%, black))
//
// This yields a linear gradient starting at white passing
// thru blue at 33% down and then to black at 67% until the end
//
// +linear-gradient(color_stops(white, blue 33%, black 67%))
//
// Browsers Supported:
//
// - Chrome
// - Safari
// - Firefox 3.6
=linear-gradient(!color_stops, !start = "top")
// Firefox's gradient api is nice.
// Webkit's gradient api sucks -- hence these backflips:
!end = grad_opposite_position(!start)
!start_color = grad_start_color(!color_stops)
!end_color = grad_end_color(!color_stops)
!webkit_stops = grad_color_stops(!color_stops)
!gradient= "#{grad_point(!start)}, #{grad_point(!end)}, from(#{!start_color}), to(#{!end_color})"
@if !webkit_stops
!gradient= !gradient + ", " + !webkit_stops
background-image: -webkit-gradient(linear, #{!gradient})
background-image: -webkit-gradient(linear, #{grad_point(!start)}, #{grad_point(!end)}, #{grad_color_stops(!color_stops)})
background-image: -moz-linear-gradient(#{!start}, #{!color_stops})
// Due to limitation's of webkit, the radial gradient mixin works best if you use
// pixel-based color stops.
//
// Examples:
//
// // Defaults to a centered, 100px radius gradient
// +radial-gradient(color_stops(#c00, #00c))
// // 100px radius gradient in the top left corner
// +radial-gradient(color_stops(#c00, #00c), "top left")
// // Three colors, ending at 50px and passing thru #fff at 25px
// +radial-gradient(color_stops(#c00, #fff, #00c 50px))
//
// Browsers Supported:
//
// - Chrome
// - Safari
// - Firefox 3.6
=radial-gradient(!color_stops, !center_position = "center center")
!end_pos = grad_end_position(!color_stops, true)
background-image: -webkit-gradient(radial, #{grad_point(!center_position)}, 0, #{grad_point(!center_position)}, #{!end_pos}, #{grad_color_stops(!color_stops)})
background-image: -moz-radial-gradient(#{!center_position}, circle, #{!color_stops})

View File

@ -25,8 +25,11 @@ module Compass::SassExtensions::Functions::GradientSupport
s = "#{color}"
if stop
s << " "
s << stop.times(Sass::Script::Number.new(100)).to_s
s << "%"
if stop.unitless?
s << stop.times(Sass::Script::Number.new(100, ["%"])).to_s
else
s << stop.to_s
end
end
s
end
@ -41,6 +44,7 @@ module Compass::SassExtensions::Functions::GradientSupport
when "bottom" then "top"
when "left" then "right"
when "right" then "left"
when "center" then "center"
else
raise Sass::SyntaxError, "Cannot determine the opposite of #{pos}"
end
@ -50,49 +54,53 @@ module Compass::SassExtensions::Functions::GradientSupport
# returns color-stop() calls for use in webkit.
def grad_color_stops(color_list)
positions = color_list.values.map{|c| [c.stop && c.stop.value, c.color]}
# fill in the blank positions
positions[0][0] = 0 unless positions.first.first
positions[positions.size - 1][0] = 1 unless positions.last.first
for i in 0...positions.size
if positions[i].first.nil?
num = 2.0
for j in (i+1)...positions.size
if positions[j].first
positions[i][0] = positions[i-1].first + (positions[j].first - positions[i-1].first) / num
break
else
num += 1
end
normalize_stops!(color_list)
max = color_list.values.last.stop
color_stops = color_list.values.map do |pos|
# have to convert absolute units to percentages for use in color stop functions.
stop = pos.stop
stop = stop.div(max).times(Sass::Script::Number.new(100,["%"])) if stop.numerator_units == max.numerator_units
"color-stop(#{stop}, #{pos.color})"
end
Sass::Script::String.new(color_stops.join(", "))
end
# returns the end position of the gradient from the color stop
def grad_end_position(color_list, radial = Sass::Script::Bool.new(false))
default = Sass::Script::Number.new(100)
grad_position(color_list, Sass::Script::Number.new(color_list.values.size), default, radial)
end
def grad_position(color_list, index, default, radial = Sass::Script::Bool.new(false))
stop = color_list.values[index.value - 1].stop
if stop && radial.to_bool
orig_stop = stop
if stop.unitless?
if stop.value <= 1
# A unitless number is assumed to be a percentage when it's between 0 and 1
stop = stop.times(Sass::Script::Number.new(100, ["%"]))
else
# Otherwise, a unitless number is assumed to be in pixels
stop = stop.times(Sass::Script::Number.new(1, ["px"]))
end
end
end
positions = positions[1..-1] if positions.first.first == 0.0
positions = positions[0..-2] if positions.last.first == 1.0
if positions.empty?
# We return false here since sass has no nil.
Sass::Script::Bool.new(false)
if stop.numerator_units == ["%"] && color_list.values.last.stop && color_list.values.last.stop.numerator_units == ["px"]
stop = stop.times(color_list.values.last.stop).div(Sass::Script::Number.new(100, ["%"]))
end
Compass::Logger.new.record(:warning, "Webkit only supports pixels for the start and end stops for radial gradients. Got: #{orig_stop}") if stop.numerator_units != ["px"]
stop.div(Sass::Script::Number.new(1, stop.numerator_units, stop.denominator_units))
elsif stop
stop
else
color_stops = positions.map {|pos| "color-stop(#{Sass::Script::Number.new((pos.first*10000).round/100.0).to_s}%, #{pos.last})"}
Sass::Script::String.new(color_stops.join(", "))
default
end
end
# the first color from a list of color stops
def grad_start_color(color_list)
color_list.values.first.color
end
# the last color from a list of color stops
def grad_end_color(color_list)
color_list.values.last.color
end
# the given a position, return a point in percents
def grad_point(position)
position = position.value
position = if position[" "]
if position =~ /(top|bottom) (left|right)/
if position =~ /(top|bottom|center) (left|right|center)/
"#{$2} #{$1}"
else
position
@ -103,9 +111,16 @@ module Compass::SassExtensions::Functions::GradientSupport
"left #{position}"
when /left|right/
"#{position} top"
else
position
end
end
Sass::Script::String.new position.gsub(/top/, "0%").gsub(/bottom/, "100%").gsub(/left/,"0%").gsub(/right/,"100%")
Sass::Script::String.new(position.
gsub(/top/, "0%").
gsub(/bottom/, "100%").
gsub(/left/,"0%").
gsub(/right/,"100%").
gsub(/center/, "50%"))
end
def color_stops(*args)
@ -125,7 +140,11 @@ module Compass::SassExtensions::Functions::GradientSupport
end
stop = Sass::Script::Number.new(number)
elsif !stop.nil?
raise Sass::SyntaxError, "A color stop location must be between 0 and 1 or 0% and 100%. Got: #{stop}"
number = Sass::Script::Parser.parse(stop, 0, 0)
unless number.is_a?(Sass::Script::Number)
raise Sass::SyntaxError, "A color stop location must be a number. Got: #{stop}"
end
stop = number
end
ColorStop.new(color, stop)
else
@ -133,5 +152,35 @@ module Compass::SassExtensions::Functions::GradientSupport
end
end)
end
private
def normalize_stops!(color_list)
positions = color_list.values
# fill in the start and end positions, if unspecified
positions.first.stop = Sass::Script::Number.new(0) unless positions.first.stop
positions.last.stop = Sass::Script::Number.new(100, ["%"]) unless positions.last.stop
# fill in empty values
for i in 0...positions.size
if positions[i].stop.nil?
num = 2.0
for j in (i+1)...positions.size
if positions[j].stop
positions[i].stop = positions[i-1].stop.plus((positions[j].stop.minus(positions[i-1].stop)).div(Sass::Script::Number.new(num)))
break
else
num += 1
end
end
end
end
# normalize unitless numbers
positions.each do |pos|
if pos.stop.unitless? && pos.stop.value <= 1
pos.stop = pos.stop.times(Sass::Script::Number.new(100, ["%"]))
elsif pos.stop.unitless?
pos.stop = pos.stop.times(Sass::Script::Number.new(1, ["px"]))
end
end
nil
end
end
end

View File

@ -1,43 +1,71 @@
.linear-1 {
background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa));
background-image: -moz-linear-gradient(top, #dddddd, #aaaaaa); }
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa));
background-image: -moz-linear-gradient(top, #dddddd 0%, #aaaaaa 100%); }
.linear-2 {
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#dddddd), to(#aaaaaa));
background-image: -moz-linear-gradient(left, #dddddd, #aaaaaa); }
background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa));
background-image: -moz-linear-gradient(left, #dddddd 0%, #aaaaaa 100%); }
.linear-3 {
background-image: -webkit-gradient(linear, 0% 0%, 100% 100%, from(#dddddd), to(#aaaaaa));
background-image: -moz-linear-gradient(top left, #dddddd, #aaaaaa); }
background-image: -webkit-gradient(linear, 0% 0%, 100% 100%, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa));
background-image: -moz-linear-gradient(top left, #dddddd 0%, #aaaaaa 100%); }
.linear-4 {
background-image: -webkit-gradient(linear, 0% 100%, 100% 0%, from(#dddddd), to(#aaaaaa));
background-image: -moz-linear-gradient(top right, #dddddd, #aaaaaa); }
background-image: -webkit-gradient(linear, 100% 0%, 0% 100%, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa));
background-image: -moz-linear-gradient(top right, #dddddd 0%, #aaaaaa 100%); }
.linear-5 {
background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa), color-stop(50%, #cccccc));
background-image: -moz-linear-gradient(top, #dddddd, #cccccc, #aaaaaa); }
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #dddddd), color-stop(50%, #cccccc), color-stop(100%, #aaaaaa));
background-image: -moz-linear-gradient(top, #dddddd 0%, #cccccc 50%, #aaaaaa 100%); }
.linear-6 {
background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa), color-stop(20%, #cccccc));
background-image: -moz-linear-gradient(top, #dddddd, #cccccc 20%, #aaaaaa); }
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #dddddd), color-stop(20%, #cccccc), color-stop(100%, #aaaaaa));
background-image: -moz-linear-gradient(top, #dddddd 0%, #cccccc 20%, #aaaaaa 100%); }
.linear-7 {
background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa), color-stop(20%, #cccccc), color-stop(60%, #eeeeee));
background-image: -moz-linear-gradient(top, #dddddd, #cccccc 20%, #eeeeee, #aaaaaa); }
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #dddddd), color-stop(20%, #cccccc), color-stop(50.1%, #eeeeee), color-stop(100%, #aaaaaa));
background-image: -moz-linear-gradient(top, #dddddd 0%, #cccccc 20%, #eeeeee 50.1%, #aaaaaa 100%); }
.linear-8 {
background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa), color-stop(80%, #dddddd));
background-image: -moz-linear-gradient(top, #dddddd 80%, #aaaaaa); }
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(80%, #dddddd), color-stop(100%, #aaaaaa));
background-image: -moz-linear-gradient(top, #dddddd 80%, #aaaaaa 100%); }
.linear-9 {
background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa), color-stop(20%, #aaaaaa));
background-image: -moz-linear-gradient(top, #dddddd, #aaaaaa 20%); }
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa));
background-image: -moz-linear-gradient(top, #dddddd 0%, #aaaaaa 20%); }
.linear-10 {
background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa), color-stop(40%, #dddddd), color-stop(50%, #aaaaaa));
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(80%, #dddddd), color-stop(100%, #aaaaaa));
background-image: -moz-linear-gradient(top, #dddddd 40%, #aaaaaa 50%); }
.linear-11 {
background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa), color-stop(40%, #dddddd), color-stop(45%, black), color-stop(50%, #aaaaaa));
background-image: -moz-linear-gradient(top, #dddddd 40%, black, #aaaaaa 50%); }
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(80%, #dddddd), color-stop(90%, black), color-stop(100%, #aaaaaa));
background-image: -moz-linear-gradient(top, #dddddd 40%, black 45%, #aaaaaa 50%); }
.radial-1 {
background-image: -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 100, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa));
background-image: -moz-radial-gradient(center center, circle, #dddddd 0%, #aaaaaa 100%); }
.radial-2 {
background-image: -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 100, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa));
background-image: -moz-radial-gradient(center center, circle, #dddddd 0%, #aaaaaa 100%); }
.radial-3 {
background-image: -webkit-gradient(radial, 50% 0%, 0, 50% 0%, 100, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa));
background-image: -moz-radial-gradient(top center, circle, #dddddd 0%, #aaaaaa 100%); }
.radial-4 {
background-image: -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 100, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa));
background-image: -moz-radial-gradient(center center, circle, #dddddd 0%, #aaaaaa 100%); }
.radial-5 {
background-image: -webkit-gradient(radial, 50% 0%, 0, 50% 0%, 100, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa));
background-image: -moz-radial-gradient(top center, circle, #dddddd 0%, #aaaaaa 100%); }
.radial-6 {
background-image: -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 50, color-stop(40%, #dddddd), color-stop(100%, #aaaaaa));
background-image: -moz-radial-gradient(center center, circle, #dddddd 20px, #aaaaaa 50px); }
.radial-7 {
background-image: -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 50, color-stop(20%, #dddddd), color-stop(100%, #aaaaaa));
background-image: -moz-radial-gradient(center center, circle, #dddddd 20%, #aaaaaa 50px); }

View File

@ -21,4 +21,28 @@
.linear-10
+linear-gradient(color_stops(#ddd 40%, #aaa 50%))
.linear-11
+linear-gradient(color_stops(#ddd 40%, #000, #aaa 50%))
+linear-gradient(color_stops(#ddd 40%, #000, #aaa 50%))
.radial-1
// A default radial gradient:
// A centered gradient having the shape of the container (aka ellipse)
+radial-gradient(color_stops(#ddd, #aaa))
.radial-2
// A centered gradient having the shape of the container (aka ellipse)
+radial-gradient(color_stops(#ddd, #aaa))
.radial-3
// A centered gradient at the top having the shape of the container (aka ellipse)
+radial-gradient(color_stops(#ddd, #aaa), "top center")
.radial-4
// A centered gradient having a circular shape
+radial-gradient(color_stops(#ddd, #aaa))
.radial-5
// A centered gradient at the top having a circular shape
+radial-gradient(color_stops(#ddd, #aaa), "top center")
.radial-6
// A centered circular gradient with color stops
// The color stops must be absolute units
+radial-gradient(color_stops(#ddd 20px, #aaa 50px))
.radial-7
// A centered elliptical gradient with color stops
// The color stops must be relative units
+radial-gradient(color_stops(#ddd 20%, #aaa 50px))