CategoryCSS

Sass mixin for transparent gradient

I’m a big fan of SASS.
Not only just because of the awesome name, but it allows me to use variables and mixins.
This keeps my code DRY.

When I was working on a mixin for creating linear gradients, I kept running in to problems with older (IE) browsers.
My first attempt:

    @mixin linear-gradient($top-color, $bottom-color, $opacity) {
        background: -moz-linear-gradient(top, rgba($top-color, $opacity) 0%, rgba($bottom-color, $opacity) 100%); /* FF3.6-15 */
        background: -webkit-linear-gradient(top, rgba($top-color, $opacity) 0%, rgba($bottom-color, $opacity) 100%); /* Chrome10-25,Safari5.1-6 */
        background: linear-gradient(to bottom, rgba($top-color, $opacity) 0%, rgba($bottom-color, $opacity) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
        filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='rgba($top-color, $opacity)', endColorstr='rgba($top-color, $opacity)',GradientType=0 ); /* IE6-9 */
    }

This resulted in not rendered variable values in the filter property. For some reason they are not compiled by the sass compiler.

My second attempt:

    @mixin linear-gradient($top-color, $bottom-color, $opacity) {
        background: -moz-linear-gradient(top, rgba($top-color, $opacity) 0%, rgba($bottom-color, $opacity) 100%); /* FF3.6-15 */
        background: -webkit-linear-gradient(top, rgba($top-color, $opacity) 0%, rgba($bottom-color, $opacity) 100%); /* Chrome10-25,Safari5.1-6 */
        background: linear-gradient(to bottom, rgba($top-color, $opacity) 0%, rgba($bottom-color, $opacity) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
        filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#{rgba($top-color, $opacity)}', endColorstr='#{rgba($bottom-color, $opacity)}',GradientType=0 ); /* IE6-9 */
    }

This did trigger the sass compiler to render the variable values, but they were rendered as rgb values. IE browsers do not work well with rbga values.
After some google searches I found “ie-hex-str”. This outputs the hex code (with alpha filter) of a color instead of the rbga value.
So this resulted in the following mixin which was working well for me:

    @mixin linear-gradient($top-color, $bottom-color, $opacity) {
        background: -moz-linear-gradient(top, rgba($top-color, $opacity) 0%, rgba($bottom-color, $opacity) 100%); /* FF3.6-15 */
        background: -webkit-linear-gradient(top, rgba($top-color, $opacity) 0%, rgba($bottom-color, $opacity) 100%); /* Chrome10-25,Safari5.1-6 */
        background: linear-gradient(to bottom, rgba($top-color, $opacity) 0%, rgba($bottom-color, $opacity) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
        filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#{ie-hex-str(rgba($top-color, $opacity))}', endColorstr='#{ie-hex-str(rgba($bottom-color, $opacity))}',GradientType=0 ); /* IE6-9 */
    }

The mixin can be used as follows:

    .background-image-overlay {
        @include linear-gradient($black, $white, .5);
    }

Running gulp tasks on a buildserver

With the newest ASP.NET release coming, Microsoft is removing their own optimization framework and pushes developers to use Gulp, NPM and Bower.
I do not want to manually minify and bundle my css and js files, so I want a Gulp task to do it.
My NPM file (package.json) looks like:

{
  "version": "1.0.0",
  "name": "ASP.NET",
  "private": true,
  "devDependencies": {
    "bower": "1.7.7",
    "gulp": "3.9.1",
    ....
  }
}

My bower file (bower.json) looks like

{
  "name": "ASP.NET",
  "private": true,
  "dependencies": {
    "jquery": "2.2.3",
    "jquery-validation-unobtrusive": "3.2.6",
    "bootstrap": "3.3.6",
    ....
  }
}

I also do not want my bundles to be source controlled.
It is a task of the buildserver to prepare my solution for release.
This means that the buildserver should be able to run the same Gulp tasks as we do in our development environment.

The following software should be installed on the buildserver to let the buildserver run Gulp tasks:

When installing Git, set install option to “Run GIT from the Windows Command Prompt”.
I’d like to have all my configuration source controlled, so I create a targets file which contains the targets for running Npm, Gulp and Bower and I import this file in my web project.

  <!-- Gulp -->
  <Target Name="RunGulpTask" AfterTargets="BowerInstall" Condition="'$(RunGulpTasks)' != ''">
    <Message Text="Running gulp task 'default'" Importance="high" />
    <Exec Command="node_modules\.bin\gulp" WorkingDirectory="$(ProjectDir)" />
  </Target>

  <!--Bower -->
  <Target Name="BowerInstall" AfterTargets="NpmInstall" Condition="'$(RunGulpTasks)' != ''">
    <Message Text="Running bower install" Importance="high"/>
    <Exec Command="node_modules\.bin\bower install" WorkingDirectory="$(ProjectDir)" />
  </Target>

  <!--Npm -->
  <Target Name="NpmInstall" BeforeTargets="BeforeBuild" Condition="'$(RunGulpTasks)' != ''">
    <Message Text="Running npm install" Importance="high"/>
    <Exec Command="npm install" WorkingDirectory="$(ProjectDir)" />
  </Target>

I do not want these tasks to run in my development environment (because the TaskRunner of Visual Studio takes care of it), so I added a RunGulpTask parameter. When this is provided (by adding /p:RunGulpTask=true to the msbuild command), the targets will be run before the solution is built.

My gulpfile.js looks like:

var gulp = require('gulp'),
.....
gulp.task('default', ['bundleCss', 'minCss', 'bundleJs', 'minJs'], function() {});

I did not provide a Gulp task to run, so Gulp will run the default task by convention. My default task has a dependency to all tasks I want to be run on the buildserver.
The buildserver now bundles and minifies my css and js files by using the same Gulp tasks.

Automatic Bundling and Minification in .Net

One of the cool new features of .Net 4.5 is the bundling and minification feature. This can save so many requests to your server and saves you many kbs without creating a debug hell. The amount of data is getting more and more important, because of the mobile devices. People pay lots of money on data bundles for their mobile device, we better not waste it. It also decreases loading time!! Reasons enough to start using bundling and minification!

First thing you need to do is download and install the Microsoft ASP.NET Web  Optimization Framework nuget package.

The bundles are registered at application startup. This event is handled in the Application_Start method in the Global.asax. I always try to keep my Global.asax as clean as possible and split all registrations to seperate files in the App_Start folder. So I created a static BundleConfig class in the App_Start folder. This class contains one method, Register with the current Bundles as argument.

BundleConfig.RegisterBundles(BundleTable.Bundles);

BundleConfig

The BundleConfig class registers all JavaScript and Stylesheet bundles, Both Bundles can be added to the same BundleCollection, but both bundles have their own classes. JavaScript bundles are created by using the ScriptBundle class and Stylesheet Bundles are created by using the StyleBundle class.

bundles.Add(new ScriptBundle("~/bundles/jquery").Include("~/Scripts/jquery-{version}.js"));

This creates a JavaScript bundle named “~/bundles/jquery”  and includes one file, “~/Scripts/jquery-{version}.js”.  {version} is automatically resolved to the version of the jquery file in the scripts folder.

bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));

