Sass (SCSS) powered Linear and Radial CSS3 gradients with MS Filters

I thought i'd share this code, it may be help anyone who wants to have some sort of backward compatibility when using CSS3 gradients with Internet Explorer 7+.
 

How does this work?

Sass mixins and functions helps a lot with the 'heavy-lifting' and colour calculations. Let me explain the setup for Linear and Radial gradients below.

Linear Graidents -- For Linear gradients there are five parameters:

  • Fallback colour -- Value to be supplied in RGBa.
  • Direction -- Default is 'false' but can be supplied as 'to right', 'to left', etc.
  • IE Filter Start Colour -- The IE filter can only use a start and end colour, this is the start colour and can be supplied in RGBa.
  • IE Filter End Colour -- This is the end colour, an can also be supplied in RGBa.
  • Colour Stops (Comma separated list of colours) -- These can be supplied in RGBa.

Radial Graidents -- For Radial gradients there are just two parameters:

  • Fallback colour -- Value to be supplied in HEX only, as the MS filter does not accept colour codes. This fallback colour is only used as a background colour.
  • Colour Stops (Comma separated list of colours) -- These can be supplied in RGBa.

The mixins then take care of creating the gradients by using the Sass functions and other complimentary mixins.
 

Demo

I have uploaded the demo to CodePen, you can visit it here. An embed is below:

See the Pen Sass (SCSS) powered Linear and Radial CSS3 gradients with MS Filters by Ryan Fitton (@ryanfitton) on CodePen.  

Mixin Examples

Linear gradient

Once you have the Mixin and Functions code ready, you can specify a Linear Gradient like this:

