New linear gradient mixin and support functions. Radial gradient and browser testing are still pending.

This commit is contained in:
Chris Eppstein 2010-02-16 01:47:27 -08:00
parent 925938cd5e
commit aef52bd57e
7 changed files with 222 additions and 38 deletions

View File

@ -6,35 +6,39 @@
background: -moz-#{!type}-gradient(#{!gradient})
//*
// This will yeild a radial gradient with an apparent specular highlight
// 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 !start to !end coordinates
+linear-gradient("left top", "left bottom", #fff, #ddd)
=linear-gradient(!start, !end, !color1, !color2, !color_stop = false)
!coords = !start + ", " + !end
+gradient("linear", !coords, !color1, !color2, !color_stop)
//*
// This yields a gradient starting at the top with #fff, ending in #aaa
+v-gradient(#fff, #aaa)
// Same as above but with a #ccc at the halfway point
+v-gradient(#fff, #aaa, color_stop(50%, #ccc))
// Same as the first example but with #ccc at the 30% from the top, and #bbb at 70% from the top
+v-gradient(#fff, #aaa, color_stop(30%, #ccc, 70%, #bbb))
=v-gradient(!color1, !color2, !color_stop = false)
+linear-gradient("left top", "left bottom", !color1, !color2, !color_stop)
//*
// This yields a horizontal linear gradient spanning from left to right
// It can be used just like v-gradient above
h-gradient(#fff, #ddd)
// This yields a linear gradient spanning from top to bottom
+linear-gradient(color_stops(white, black))
=h-gradient(!color1, !color2, !color_stop = false)
+linear-gradient("left top", "right top", !color1, !color2, !color_stop)
// 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%))
=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: -moz-linear-gradient(#{!start}, #{!color_stops})

View File

@ -1,7 +1,7 @@
module Compass::SassExtensions::Functions
end
%w(selectors enumerate urls display inline_image color_stop font_files).each do |func|
%w(selectors enumerate urls display inline_image gradient_support font_files).each do |func|
require "compass/sass_extensions/functions/#{func}"
end
@ -11,7 +11,7 @@ module Sass::Script::Functions
include Compass::SassExtensions::Functions::Urls
include Compass::SassExtensions::Functions::Display
include Compass::SassExtensions::Functions::InlineImage
include Compass::SassExtensions::Functions::ColorStop
include Compass::SassExtensions::Functions::GradientSupport::Functions
include Compass::SassExtensions::Functions::FontFiles
end

View File

@ -1,10 +0,0 @@
module Compass::SassExtensions::Functions::ColorStop
def color_stop(*args)
raise Sass::SyntaxError, "An even number of arguments must be passed to color-stop()" unless args.size % 2 == 0
stops = []
while args.size > 0
stops << "color-stop(#{args.shift}, #{args.shift})"
end
Sass::Script::String.new(stops.join(", "))
end
end

View File

@ -0,0 +1,123 @@
module Compass::SassExtensions::Functions::GradientSupport
class List < Sass::Script::Literal
attr_accessor :values
def initialize(*values)
self.values = values
end
def inspect
to_s
end
def to_s
values.map{|v| v.to_s}.join(", ")
end
end
class ColorStop < Sass::Script::Literal
attr_accessor :color, :stop
def initialize(color, stop = nil)
self.color, self.stop = color, stop
end
def inspect
to_s
end
def to_s
s = "#{color}"
if stop
s << " "
s << stop.times(Sass::Script::Number.new(100)).to_s
s << "%"
end
s
end
end
module Functions
def grad_opposite_position(position)
opposite = position.value.split(/ +/).map do |pos|
case pos
when "top" then "bottom"
when "bottom" then "top"
when "left" then "right"
when "right" then "left"
else
raise Sass::SyntaxError, "Cannot determine the opposite of #{pos}"
end
end
Sass::Script::String.new(opposite.join(" "))
end
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
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)
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(", "))
end
end
def grad_start_color(color_list)
color_list.values.first.color
end
def grad_end_color(color_list)
color_list.values.last.color
end
def grad_point(position)
position = position.value
position = if position[" "]
position
else
case position
when /top|bottom/
"#{position} left"
when /left|right/
"top #{position}"
end
end
Sass::Script::String.new position.gsub(/top/, "0%").gsub(/bottom/, "100%").gsub(/left/,"0%").gsub(/right/,"100%")
end
def color_stops(*args)
List.new(*args.map do |arg|
case arg
when Sass::Script::Color
ColorStop.new(arg)
when Sass::Script::String
color, stop = arg.value.split(/ +/, 2)
color = Sass::Script::Parser.parse(color, 0, 0)
if stop =~ /^(\d+)?(?:\.(\d+))?(%)?$/
integral, decimal, percent = $1, $2, $3
number = "#{integral || 0}.#{decimal || 0}".to_f
number = number / 100 if percent
if number > 1
raise Sass::SyntaxError, "A color stop location must be between 0#{"%" if percent} and 1#{"00%" if percent}. Got: #{stop}"
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}"
end
ColorStop.new(color, stop)
else
raise Sass::SyntaxError, "Not a valid color stop: #{arg}"
end
end)
end
end
end

View File

@ -42,7 +42,7 @@ class CompassTest < Test::Unit::TestCase
each_css_file(proj.css_path) do |css_file|
assert_no_errors css_file, 'compass'
end
assert_renders_correctly :reset, :layout, :utilities
assert_renders_correctly :reset, :layout, :utilities, :gradients
end
end

View File

@ -0,0 +1,43 @@
.linear-1 {
background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa));
background-image: -moz-linear-gradient(top, #dddddd, #aaaaaa); }
.linear-2 {
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#dddddd), to(#aaaaaa));
background-image: -moz-linear-gradient(left, #dddddd, #aaaaaa); }
.linear-3 {
background-image: -webkit-gradient(linear, 0% 0%, 100% 100%, from(#dddddd), to(#aaaaaa));
background-image: -moz-linear-gradient(top left, #dddddd, #aaaaaa); }
.linear-4 {
background-image: -webkit-gradient(linear, 0% 100%, 100% 0%, from(#dddddd), to(#aaaaaa));
background-image: -moz-linear-gradient(top right, #dddddd, #aaaaaa); }
.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); }
.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); }
.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); }
.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); }
.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%); }
.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: -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%); }

View File

@ -0,0 +1,24 @@
@import compass/css3.sass
.linear-1
+linear-gradient(color_stops(#ddd, #aaa))
.linear-2
+linear-gradient(color_stops(#ddd, #aaa), "left")
.linear-3
+linear-gradient(color_stops(#ddd, #aaa), "top left")
.linear-4
+linear-gradient(color_stops(#ddd, #aaa), "top right")
.linear-5
+linear-gradient(color_stops(#ddd, #ccc, #aaa))
.linear-6
+linear-gradient(color_stops(#ddd, #ccc 20%, #aaa))
.linear-7
+linear-gradient(color_stops(#ddd, #ccc 20%, #eee, #aaa))
.linear-8
+linear-gradient(color_stops(#ddd 80%, #aaa))
.linear-9
+linear-gradient(color_stops(#ddd, #aaa 20%))
.linear-10
+linear-gradient(color_stops(#ddd 40%, #aaa 50%))
.linear-11
+linear-gradient(color_stops(#ddd 40%, #000, #aaa 50%))