This creates a Stylesheet bundle names “~/content/css”” and contains one file “~/Content/site.css”. Adding more files is easy, just add more files to the include and separate them by a comma.

Adding bundles to a view

The only thing left to do, is adding the bundles to a view.

MVC (Razor)

@Scripts.Render("~/bundles/jquery")

WebForms

<%: Scripts.Render("~/bundles/jquery") %>

The above code renders the JavaScript bundle.

MVC (Razor)

@Styles.Render("~/Content/css")

WebForms

<%: Styles.Render("~/Content/css") %>

The above code renders the Stylesheet bundle.

All the requests to the bundles have a querystring parameter (v=CkVTG71m7lHB5jSCpyOSxbeCVJLIPag7u7NL4ykFenk1). This is to make sure that no old versions of this file are cached and retrieved.

Config files

Bundles can also be configured in config files. This allows you to make changes to your bundle without having to rebuild the project. It also allows frontend developers to easily include, remove or change files in a bundle without having to use visual studio.

An example of a bundle.config file

<?xml version="1.0" encoding="utf-8" ?>
<bundles version="1.0">
  <styleBundle path="~/Content/css">
    <include path="~/Content/Site.css" />
  </styleBundle>
</bundles>

Debugging

One of the biggest problems of minified files is debugging. It’s almost impossible to debug those files.

That’s when the best feature of this minification framework comes in place. When compilation is set to debug (in web.config), the files will not be minified, which makes it a lot easier to debug.

<system.web>
    <compilation debug="true" />
    <!-- Lines removed for clarity. -->
</system.web>

Creating custom bundle transforms

Custom transforms can be created by implementing the IBundleTransform interface.,

using System.Web.Optimization;

public class MyByndleTransform : IBundleTransform
{
   public void Process(BundleContext context, BundleResponse response)
   {
       // Process bundle tranform here
   }
}

The custom transform can now be added to the transform of a bundle

var myBundle = new Bundle("~/My/Files/To/Include");
lessBundle.Transforms.Add(new MyBundleTransform());

This bundle can now be added to the bundles collection in the BundleConfig file.

Why creating custom bundle transforms? Just think of less or coffeescript, or whatever bundle you want.