From 4dc455f312797aeeda9eba244bfe804500d13070 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sun, 14 Nov 2010 16:39:43 -0800 Subject: [PATCH] [CSS3] Support for the border-image property. --- .../stylesheets/compass/css3/_gradient.scss | 19 ----- .../stylesheets/compass/css3/_images.scss | 34 ++++++++ .../stylesheets/compass/css3/_shared.scss | 2 +- .../stylesheets/compass/css3/_version-1.scss | 1 + .../stylesheets/compass/css3/_version-2.scss | 1 + .../functions/gradient_support.rb | 80 ++++++++++++++++++- .../stylesheets/compass/css/gradients.css | 16 ++-- .../stylesheets/compass/sass/gradients.sass | 4 + 8 files changed, 129 insertions(+), 28 deletions(-) create mode 100644 frameworks/compass/stylesheets/compass/css3/_images.scss diff --git a/frameworks/compass/stylesheets/compass/css3/_gradient.scss b/frameworks/compass/stylesheets/compass/css3/_gradient.scss index 31a00482..42d1a0f4 100644 --- a/frameworks/compass/stylesheets/compass/css3/_gradient.scss +++ b/frameworks/compass/stylesheets/compass/css3/_gradient.scss @@ -1,24 +1,5 @@ -@import "shared"; @import "compass/utilities/general/hacks"; -@mixin background-image( - $image-1, $image-2: false, $image-3: false, - $image-4: false, $image-5: false, $image-6: false, - $image-7: false, $image-8: false, $image-9: false, $image-10: false -) { - $images: compact($image-1, $image-2, $image-3, $image-4 ,$image-5, $image-6, $image-7, $image-8, $image-9, $image-10); - @if $experimental-support-for-webkit and prefixed(-webkit, $images) { - background-image: -webkit($images); - } - @if $experimental-support-for-mozilla and prefixed(-moz, $images) { - background-image: -moz($images); - } - @if $experimental-support-for-svg and prefixed(-svg, $images) { - background-image: -svg($images); - } - background-image: $images; -} - // The linear gradient mixin works best across browsers if you use percentage-based color stops. // // Examples: diff --git a/frameworks/compass/stylesheets/compass/css3/_images.scss b/frameworks/compass/stylesheets/compass/css3/_images.scss new file mode 100644 index 00000000..d26b880f --- /dev/null +++ b/frameworks/compass/stylesheets/compass/css3/_images.scss @@ -0,0 +1,34 @@ +@import "shared"; + + +@mixin background-image( + $image-1, + $image-2: false, + $image-3: false, + $image-4: false, + $image-5: false, + $image-6: false, + $image-7: false, + $image-8: false, + $image-9: false, + $image-10: false +) { + $images: compact($image-1, $image-2, $image-3, $image-4, $image-5, $image-6, $image-7, $image-8, $image-9, $image-10); + + @if $experimental-support-for-mozilla and prefixed(-moz, $images) { background-image: -moz($images); } + @if $experimental-support-for-webkit and prefixed(-webkit, $images) { background-image: -webkit($images); } + @if $experimental-support-for-svg and prefixed(-svg, $images) { background-image: -svg($images); } + background-image: $images; +} + +@mixin border-image($value) { + // This is just until we have Official Sass list support in 3.1 + $values: -compass-list($value); + $image: -compass-nth($values, first); + $rest: -compass-slice($values, 2); + + @if $experimental-support-for-mozilla { -moz-border-image: -moz($image) $rest; } + @if $experimental-support-for-webkit { -webkit-border-image: -webkit($image) $rest; } + @if $experimental-support-for-svg { border-image: -svg($image) $rest; } + border-image: $image $rest; +} diff --git a/frameworks/compass/stylesheets/compass/css3/_shared.scss b/frameworks/compass/stylesheets/compass/css3/_shared.scss index e0860673..e1a7628a 100644 --- a/frameworks/compass/stylesheets/compass/css3/_shared.scss +++ b/frameworks/compass/stylesheets/compass/css3/_shared.scss @@ -35,4 +35,4 @@ @if $ms and $experimental-support-for-microsoft { #{$property} : -ms-#{$value}; } @if $khtml and $experimental-support-for-khtml { #{$property} : -khtml-#{$value}; } @if $official { #{$property} : #{$value}; } -} \ No newline at end of file +} diff --git a/frameworks/compass/stylesheets/compass/css3/_version-1.scss b/frameworks/compass/stylesheets/compass/css3/_version-1.scss index cc124cc1..273f9d49 100644 --- a/frameworks/compass/stylesheets/compass/css3/_version-1.scss +++ b/frameworks/compass/stylesheets/compass/css3/_version-1.scss @@ -6,6 +6,7 @@ @import "columns"; @import "box-sizing"; @import "box"; +@import "images"; @import "gradient"; @import "background-clip"; @import "background-origin"; diff --git a/frameworks/compass/stylesheets/compass/css3/_version-2.scss b/frameworks/compass/stylesheets/compass/css3/_version-2.scss index 54f7681c..ffe69b09 100644 --- a/frameworks/compass/stylesheets/compass/css3/_version-2.scss +++ b/frameworks/compass/stylesheets/compass/css3/_version-2.scss @@ -6,6 +6,7 @@ @import "columns"; @import "box-sizing"; @import "box"; +@import "images"; @import "gradient"; @import "background-clip"; @import "background-origin"; diff --git a/lib/compass/sass_extensions/functions/gradient_support.rb b/lib/compass/sass_extensions/functions/gradient_support.rb index 8d133a7d..5ba2709e 100644 --- a/lib/compass/sass_extensions/functions/gradient_support.rb +++ b/lib/compass/sass_extensions/functions/gradient_support.rb @@ -5,11 +5,20 @@ module Compass::SassExtensions::Functions::GradientSupport def initialize(*values) self.values = values end + def join_with + ", " + end def inspect - values.map{|v| v.inspect}.join(", ") + to_s end def to_s - values.map{|v| v.to_s}.join(", ") + values.map {|v| v.to_s }.join(join_with) + end + end + + class SpaceList < List + def join_with + " " end end @@ -111,7 +120,6 @@ module Compass::SassExtensions::Functions::GradientSupport end end - module Functions def radial_gradient(position_or_angle, shape_or_size, *color_stops) @@ -260,6 +268,49 @@ module Compass::SassExtensions::Functions::GradientSupport List.new(*args.reject{|a| !a.to_bool}) end + # Returns a list object from a value that was passed. + # This can be used to unpack a space separated list that got turned + # into a string by sass before it was passed to a mixin. + def _compass_list(arg) + return arg if arg.is_a?(List) + values = case arg + when Sass::Script::String + expr = Sass::Script::Parser.parse(arg.value, 0, 0) + if expr.is_a?(Sass::Script::Operation) + extract_list_values(expr) + elsif expr.is_a?(Sass::Script::Funcall) + expr.perform(Sass::Environment.new) #we already evaluated the args in context so no harm in using a fake env + else + [arg] + end + else + [arg] + end + + SpaceList.new(*values) + end + + # Get the nth value from a list + def _compass_nth(list, place) + if place.value == "last" + list.values.last + elsif place.value == "first" + list.values.first + else + list.values[place.value - 1] + end + end + + # slice a sublist from a list + def _compass_slice(list, start_index, end_index = nil) + end_index ||= Sass::Script::Number.new(-1) + start_index = start_index.value + end_index = end_index.value + start_index -= 1 unless start_index < 0 + end_index -= 1 unless end_index < 0 + list.class.new *list.values[start_index..end_index] + end + %w(webkit moz o ms svg).each do |prefix| class_eval <<-RUBY, __FILE__, __LINE__ + 1 def _#{prefix}(*args) @@ -269,6 +320,7 @@ module Compass::SassExtensions::Functions::GradientSupport RUBY end + # Check if any of the arguments passed have a tendency towards vendor prefixing. def prefixed(prefix, *args) method = prefix.value.sub(/^-/,"to_").to_sym args.map!{|a| a.is_a?(List) ? a.values : a}.flatten! @@ -276,6 +328,28 @@ module Compass::SassExtensions::Functions::GradientSupport end private + # After using the sass script parser to parse a string, this reconstructs + # a list from operands to the space/concat operation + def extract_list_values(operation) + left = operation.instance_variable_get("@operand1") + right = operation.instance_variable_get("@operand2") + left = extract_list_values(left) if left.is_a?(Sass::Script::Operation) + right = extract_list_values(right) if right.is_a?(Sass::Script::Operation) + left = literalize(left) unless left.is_a?(Array) + right = literalize(right) unless right.is_a?(Array) + Array(left) + Array(right) + end + # Makes a literal from other various script nodes. + def literalize(node) + case node + when Sass::Script::Literal + node + when Sass::Script::Funcall + node.perform(Sass::Environment.new) + else + Sass::Script::String.new(node.to_s) + end + end def normalize_stops!(color_list) positions = color_list.values # fill in the start and end positions, if unspecified diff --git a/test/fixtures/stylesheets/compass/css/gradients.css b/test/fixtures/stylesheets/compass/css/gradients.css index 425afb8d..44956d3f 100644 --- a/test/fixtures/stylesheets/compass/css/gradients.css +++ b/test/fixtures/stylesheets/compass/css/gradients.css @@ -2,31 +2,37 @@ background-image: url("foo.png"); } .bg-linear-gradient { + 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%); background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+IDxkZWZzPiA8bGluZWFyR3JhZGllbnQgaWQ9ImdyYWQiIHgxPSIwJSIgeTE9IjAlIiB4Mj0iMTAwJSIgeTI9IjEwMCUiPiA8c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjZGRkZGRkIiAvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2FhYWFhYSIgLz4gPC9saW5lYXJHcmFkaWVudD4gPC9kZWZzPiA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2dyYWQpIiAvPiA8L3N2Zz4g'); background-image: linear-gradient(top left, #dddddd 0%, #aaaaaa 100%); } .bg-radial-gradient { + background-image: -moz-radial-gradient(center center, #dddddd, #aaaaaa 100px); 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, #dddddd 0%, #aaaaaa 100px); background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+IDxkZWZzPiA8cmFkaWFsR3JhZGllbnQgaWQ9ImdyYWQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjeD0iNTAlIiBjeT0iNTAlIiByPSIxMDAiPiA8c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjZGRkZGRkIiAvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2FhYWFhYSIgLz4gPC9yYWRpYWxHcmFkaWVudD4gPC9kZWZzPiA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2dyYWQpIiAvPiA8L3N2Zz4g'); background-image: radial-gradient(center center, #dddddd 0%, #aaaaaa 100px); } .bg-all-gradient-types { + background-image: url('/images/4x6.png?busted=true'), -moz-linear-gradient(top left, #dddddd, #aaaaaa), -moz-radial-gradient(center center, #dddddd, #aaaaaa 100px); background-image: url('/images/4x6.png?busted=true'), -webkit-gradient(linear, 0% 0%, 100% 100%, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa)), -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 100, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa)); - background-image: url('/images/4x6.png?busted=true'), -moz-linear-gradient(top left, #dddddd 0%, #aaaaaa 100%), -moz-radial-gradient(center center, #dddddd 0%, #aaaaaa 100px); background-image: url('/images/4x6.png?busted=true'), url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+IDxkZWZzPiA8bGluZWFyR3JhZGllbnQgaWQ9ImdyYWQiIHgxPSIwJSIgeTE9IjAlIiB4Mj0iMTAwJSIgeTI9IjEwMCUiPiA8c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjZGRkZGRkIiAvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2FhYWFhYSIgLz4gPC9saW5lYXJHcmFkaWVudD4gPC9kZWZzPiA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2dyYWQpIiAvPiA8L3N2Zz4g'), url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+IDxkZWZzPiA8cmFkaWFsR3JhZGllbnQgaWQ9ImdyYWQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjeD0iNTAlIiBjeT0iNTAlIiByPSIxMDAiPiA8c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjZGRkZGRkIiAvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2FhYWFhYSIgLz4gPC9yYWRpYWxHcmFkaWVudD4gPC9kZWZzPiA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2dyYWQpIiAvPiA8L3N2Zz4g'); background-image: url('/images/4x6.png?busted=true'), linear-gradient(top left, #dddddd 0%, #aaaaaa 100%), radial-gradient(center center, #dddddd 0%, #aaaaaa 100px); } +.border-image-gradient { + -moz-border-image: -moz-radial-gradient(#00ff00, #ff0000 100px) 100 stretch; + -webkit-border-image: -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 100, color-stop(0%, #00ff00), color-stop(100%, #ff0000)) 100 stretch; + border-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+IDxkZWZzPiA8cmFkaWFsR3JhZGllbnQgaWQ9ImdyYWQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBjeD0iNTAlIiBjeT0iNTAlIiByPSIxMDAiPiA8c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjMDBmZjAwIiAvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2ZmMDAwMCIgLz4gPC9yYWRpYWxHcmFkaWVudD4gPC9kZWZzPiA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2dyYWQpIiAvPiA8L3N2Zz4g') 100 stretch; + border-image: radial-gradient(#00ff00 0%, #ff0000 100px) 100 stretch; } + .bg-linear-gradient-no-position { + background-image: -moz-linear-gradient(#dddddd, #aaaaaa); background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa)); - background-image: -moz-linear-gradient(#dddddd 0%, #aaaaaa 100%); background-image: linear-gradient(#dddddd 0%, #aaaaaa 100%); } .bg-radial-gradient-no-position { + background-image: -moz-radial-gradient(#dddddd, #aaaaaa 100px); background-image: -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 100, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa)); - background-image: -moz-radial-gradient(#dddddd 0%, #aaaaaa 100px); background-image: radial-gradient(#dddddd 0%, #aaaaaa 100px); } .linear-1 { diff --git a/test/fixtures/stylesheets/compass/sass/gradients.sass b/test/fixtures/stylesheets/compass/sass/gradients.sass index 0fc7d85b..4cb5a02d 100644 --- a/test/fixtures/stylesheets/compass/sass/gradients.sass +++ b/test/fixtures/stylesheets/compass/sass/gradients.sass @@ -12,6 +12,10 @@ $experimental-support-for-svg: true .bg-all-gradient-types +background-image(image-url("4x6.png"), linear-gradient(top left, #ddd, #aaa), radial-gradient(center center, #ddd, #aaa 100px)) + +.border-image-gradient + +border-image(radial-gradient(#0f0,#f00 100px) 100 stretch) + $experimental-support-for-svg: false .bg-linear-gradient-no-position