//Green linear gradient
&.green-linear {
    /*
        Notes:

        Fallback color:         rgba(#78BA00, 1)
        Direction:              to right
        IE Filter Start Color:  rgba(#78BA00, 1)
        IE Filter End Color:    rgba(#ffffff, 1)
        Colour Stops:           rgba(#78BA00, 1), rgba(#ffffff, 1)
    */
    @include custom_linear-gradient(
        rgba(#78BA00, 1),       //Fallback color
        to right,               //Direction
        rgba(#78BA00, 1),       //IE Filter Start Color
        rgba(#ffffff, 1),       //IE Filter End Color

        //Colour Stops
        rgba(#78BA00, 1), rgba(#ffffff, 1)
    );
}
Radial gradient

Once you have the Mixin and Functions code ready, you can specify a Radial Gradient like this:

//Orange radial gradient
&.orange-radial {
    /*
        Notes:

        Fallback color:         #FF8010 - This fallback colour must be a Hex value.
        Colour Stops:           rgba(#FF8010, 0.7), rgba(#FF8010, 0.72), rgba(#FF8010, 0.74), rgba(#FF8010, 0.85), rgba(#FF8010, 1)
    */
    @include custom_radial-gradient(
        $orange,                //Fallback color - Must be Hex value for IE filter

        //Colour Stops
        rgba(#FF8010, 1), rgba(#FF8010, 0.6), rgba(#FF8010, 0.2), rgba(#FF8010, 0), rgba(#FF8010, 0)
    );
}

 

The full code

Sass Functions:
/*---------------------------------------------------------------------
    Functions for Gradients
---------------------------------------------------------------------*/

    /*
        Convert to IE Hex String (ie-hex-str)
    */
    @function custom_ieHexStr($value) {
        
        //Default variables
        $result: null;
        
        //Convert $value to IE Hex String
        $result: ie-hex-str($value);
        
        //Return the result
        @return $result;
        
    }
    
    
    
    /*
        Convert angle
        @param {Number} $value - Value to convert
        @param {String} $unit - Unit to convert to
        @return {Number} Converted angle
    */
    @function custom_convert-angle($value, $unit) {
        $convertable-units:deg grad turn rad;
        $conversion-factors:1 (10grad/9deg) (1turn/360deg) (3.1415926rad/180deg);

        @if index($convertable-units, unit($value)) and index($convertable-units, $unit) {
            @return $value
            / nth($conversion-factors, index($convertable-units, unit($value)))
            * nth($conversion-factors, index($convertable-units, $unit));
        }

        @warn "Cannot convert `#{unit($value)}` to `#{$unit}`.";
    }



    /*
        Test if `$value` is an angle
        @param {*} $value - Value to test
        @return {Bool}
    */
    @function custom_is-direction($value) {
        $is-direction:index((to top, to top right, to right top, to right, to bottom right, to right bottom, to bottom, to bottom left, to left bottom, to left, to left top, to top left), $value);
        $is-angle:type-of($value) == 'number' and index('deg' 'grad' 'turn' 'rad', unit($value));

        @return $is-direction or $is-angle;
    }



    /*
        Convert a direction to legacy syntax
        @param {Keyword | Angle} $value - Value to convert
        @require {function} custom_is-direction
        @require {function} custom_convert-angle
    */
    @function custom_legacy-direction($value) {
        @if custom_is-direction($value) == false {
            @warn "Cannot convert `#{$value}` to legacy syntax because it doesn't seem to be an angle or a direction";
        }

        $conversion-map: ( 
            to top          : bottom,
            to top right    : bottom left,
            to right top    : left bottom,
            to right        : left,
            to bottom right : top left,
            to right bottom : left top,
            to bottom       : top,
            to bottom left  : top right,
            to left bottom  : right top,
            to left         : right,
            to left top     : right bottom,
            to top left     : bottom right
        );

        @if map-has-key($conversion-map, $value) {
            @return map-get($conversion-map, $value);
        }

        @return 90deg - custom_convert-angle($value, 'deg');
    }
Sass Mixins:
/*---------------------------------------------------------------------
    Mixins for Gradients 
---------------------------------------------------------------------*/

    /*
        Linear Gradient

        Mixin printing a linear-gradient as well as a plain color fallback and the `-webkit-` prefixed declaration
        @param {String} $color-fallback - Fallback color
        @param {String | List | Angle} $direction - Linear gradient direction
        @param {Color} $ie-gradient-color-start - The IE gradient filter start color.
        @param {Color} $ie-gradient-color-end - The IE gradient filter end color.
        @param {Arglist} $color-stops - List of color-stops composing the gradient. Should be in an RGBa format.
    */
    @mixin custom_linear-gradient($color-fallback, $direction, $ie-gradient-color-start, $ie-gradient-color-end, $color-stops...) {
        
        @if custom_is-direction($direction) == false {
            //$color-stops:($direction, $color-stops); - Not required, this causes errors with the IE gradient filters
            $direction:180deg; //Default direction is vertical
        }

        /***** Background colours *****/
            //Fallback colour
            /*
                Disabled as all modern browsers should use 'Vendor Prefixes', or the standard version. IE 8 to IE9 will use the filters. Note: IE9 will used this as it does not support CSS3 'linear-gradients, this is the reason why this has been disabled.
                
                By not enabling this, IE9 will flicker on dropdown tabs with no dropdown menus
            */
            background:$color-fallback;

            //Vendor prefixes
            background:-moz-linear-gradient(custom_legacy-direction($direction), $color-stops);        //FireFox 3.5
            background:-webkit-linear-gradient(custom_legacy-direction($direction), $color-stops);     //Chrome, Safari, newer versions of Opera, almost all iOS browsers (including Firefox for iOS)
            background:-ms-linear-gradient(custom_legacy-direction($direction), $color-stops);         //Internet Explorer 10 to 11

            //All modern browsers
            background: linear-gradient($direction, $color-stops);

        /***** Filters for IE8 and IE9 *****/
            //Colours for the IE filter gradients - Convert to Internet Explorer Hex String
            $ieGradientStartColor: custom_ieHexStr( $ie-gradient-color-start );
            $ieGradientLastColor: custom_ieHexStr( $ie-gradient-color-end );
        
            //No longer used:
                //Find the first colour in the '$color-stops' ArgList
                //$ieGradientStartColor: custom_ieHexStr( nth($color-stops,1) );

                //Find the last colour in the '$color-stops' ArgList
                //$ieGradientLastColor: custom_ieHexStr( nth($color-stops,length($color-stops)) );

            //Filters for IE8 and IE9 - These will be overlayed over 'background'. They will also prevent 'border-radius' corners from appearing
            filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$ieGradientStartColor}, endColorstr=#{$ieGradientLastColor},GradientType=0);
            -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$ieGradientStartColor}, endColorstr=#{$ieGradientLastColor},GradientType=0)";
    }



    /*
        Radial Gradient

        Mixin printing a radial-gradient as well as a plain color fallback
        This will work in most modern browsers and IE11+
        There is some filters setup for IE8 and IE9, they dont produce the best result, but its better than nothing!
        @param {String} $color-fallback - Fallback color
        @param {Arglist} $color-stops - List of color-stops composing the gradient
    */
    @mixin custom_radial-gradient($color-fallback, $color-stops...) {
        background:$color-fallback;                           //Default background, this is used by the IE filter
        //background:nth($color-stops,length($color-stops));  //Not used: Use the last 'color-stop' for the IE filter instead
        
        background:radial-gradient(circle, $color-stops);
        
        //Filters for IE8 and IE9
        filter: progid:DXImageTransform.Microsoft.Alpha(opacity=65, finishopacity=100, style=2);
        -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(opacity=65, finishopacity=100, style=2)";
    }
Sass:
/*---------------------------------------------------------------------
    Sass (SCSS) code
---------------------------------------------------------------------*/

    /* Colours */
    $green:       #78BA00;
    $lightGreen:  lighten($green, 75%);
    
    $blue:        #29B1FE;
    $lightBlue:   lighten($blue, 25%);
    
    $red:         #ea4848;
    $orange:      #FF8010;



    /* Graidents */
    .gradient {
        //On-screen styling
        width: 400px;
        height: 400px;
        margin: 20px;
        float:left;


        //Blue linear gradient
        &.blue-linear {
            /*
                Notes:
                
                Fallback color:         rgba($blue, 1)
                Direction:              false
                IE Filter Start Color:  rgba($blue, 1)
                IE Filter End Color:    rgba($lightBlue, 1)
                Colour Stops:           rgba($blue, 1), rgba($lightBlue, 1)
            */
            @include custom_linear-gradient(
                rgba($blue, 1),         //Fallback color
                false,                  //Direction
                rgba($blue, 1),         //IE Filter Start Color
                rgba($lightBlue, 1),    //IE Filter End Color
                
                //Colour Stops
                rgba($blue, 1), rgba($lightBlue, 1)
            );
        }
        
        
        //Green linear gradient
        &.green-linear {
            /*
                Notes:
                
                Fallback color:         rgba($green, 1)
                Direction:              to right
                IE Filter Start Color:  rgba($green, 1)
                IE Filter End Color:    rgba($lightGreen, 1)
                Colour Stops:           rgba($green, 1), rgba($lightGreen, 1)
            */
            @include custom_linear-gradient(
                rgba($green, 1),        //Fallback color
                to right,               //Direction
                rgba($green, 1),        //IE Filter Start Color
                rgba($lightGreen, 1),   //IE Filter End Color
                
                //Colour Stops
                rgba($green, 1), rgba($lightGreen, 1)
            );
        }


        //Red radial gradient
        &.red-radial {
            /*
                Notes:
                
                Fallback color:         $red - This fallback colour must be a Hex value.
                Colour Stops:           rgba($red, 0.7), rgba($red, 0.72), rgba($red, 0.74), rgba($red, 0.85), rgba($red, 1)
            */
            @include custom_radial-gradient(
                $red,                   //Fallback color - Must be Hex value for IE filter
                
                //Colour Stops
                rgba($red, 0.2), rgba($red, 0.4), rgba($red, 0.74), rgba($red, 0.85), rgba($red, 1)
            );
        }
        
        
        //Orange radial gradient
        &.orange-radial {
            /*
                Notes:
                
                Fallback color:         $orange - This fallback colour must be a Hex value.
                Colour Stops:           rgba($orange, 0.7), rgba($orange, 0.72), rgba($orange, 0.74), rgba($orange, 0.85), rgba($orange, 1)
            */
            @include custom_radial-gradient(
                $orange,                //Fallback color - Must be Hex value for IE filter
                
                //Colour Stops
                rgba($orange, 1), rgba($orange, 0.6), rgba($orange, 0.2), rgba($orange, 0), rgba($orange, 0)
            );
        }
    }
HTML:
<div style="width:880px;margin:25px auto;text-align:center;">

    <div style="display:block;margin-bottom:50px;overflow:hidden;">
        <h1 style="font-family:Arial, Helvetica, sans-serif;font-size:22px;">Linear gradient examples</h1>

        <div class="gradient blue-linear"></div>    <!-- Blue linear -->
        <div class="gradient green-linear"></div>   <!-- Green linear -->
    </div>

    <div style="display:block;margin-bottom:50px;overflow:hidden;">
        <h1 style="font-family:Arial, Helvetica, sans-serif;font-size:22px;">Radial gradient examples</h1>

        <div class="gradient red-radial"></div>     <!-- Red radial -->
        <div class="gradient orange-radial"></div>  <!-- Orange radial -->
    </div>

</div>

Discuss on X (Twitter)