利用CSS預處理技術實現項目換膚功能(less css + asp.net mvc4.0 bundle)

1、背景css

    在愈來愈重視用戶體驗的今天,換膚功能也慢慢被重視起來。一個web系統用戶能夠選擇一個本身喜歡的系統主題,在用戶眼裏仍是會多少加點分的。咱們很開心的是easyui v1.3.4有自帶default gray black bootstrap metro五款皮膚,可是它並不像bootsrap提供了很完整的css框架,不能提供項目須要的全部的css,因此還須要本身編寫控件以外的一些css。給系統換膚時,easyui控件都沒問題,問題就在於本身編寫的這部分css怎麼實現換膚,固然,最簡單的辦法就是爲每一款主題都寫對應的一份自定義css而後在項目中加載,這樣是能夠實現。
    可是我以爲這樣有點羅嗦了,當你添加新的css或修改css時,你要同時修改N份css,每個主題對應一份,並且easyui除了這5款默認的主題還有其它主題或者咱們還能夠自定義主題,那這樣修改css就更不現實了。因此咱們就想到的動態css,也就是css預處理技術。前端

2、CSS預處理技術java

CSS 預處理器技術已經很是的成熟,經常使用的預處理器框架有:
一、Less 官網:http://lesscss.org/
二、Sass 官網:http://sass-lang.com/
三、Stylus 官網:http://learnboost.github.io/stylus/git

我研究比較多的只有less,後二者也只是瞭解了下,因此這裏我仍是選用less來實現github

咱們先來看看用less帶來了哪些方便
一、用Less咱們能夠實現用變量去寫css,能夠很方便的實現換膚功能(只要改變變量的值便可)web

@the-border: 1px;
@base-color: #111;
@red:        #842210;

#header {
  color: (@base-color * 3);
  border-left: @the-border;
  border-right: (@the-border * 2);
}
#footer {
  color: (@base-color + #003300);
  border-color: desaturate(@red, 10%);
}

二、Less提供了不少頗有用的函數好比lighten darken fadein fadeout…等等,好比把字體A顏色設置爲#1382CE,字體B跟A同一顏色,只是比較淡:bootstrap

@fontcolor:#1382CE;
.font1 {
    color: @fontcolor;
}
.font2 {
    color: lighten(@fontcolor,30%);
}

三、咱們也能夠本身定義本身的less函數,好比咱們寫一個背景漸變的css,咱們能夠定義一個漸變的函數,以下:緩存

.gradient(@color: #F5F5F5, @start: #EEE, @stop: #FFF) {
  background: @color;
  background: -webkit-gradient(linear,
                               left bottom,
                               left top,
                               color-stop(0, @start),
                               color-stop(1, @stop));
  background: -ms-linear-gradient(bottom,
                                  @start,
                                  @stop);
  background: -moz-linear-gradient(center bottom,
                                   @start 0%,
                                   @stop 100%);
  background: -o-linear-gradient(@stop,
                                 @start);
  filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",@stop,@start));
}

而後咱們只須要這樣用:sass

.head-north
{
    .gradient(colorDefault,colorFrom, colorTo);
}

我就簡單介紹這些,less還有不少用法,你們本身去探究。服務器

3、系統換膚實現思路

固然不光是引入less就完了,事情遠沒有這麼簡單,咱們知道既然是dynamic css那麼必定是須要編譯的,less最終也是隻是編譯生成css代碼,那麼就有一個問題,何時編譯
一、使用編譯工具好比koala、SimpleLess等,在項目發佈前編譯好放在項目中
二、前端解析編譯,須要在項目中引入less.js
三、後臺動態解析,在java環境下的編譯引擎比較多,.net下好像我就找到一個dotless,並且實現的還不是很完整,只能說是less v1.5的部分實現。

先分析下這三種方式,第一種用編譯工具,就是我發佈項目要作的事情變多了,我一貫比較懶,喜歡簡單的,萬一我忘記了怎麼辦,總以爲是多了一趟事情。
第二種前端實時解析,這種實際上是很理想的一種方便,也很方便,可是帶來的一個問題就是前端的效率,若是css少還好說,多了確定會影響效率的。
第三種呢,後臺動態編譯,後臺只編譯一次後緩存起來,對服務器基本沒有影響,這樣很好,問題是我這個框架是.net的,是dotless實現不完整,可是咱們不必定會用到less全部的功能,有基本功能就夠用了,好比條件判斷等更高級的使用,咱們能夠在處理前本身先預處理一下,再給less類庫去解析。

好吧,那麼我就選擇第三種在後臺動態解析了。
具體思路:
一、根據當前用戶選擇的theme取得easyui.css文件並根據特徵得到主題的相關變量@body-background-color或@body-text-color等等,這些變量我在我自定義的css中會經常使用到,取得這些變量是很容易作到的。
二、利用這些變量,咱們能夠theme.less中編寫自定義的css
三、利用asp.net mvc4.0中的bundle中來處理less
四、頁面引用輸出css

