CSS (Perhaps with Compass): Cross-Browser Gradient

CSS (perhaps with Compass): Cross-browser gradient

I just noticed that the current Compass beta (0.11.beta.6) has support for generating IE gradients in the compass/css3/images module (which supersedes the previous gradient module), so you can generate your gradients with a total of two short commands:

@import "compass/css3/images";
@import "compass/utilities/general/hacks"; /* filter-gradient needs this */

.whatever {
/* IE; docs say this should go first (or better, placed in separate IE-only stylesheet): */
@include filter-gradient(#aaaaaa, #eeeeee);
/* Fallback: */
background: #cccccc;
/* CSS 3 plus vendor prefixes: */
@include background(linear-gradient(top, #aaaaaa, #eeeeee));
}

This generates the following slew of CSS:

.whatever {
*zoom: 1;
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#FFAAAAAA', endColorstr='#FFEEEEEE')";
filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#FFAAAAAA', endColorstr='#FFEEEEEE');
background: #cccccc;
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #aaaaaa), color-stop(100%, #eeeeee));
background: -moz-linear-gradient(top, #aaaaaa, #eeeeee);
background: -o-linear-gradient(top, #aaaaaa, #eeeeee);
background: linear-gradient(top, #aaaaaa, #eeeeee);
}

I guess I would have preferred to have the IE and non-IE gradient code in one call, but since IE's DXImageTransform gradient function is pretty limited, that is probably not possible.

How to overwrite linear-gradient function in Compass?

What you are attempting won't work, because we are dealing with prefixed values that have to be split apart into distinct properties. As the author of the linked code, here is how I recommend using it. You'll need these functions:

@function convert-gradient-angle(
$deg
) {
@if type-of($deg) == 'number' {
@return mod(abs($deg - 450), 360deg);
} @else {
$direction: compact();
@if nth($deg,1) == 'to' {
@if length($deg) < 2 {
$direction: top;
@warn "no direction given for 'to'. Using 'to bottom' as default.";
} @else { $direction: opposite-position(nth($deg,2)); }
@if length($deg) > 2 { $direction: append($direction, opposite-position(nth($deg,3)), space);}
} @else {
$direction: append($direction, to, space);
@each $pos in $deg { $direction: append($direction, opposite-position($pos), space); }
}
@return $direction;
}
}

@function convert-gradient(
$angle,
$details...
) {
@return linear-gradient(convert-gradient-angle($angle), $details...);
}

The problem is, if you use multiple-backgrounds or anything like that, you will have to repeat the functions yourself in different properties. If you just want a simple background-image gradient, you can use this to simplify:

@mixin gradient-background-image(
$gradient...
) {
@include background-image(convert-gradient($gradient...));
background-image: linear-gradient($gradient...);
}

Otherwise you will need to write those two lines by hand, adding the other layers as needed.

Adding !important using a Compass Mixin

UPDATE: new versions of sass support this syntax now:

@include border-radius(5px !important);

Just do this (as noted in @naoufal answer).

--- old answer ---

You can not use !important with compass mixings, but the culprit is not compass, you should blame sass for this.

@include border-radius(5px) !important; #=> SASS Syntax Error

IE9 border-radius and background gradient bleeding

Here's one solution that adds a background gradient, using a data URI to create a semi-transparent image that overlays any background color. I've verified that it's clipped correctly to the border radius in IE9. This is lighter weight than SVG-based proposals but as a downside, is not resolution-independent. Another advantage: works with your current HTML/CSS and does not require wrapping with additional elements.

I grabbed a random 20x20 gradient PNG via a web search, and converted it into a data URI using an online tool. The resulting data URI is smaller than the CSS code for all that SVG mess, much less the SVG itself! (You could apply this conditionally to IE9 only using conditional styles, browser-specific css classes, etc.) Of course, generating a PNG works great for button-sized gradients, but not page-sized gradients!

HTML:

<span class="button">This is a button</span>

CSS:

span.button { 
padding: 5px 10px;
border-radius: 10px;
background-color: orange;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAvUlEQVQ4y63VMQrDMAyF4d/BGJ+rhA4dOnTo0Kn3P4ExxnSoXVQhpx0kEMmSjyfiKAF4AhVoqrvqjXdtoqPoBMQAPAZwhMpaYkAKwH1gFtgG0v9IlyZ4E2BVabtKeZhuglegKKyqsWXFVboJXgZQfqSUCZOFATkAZwEVY/ymQAtKQJ4Jd4VZqARnuqyxmXAfiAQtFJEuG9dPwtMC0zD6YXH/ldAddB/Z/aW4Hxv3g+3+6bkvB/f15b5gXX8BL0z+tEEtuNA8AAAAAElFTkSuQmCC);
background-size: 100% 100%;

border: 2px solid white;
color: white;
}

Easier Cross-Browser CSS3 Features

You could use any of the following to ease your sorrows:

Dynamic Stylesheet Languages/CSS Extensions

  • LESS
  • Sass
  • Compass (Sass Framework)

CSS 3 Generators

  • Prefixr
  • CSS 3 Please
  • CSS 3 Generator
  • Mother Effing HSL
  • Mother Effing Text Shadow
  • CSS 3 Maker
  • CSS Gradient Generator
  • CSS Filter Effects

Is there a current or proposed way to set individual layers of multiple backgrounds?

Abstract it with Pseudo Elements

I am not aware of any way to "swap" a single background yet. One workaround is based off the "separate elements" technique, but the inner element is a pseudo-element instead. I have no idea about rendering speed. It also has the drawback that it will not work for IE8, as you cannot apply filter to pseudo-elements. However, since you are using the idea in conjunction with CSS3 perspective and such, the IE8 caveat is not an issue for you.

This achieves the abstraction of the texture from the shading. It could even add another layer through an :after pseudo-element, and it still could use multiple backgrounds in each of the three if needed/desired.

Here is the fiddle.

Sample Code:

HTML

<div class="texture"></div>
<div class="texture light"></div>
<div class="texture medium"></div>
<div class="texture dark"></div>

CSS (core)

.texture {
position: relative;
background: url(http://www.dummyimage.com/12x16/ff0000/ffffff.png&text=X++) top left repeat;
}

.light:before,
.medium:before,
.dark:before {
content: '';
position: absolute;
top:0;
right: 0;
bottom:0;
left: 0;
}
.light:before {
background: -moz-linear-gradient(left, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.1) 100%);
background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(0,0,0,0.3)), color-stop(100%,rgba(0,0,0,0.1)));
background: -webkit-linear-gradient(left, rgba(0,0,0,0.3) 0%,rgba(0,0,0,0.1) 100%);
background: -o-linear-gradient(left, rgba(0,0,0,0.3) 0%,rgba(0,0,0,0.1) 100%);
background: -ms-linear-gradient(left, rgba(0,0,0,0.3) 0%,rgba(0,0,0,0.1) 100%);
background: linear-gradient(to right, rgba(0,0,0,0.3) 0%,rgba(0,0,0,0.1) 100%);
}
.medium:before {
background: -moz-linear-gradient(left, rgba(0,0,0,0.6) 0%, rgba(0,0,0,0.2) 100%);
background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(0,0,0,0.6)), color-stop(100%,rgba(0,0,0,0.2)));
background: -webkit-linear-gradient(left, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.2) 100%);
background: -o-linear-gradient(left, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.2) 100%);
background: -ms-linear-gradient(left, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.2) 100%);
background: linear-gradient(to right, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.2) 100%);
}
.dark:before {
background: -moz-linear-gradient(left, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0.3) 100%);
background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(0,0,0,0.8)), color-stop(100%,rgba(0,0,0,0.3)));
background: -webkit-linear-gradient(left, rgba(0,0,0,0.8) 0%,rgba(0,0,0,0.3) 100%);
background: -o-linear-gradient(left, rgba(0,0,0,0.8) 0%,rgba(0,0,0,0.3) 100%);
background: -ms-linear-gradient(left, rgba(0,0,0,0.8) 0%,rgba(0,0,0,0.3) 100%);
background: linear-gradient(to right, rgba(0,0,0,0.8) 0%,rgba(0,0,0,0.3) 100%);
}


Related Topics



Leave a reply



Submit