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)
至此,換膚功能已完成,咱們能夠看看效果
六、metro風格,這款很乾淨簡潔,我本身很喜歡
6、後述
這樣一來,這個功能就算是很靈活了,就算是之後再加入一款新主題,代碼也徹底不用修改,並且想效果更好點還能夠p幾張題頭的圖片換上。 整體效果固然和專業美工作的固然無法比,不過作作業務管理系統忽悠忽悠客戶已經足夠了。