一、背景

在越来越重视用户体验的今天,换肤功能也慢慢被重视起来。一个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预处理技术。

二、CSS预处理技术

CSS 预处理器技术已经非常的成熟,常用的预处理器框架有:
1、Less 官网:http://lesscss.org/
2、Sass 官网:http://sass-lang.com/
3、Stylus 官网:http://learnboost.github.io/stylus/

我研究比较多的只有less,后两者也只是了解了下,所以这里我还是选用less来实现

我们先来看看用less带来了哪些方便
1、用Less我们可以实现用变量去写css,可以很方便的实现换肤功能(只要改变变量的值即可)

@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%);
}

2、Less提供了很多很有用的函数比如lighten darken fadein fadeout…等等,比如把字体A颜色设置为#1382CE,字体B跟A同一颜色,只是比较淡:

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

3、我们也可以自己定义自己的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));
}

然后我们只需要这样用:

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

我就简单介绍这些,less还有很多用法,大家自己去探究。

三、系统换肤实现思路

当然不光是引入less就完了,事情远没有这么简单,我们知道既然是dynamic css那么一定是需要编译的,less最终也是只是编译生成css代码,那么就有一个问题,什么时候编译
1、使用编译工具比如koala、SimpleLess等,在项目发布前编译好放在项目中

2、前端解析编译,需要在项目中引入less.js

3、后台动态解析,在java环境下的编译引擎比较多,.net下好像我就找到一个dotless,而且实现的还不是很完整,只能说是less v1.5的部分实现。

先分析下这三种方式,第一种用编译工具,就是我发布项目要做的事情变多了,我一向比较懒,喜欢简单的,万一我忘记了怎么办,总觉得是多了一趟事情。

第二种前端实时解析,这种其实是很理想的一种方便,也很方便,但是带来的一个问题就是前端的效率,如果css少还好说,多了肯定会影响效率的。

第三种呢,后台动态编译,后台只编译一次后缓存起来,对服务器基本没有影响,这样很好,问题是我这个框架是.net的,是dotless实现不完整,但是我们不一定会用到less所有的功能,有基本功能就够用了,比如条件判断等更高级的使用,我们可以在处理前自己先预处理一下,再给less类库去解析。

好吧,那么我就选择第三种在后台动态解析了。

具体思路:

1、根据当前用户选择的theme取得easyui.css文件并根据特征获得主题的相关变量@body-background-color或@body-text-color等等,这些变量我在我自定义的css中会常用到,取得这些变量是很容易做到的。

2、利用这些变量,我们可以theme.less中编写自定义的css

3、利用asp.net mvc4.0中的bundle中来处理less

4、页面引用输出css

四、具体实现

1、引入dotless类库

2、定义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变量赋值

3、自定义自己的动态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%);
}
 
……

4、在项目中的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混淆压缩处理。

5、在页面中引用,razor页面中只需要以下代码即可

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

至此,换肤功能已完成,我们可以看看效果

五、各种主题下的效果
1、默认主题

2、gray风格

3、bootstrap风格

4、black风格,这个好像口味比较重

6、metro风格,这款很干净简洁,我自己很喜欢

六、后述

这样一来,这个功能就算是很灵活了,就算是以后再加入一款新主题,代码也完全不用修改,而且想效果更好点还可以p几张题头的图片换上。

总体效果当然和专业美工做的当然没法比,不过做做业务管理系统忽悠忽悠客户已经足够了。