4、具體實現

一、引入dotless類庫
二、定義easyui中的變量,應該包括如下變量

/*common*/
@border-color
@border-radius
@font-size
@shadow-background-color
@mask-background-color
@toolbar-background-color
@toolbar-border-color
@split-color
@split-proxy-color

/*Header*/
@header-background-color
@header-text-color
@header-gradient-used
@header-gradient-from
@header-gradient-to

/*body*/
@body-background-color
@body-text-color

/*grid*/
@grid-header-background-color
@grid-header-gradient-from
@grid-header-gradient-to
@cell-border-color
@alt-background-color

/*state*/
@selected-background-color
@selected-text-color
@selected-border-color
@hover-background-color
@hover-text-color
@hover-border-color
@invalid-background-color
@invalid-border-color
@invalid-text-color

/*menu*/
@menu-background-color
@menu-text-color
@menu-border-color

/*button*/
@button-background-color
@button-selected-color
@button-text-color
@button-gradient-used
@button-gradient-from
@button-gradient-to
@button-radius
@button-split-color1
@button-split-color2

這些變量要經過用戶的theme取得easyui.css文件並解析這個文件去給這些less變量賦值

三、自定義本身的動態css,下面是個人項目中theme.less文件的片斷

.z-body
{
    background:@body-background-color;
}

.z-toolbar,.z-toolbar-dialog{
    border-color:@border-color;
    background:@header-background-color;
}

.z-txt {
    border-color:@border-color;
    background:white;
}
.head-left, .head-right, .head-right a
{ color: $when(@theme=gray,default,black,bootstrap| #fff | #000); } .head-north {
    .gradient(@selected-background-color,@header-background-color, @selected-background-color);
}

.head-south,.head-south a
{
    background:@header-background-color;
    color: lighten(@body-text-color,30%);
}
 
……

四、在項目中的BundleConfig.cs中的RegisterBundles中註冊bundles

using System;
using System.IO;
using System.Web;
using System.Web.Hosting;
using System.Web.Mvc;
using System.Web.Optimization;
using Zephyr.Utils;

namespace Zephyr.Web.Mvc
{
    public class BundleConfig
    {
        public static void RegisterBundles(BundleCollection bundles)
        {
            var dirBase = new DirectoryInfo(HttpContext.Current.Server.MapPath(
                string.Format("~/Content/js/easyui/{0}/themes",AppSettings.EasyuiVersion)));
            var dirs = dirBase.GetDirectories();
            foreach (var dir in dirs)
            {
                if (dir.Name == "icons") continue;
                var theme = dir.Name;
                var themeBundle = new Bundle(string.Format("~/Content/css/theme/{0}", theme)).Include(
                    "~/Content/css/less/elements.less", 
                    "~/Content/css/less/theme.less");
                themeBundle.Transforms.Add(new EasyuiLessTransform(theme));
                themeBundle.Transforms.Add(new LessTransform());
                themeBundle.Transforms.Add(new CssMinify());
                bundles.Add(themeBundle);
            }
        }
    }
}

這裏在bundle的Transforms中添加了三個BundleTransform處理,
其中EasyuiLessTransform是我對easyui變量及自定義條件判斷$when的處理
LessTransform則是調用dotless庫解析less代碼

using System;
using System.Web.Optimization;
using dotless.Core;

namespace Zephyr.Web.Mvc
{
    public class LessTransform : IBundleTransform
    {
        public void Process(BundleContext context, BundleResponse response)
        {
            var compiled = Less.Parse(response.Content);
            if (string.IsNullOrEmpty(compiled))
                throw new Exception("less文件中語法有錯誤!");
            response.Content = compiled;
            response.ContentType = "text/css";
        }
    }
}

第三個CssMinify則是System.Web.Optimization下面的對css混淆壓縮處理。

五、在頁面中引用,razor頁面中只須要如下代碼便可

@Styles.Render("~/Content/css/theme/" + AppLoginer.Theme)

至此,換膚功能已完成,咱們能夠看看效果

5、各類主題下的效果
一、默認主題
image

image

二、gray風格image

image

三、bootstrap風格
image

image

四、black風格,這個好像口味比較重
image

image

六、metro風格,這款很乾淨簡潔,我本身很喜歡

image

image

6、後述

這樣一來,這個功能就算是很靈活了,就算是之後再加入一款新主題,代碼也徹底不用修改,並且想效果更好點還能夠p幾張題頭的圖片換上。 整體效果固然和專業美工作的固然無法比,不過作作業務管理系統忽悠忽悠客戶已經足夠了。

相關文章
相關標籤/搜索