利用CSS预处理技术实现项目换肤功能(less css + asp.net mvc4.0 bundle)的更多相关文章

  1. 使用 css/less 动态更换主题色(换肤功能)

    前言 说起换肤功能,前端肯定不陌生,其实就是颜色值的更换,实现方式有很多,也各有优缺点 一.看需求是什么 一般来说换肤的需求分为两种: 1. 一种是几种可供选择的颜色/主题样式,进行选择切换,这种可供 ...

  2. 【转】Javascript+css 实现网页换肤功能

    来源:http://www.php100.com/html/webkaifa/DIV_CSS/2008/1014/2326.html Html代码部分: 1.要有一个带id的样式表链接,我们要通过操作 ...

  3. 基于webpack4+vue-cli3项目的换肤功能

    起因 最近因公司需求,需要实现主题换肤功能,不仅仅是颜色的更改,还需要包括图片,字体等文件等更换,因此在百度里各种实现方案后,决定根据scss+style-loader/useable做换肤. 项目开 ...

  4. .NET vs2010中使用IrisSkin2.dll轻松实现winForm窗体换肤功能

    IrisSkin2.dll是一款很不错的免费皮肤控件,利用它可以轻松的实现winForm窗体换肤! 网上很多朋友说在VS2010中不能使用IrisSkin2.dll,我这里提供一个取巧的办法. Iri ...

  5. 用js来实现页面的换肤功能(带cookie记忆)

    用js来实现页面的换肤功能 js实现换肤功能的实现主要是通过利用js控制CSS来实现的.大致的实现原理是这样的, 1.先定义一个页面基本样式style.css来确定div的宽高等属性,使得整个页面的D ...

  6. 换肤功能的实现以及监听storage实现多个标签页一起换肤

    1:需求:项目的侧边栏实现换肤功能,核心代码: updateSkin (val) { const existSkinLink = document.head.querySelector('link[i ...

  7. 一种简单的实现:Android一键换肤功能

    现在的APP开发,通常会提供APP的换肤功能,网上流传的换肤代码和实现手段过于复杂,我把原作者的代码重新整理抽取出来,转换成Eclipse项目,重新整理成正确.可直接运行的项目. 代码运行结果如图. ...

  8. Android 换肤功能的实现(Apk插件方式)

    一.概述 由于Android 没有提供一套统一的换肤机制,我猜可能是因为国外更注重功能和体验的原因 所以国内如果要做一个漂亮的换肤方案,需要自己去实现. 目前换肤的方法大概有三种方案: (1)把皮肤资 ...

  9. JS实现网页换肤功能效果

    网页换肤的基本原理 使用 JS 切换对应的 CSS 样式表.例如hao123首页的右上方就有网页换肤功能.除了切换 CSS 样式表文件之外,通常的网页换肤还需要通过 Cookie 来记录用户之前更换过 ...

随机推荐

  1. ORACLE关于索引是否需要定期重建争论的整理

    ORACLE数据库中的索引到底要不要定期重建呢? 如果不需要定期重建,那么理由是什么? 如果需要定期重建,那么理由又是什么?另外,如果需要定期重建,那么满足那些条件的索引才需要重建呢?关于这个问题,网 ...

  2. ORACLE SQL调优案例一则

    收到监控告警日志文件(Alert)的作业发出的告警邮件,表空间TEMPSCM2不能扩展临时段,说明临时表空间已经被用完了,TEMPSCM2表空间不够用了 Dear All:   The Instanc ...

  3. MongoDB 常用故障排查工具

    1.profile profiling levels: 0,关闭profile:1,只抓取slow查询:2,抓取所有数据. 启动profile并且设置Profile级别: 可以通过mongo shel ...

  4. 最近用Timer踩了一个坑,分享一下避免别人继续踩

    最近做一个小项目,项目中有一个定时服务,需要向对方定时发送数据,时间间隔是1.5s,然后就想到了用C#的Timer类,我们知道Timer 确实非常好用,因为里面有非常人性化的start和stop功能, ...

  5. java自定义Annotation(载自百度文库)

    java中自定义annotation需要@interface关键字和用到几个内置annotation. 用到的注解有@Target,@Retention,@Documented,@Inherited  ...

  6. golang和vim-go安装配置

    一.Golang安装 1.下载golang安装包http://golangtc.com/download,我这里下载的是go1.6rc2.linux-amd64.tar.gz. 2.解压到安装目录,我 ...

  7. PHP&MySQL(三)——数组

    前一段忙着比赛忙着找实习,最后一地鸡毛,就是长长教训罢了.... 看书还是多必须的,试着高效的.踏实的做吧!! <?php //PHP数组其实能创建很多种数据结构,列表,堆栈,队列,树等 //数 ...

  8. POJ2743Mobile Computing[DFS 状态压缩]

    Mobile Computing Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 666   Accepted: 224   ...

  9. Codeforces 549G Happy Line[问题转换 sort]

    G. Happy Line time limit per test 1 second memory limit per test 256 megabytes input standard input ...

  10. ural One-two, One-two 2

     One-two, One-two 2 Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u ...