JavaScript 颜色梯度和渐变效果

序二(09/11/1)

近来看了Dean的“Convert any colour value to hex in MSIE”,终于解决了根据关键字获取颜色rgb值的问题。
顺便把程序也重新整理一番,并使用了最近整理的工具库

序一(09/03/11)

很久没写blog,太忙了。没什么时间写复杂的东西,重新把颜色渐变效果写一遍。
关于颜色的效果一般就两个,颜色梯度变化和颜色动态渐变,前者在ie中一般用滤镜实现。

效果预览

颜色梯度变化演示:

简单的颜色拾取器(点击修改梯度演示颜色): 

颜色渐变菜单:

Cropper Tween Slider Resize Drag Tooltips

点击随机颜色渐变:

点击随机颜色渐变

程序说明

【ColorGrads颜色梯度】

程序ColorGrads的作用是根据颜色集合和渐变级数生成颜色梯度集合。
渐变级数的意思是分多少步完成渐变。

网页设计中的颜色是用RGB色彩模式呈现的。
在这个模式中每种颜色可以用三个代表红(r)、绿(g)、蓝(b)的颜色值(0到255)来表示。

w3c的Colors部分看到标准中颜色的表示形式包括:
关键字形式:
em { color: red }
RGB形式:
em { color: #f00 }
em { color: #ff0000 }
em { color: rgb(255, 0, 0) }
em { color: rgb(100%, 0%, 0%) }
以上都是表示同一种颜色(红色)。
关键字形式就是用关键字代表颜色值。
而RGB形式,前两种用的比较多,都是一个"#"后面带16进制表示的颜色值,第三种是用十进制的颜色值,第四种是实际值跟255的百分比形式。

各个浏览器对各种颜色表示形式的获取并不相同:

"color: red"形式:
  ie opera ff chrome/safari
style red red #ff0000 red
currentStyle red "red"    
getComputedStyle   #ff0000 rgb(255, 0, 0) rgb(255, 0, 0)
"color: #ff0000"/"color: #f00"形式:
  ie opera ff chrome/safari
style #ff0000/#f00 #ff0000 rgb(255, 0, 0) rgb(255, 0, 0)
currentStyle #ff0000/#f00 #ff0000    
getComputedStyle   #ff0000 rgb(255, 0, 0) rgb(255, 0, 0)
"color: rgb(255, 0, 0)"/"color: rgb(100%, 0%, 0%)"形式:
  ie opera ff chrome/safari
style rgb(255,0,0) #ff0000 rgb(255, 0, 0) rgb(255, 0, 0)
currentStyle rgb(255,0,0) #ff0000    
getComputedStyle   #ff0000 rgb(255, 0, 0) rgb(255, 0, 0)

基本上得到的值还是按标准的形式显示的,只是有些会自动转换形式。
不过ie的rgb形式跟ff/chrome/safari的不同,数值之间并没有空格。
要特别注意的是opera用currentStyle获取关键字形式得到的颜色值是带双引号的,十分奇怪,要尽量避免使用。

要获取两种颜色的渐变梯度,先要把颜色转化成能用来计算的数值。
GetColor和GetData程序就是用来把符合w3c标准表示的颜色值转化成组合该颜色的红(r)、绿(g)、蓝(b)的颜色数值。
RGB形式的值本身就已经带了rgb的具体数值,只要用正则把值提取出来再转化就可以了。
这个过程在GetData中进行:

function GetData(color) {
    var re = RegExp;
    if (/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.test(color)) {
        //#rrggbb
        return $$A.map([ re.$1, re.$2, re.$3 ], function(x){
                return parseInt(x, 16);
            });
    } else if (/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(color)) {
        //#rgb
        return $$A.map([ re.$1, re.$2, re.$3 ], function(x){
                return parseInt(x + x, 16);
            });
    } else if (/^rgb\((.*),(.*),(.*)\)$/i.test(color)) {
        //rgb(n,n,n) or rgb(n%,n%,n%)
        return $$A.map([ re.$1, re.$2, re.$3 ], function(x){
                return x.indexOf("%") > 0 ? parseFloat(x, 10) * 2.55 : x | 0;
            });
    }
}

注意#rrggbb/#rgb形式得到的是16进制的数值字符,把parseInt的第二个参数设为16就可以指定用16进制来处理字符串转换。
对于rgb(n,n,n)/rgb(n%,n%,n%)的形式,直接取得数值,如果有%就根据百分比计算对应数值就行了。
使用这种形式设置颜色时也要注意,
ie6和ie7允许数字百分比混用,其他不可以(包括ie8);
ie6和ie7可以用空格或逗号分隔数值,其他必须用逗号(包括ie8);
当然我们使用时也应该是按照w3c的标准来设置了。
ps:那个DHTML 手册上写的 EM { color: rgb 1.0 0.0 0.0 } 是不能用的,不要被误导了。

如果是关键字形式那就要另外想方法了,可以用一个字典对象来匹配颜色值,但这样程序会变得很庞大。
ps:可以到这里看所有颜色名对应的数值
近来dean发表了“Convert any colour value to hex in MSIE”,终于解决了这个难题。
其中的关键是利用queryCommandValue("ForeColor")来获取颜色值(或许做过编辑器的会比较熟悉)。
queryCommandValue的作用是返回document、range或current selection对于给定命令的当前值。
ForeColor命令是设置或获取文本时的前景色。

具体的做法是先创建一个textarea: 

if (!frag) {
    frag = document.createElement("textarea");
    frag.style.display = "none";
    document.body.insertBefore(frag, document.body.childNodes[0]);
};

ps:由于ie的document.body.appendChild()导致IE已终止操作bug,所以要用insertBefore。

然后设置color为要取值的颜色:

try { frag.style.color = color; } catch(e) { return [0, 0, 0]; }

ps:在ie如果设置错误的颜色值会报错,所以这里用try...catch来保证能返回值。

能使用queryCommandValue方法的对象包括document、range和current selection。
用createTextRange就可以建立一个range:

color = frag.createTextRange().queryCommandValue("ForeColor");

createTextRange可以用在Body,Button,Input和TextArea。
dean是用createPopup().document.body的,好处是不用插入元素到dom。
但createPopup是ie的方法,而TextArea还可以用于getComputedStyle,后面会用到。

这样得到的颜色值是一个数值,这个数字跟颜色的关系是这样的:
例如红色的16进制rgb是ff0000,先转成bgr,即0000ff,然后转成10进制,得到255。
同样粉红色pink是FFC0CB,转成bgr是CBC0FF,10进制是13353215。
ps:使用时要注意,跟一般不同,queryCommandValue("ForeColor")得到的颜色是bgr排列的。

要得到rgb的值可以把转换过程倒过来获取,不过参考dean的文章有更巧妙的方法:

ret = [ color & 0x0000ff, (color & 0x00ff00) >>> 8, (color & 0xff0000) >>> 16 ];

先用与操作(&)把对应位的数值取出来,再用右移运算符(>>>)把数值移到正确的位置上。

例如粉红色FFC0CB要取得绿(g)的颜色值,用与操作(&)取得对应值,FFC0CB & 0x00ff00得到C000,然后右移8个数位得到C0(16进制的一位相当于二进制的4位),即192。

其他支持document.defaultView的可以直接用getComputedStyle获取color。
从上面各个浏览器获取颜色值的结果可知获取的值都是RGB形式的值,所以可以直接用GetData转换:

ret = GetData(document.defaultView.getComputedStyle(frag, null).color);

注意除了ff,如果元素没有插入dom,用getComputedStyle是获取不了color的,所以元素创建时要顺便插入到body中。

在GetStep用GetColor获得颜色值之后,再根据step就可以获得步长了:

var colors = [], start = GetColor(start), end = GetColor(end),
    stepR = (end[0] - start[0]) / step,
    stepG = (end[1] - start[1]) / step,
    stepB = (end[2] - start[2]) / step;

再根据步长生成集合:

for(var i = 0, r = start[0], g = start[1], b = start[2]; i < step; i++){
    colors[i] = [r, g, b]; r += stepR; g += stepG; b += stepB;
}
colors[i] = end;

正确的颜色值是在0到255之间的,而且是不带小数的,需要修正一下:

return $$A.map(colors, function(x){ return $$A.map(x, function(x){
    return Math.min(Math.max(0, Math.floor(x)), 255);
});});

程序支持设置多个颜色的连续变换:

for(var i = 0, n = len - 1; i < n; i++){
    var steps = GetStep( colors[i], colors[i+1], step );
    i < n - 1 && steps.pop();
    ret = ret.concat(steps);
}

要注意的是要去掉各次变换之间重复的颜色组合(steps.pop())。

【ColorTrans颜色渐变】

有了颜色梯度集合,只需要设个定时器把颜色集合的元素依次显示就是一个渐变效果了。
这个渐变有两种效果:颜色渐入(transIn)和颜色渐出(transOut)。
原理就是通过改变_index集合索引属性,渐入时逐渐变大,渐出时逐渐变小:

 transIn: function() {
    this.stop(); this._index++; this._set();
    if(this._index < this._colors.length - 1){
        this._timer = setTimeout($$F.bind( this.transIn, this ), this.speed);
    }
  },
  transOut: function() {
    this.stop(); this._index--; this._set();
    if(this._index > 0){
        this._timer = setTimeout($$F.bind( this.transOut, this ), this.speed);
    }
  },

在_set设置样式程序中修改样式:

var color = this._colors[Math.min(Math.max(0, this._index), this._colors.length - 1)];
this._elem.style[this.style] = "rgb(" + color.join(",") + ")";

其中style属性是要修改的样式属性名,例如颜色是"color",背景色是"backgroundColor"。

由于颜色集合是根据开始颜色、结束颜色和步数生成的,所以如果要修改这些属性必须重新生成过集合。
reset程序就是用来重新生成集合的,同时索引也会设回0:

this._options = options = $$.extend(this._options, options || {});
this._colors = ColorGrads( [options.from, options.to], options.step );
this._index = 0;

程序初始化的时候也会reset一次:

this.reset({
    from: this.options.from || $$D.getStyle(this._elem, this.style),
    to: this.options.to,
    step: Math.abs(this.options.step)
});

如果没有自定义from颜色的话会自动获取当前颜色。

使用技巧

链接标签a的伪类的颜色暂时没有办法直接用dom来修改(除非改class)。
所以在颜色渐变菜单中用了个小技巧,把a的内容和跳转换到td的innerHTML和onclick上实现:

var a = x.getElementsByTagName("a")[0], href = a.href, txt = a.innerHTML;
x.onclick = function(){ location.href = href; }
x.innerHTML = txt;

这样就可以实现效果的同时保持可访问性。

在测试过程中还发现一个数组的问题,运行alert([,,].length),在ie会返回3,其他会返回2。
mozilla的Array_Literals部分查到:
If you include a trailing comma at the end of the list of elements, the comma is ignored. 
即如果数组字面量元素集合的最后是逗号,逗号会被忽略掉。

使用说明

ColorGrads的第一个参数是颜色集合,第二个参数是渐变级数。

ColorTrans只要一个参数,要实现渐变的对象,可设置以下属性:
from: "",//开始颜色
to:  "#000",//结束颜色
step: 20,//渐变级数
speed: 20,//渐变速度
style: "color"//设置属性(Scripting属性)
from默认是空值,方便判断自动获取。
其中from、to和step在实例化后要修改的话需要用reset来设置。
具体使用请参考实例。

程序代码

ColorGrads部分:

var ColorGrads = (function(){
    //获取颜色梯度数据
    function GetStep(start, end, step) {
        var colors = [], start = GetColor(start), end = GetColor(end),
            stepR = (end[0] - start[0]) / step,
            stepG = (end[1] - start[1]) / step,
            stepB = (end[2] - start[2]) / step;
        //生成颜色集合
        for(var i = 0, r = start[0], g = start[1], b = start[2]; i < step; i++){
            colors[i] = [r, g, b]; r += stepR; g += stepG; b += stepB;
        }
        colors[i] = end;
        //修正颜色值
        return $$A.map(colors, function(x){ return $$A.map(x, function(x){
            return Math.min(Math.max(0, Math.floor(x)), 255);
        });});
    }
    //获取颜色数据
    var frag;
    function GetColor(color) {
        var ret = GetData(color);
        if (ret === undefined) {
            if (!frag) {
                frag = document.createElement("textarea");
                frag.style.display = "none";
                document.body.insertBefore(frag, document.body.childNodes[0]);
            };
            try { frag.style.color = color; } catch(e) { return [0, 0, 0]; }//ie opera
            
            if (document.defaultView) {
                //opera #rrggbb
                ret = GetData(document.defaultView.getComputedStyle(frag, null).color);
            } else {
                color = frag.createTextRange().queryCommandValue("ForeColor");
                ret = [ color & 0x0000ff, (color & 0x00ff00) >>> 8, (color & 0xff0000) >>> 16 ];
            }
        }
        return ret;
    }
    //获取颜色数组
    function GetData(color) {
        var re = RegExp;
        if (/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.test(color)) {
            //#rrggbb
            return $$A.map([ re.$1, re.$2, re.$3 ], function(x){
                    return parseInt(x, 16);
                });
        } else if (/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(color)) {
            //#rgb
            return $$A.map([ re.$1, re.$2, re.$3 ], function(x){
                    return parseInt(x + x, 16);
                });
        } else if (/^rgb\((.*),(.*),(.*)\)$/i.test(color)) {
            //rgb(n,n,n) or rgb(n%,n%,n%)
            return $$A.map([ re.$1, re.$2, re.$3 ], function(x){
                    return x.indexOf("%") > 0 ? parseFloat(x, 10) * 2.55 : x | 0;
                });
        }
    }
    
    return function(colors, step){
        var ret = [], len = colors.length;
        if ( step === undefined ) { step = 20; }
        if ( len == 1 ) {
            ret = GetStep( colors[0], colors[0], step );
        } else if ( len > 1 ) {
            for(var i = 0, n = len - 1; i < n; i++){
                var steps = GetStep( colors[i], colors[i+1], step );
                i < n - 1 && steps.pop();
                ret = ret.concat(steps);
            }
        }
        return ret;
    }
})();

ColorTrans部分:

var ColorTrans = function(elem, options){
    
    this._elem = $$(elem);
    this._timer = null;//定时器
    this._index = 0;//索引
    this._colors = [];//颜色集合
    this._options = {};//参数对象
    
    this._setOptions(options);
    
    this.speed = Math.abs(this.options.speed);
    this.style = this.options.style;
    
    this.reset({
        from: this.options.from || $$D.getStyle(this._elem, this.style),
        to: this.options.to,
        step: Math.abs(this.options.step)
    });
    
    this._set();
};
ColorTrans.prototype = {
  //设置默认属性
  _setOptions: function(options) {
    this.options = {//默认值
        from:    "",//开始颜色(默认空值方便自动获取)
        to:        "#000",//结束颜色
        step:    20,//渐变级数
        speed:    20,//渐变速度
        style:    "color"//设置属性(Scripting属性)
    };
    $$.extend(this.options, options || {});
  },
  //重设颜色集合
  reset: function(options) {
    //根据参数设置属性
    this._options = options = $$.extend( this._options, options || {} );
    //获取颜色集合
    this._colors = ColorGrads( [ options.from, options.to ], options.step );
    this._index = 0;
  },
  //颜色渐入
  transIn: function() {
    this.stop(); this._index++; this._set();
    if(this._index < this._colors.length - 1){
        this._timer = setTimeout($$F.bind( this.transIn, this ), this.speed);
    }
  },
  //颜色渐出
  transOut: function() {
    this.stop(); this._index--; this._set();
    if(this._index > 0){
        this._timer = setTimeout($$F.bind( this.transOut, this ), this.speed);
    }
  },
  //颜色设置
  _set: function() {
    var color = this._colors[Math.min(Math.max(0, this._index), this._colors.length - 1)];
    this._elem.style[this.style] = "rgb(" + color.join(",") + ")";
  },
  //停止
  stop: function() {
    clearTimeout(this._timer);
  }
};

本文转自博客园cloudgamer的博客,原文链接:JavaScript 颜色梯度和渐变效果,如需转载请自行联系原博主。

时间: 2024-09-20 05:32:17

JavaScript 颜色梯度和渐变效果的相关文章

JavaScript 颜色梯度和渐变效果第1/3页_javascript技巧

程序说明 [ColorGrads颜色梯度] 程序ColorGrads的作用是通过StartColor和EndColor生成颜色梯度集合. 颜色都可以用红(r).绿(g).蓝(b)三个颜色来表示. 程序中先通过GetColor把一般的颜色表示形式转化成一个用红(r).绿(g).蓝(b)三个颜色值作元素的集合. 那就首先要知道有什么颜色表示形式,从w3c的Colors部分可以知道有以下形式: 关键词模式: em { color: red } RGB颜色模式: em { color: #f00 } e

JS教程:制作颜色梯度和渐变效果

序二(09/11/1)近来看了Dean的"Convert any colour value to hex in MSIE",终于解决了根据关键字获取颜色rgb值的问题.顺便把程序也重新整理一番,并使用了最近整理的工具库. 序一(09/03/11)很久没写blog,太忙了.没什么时间写复杂的东西,重新把颜色渐变效果写一遍.关于颜色的效果一般就两个,颜色梯度变化和颜色动态渐变,前者在ie中一般用滤镜实现. 效果预览: 运行代码框<!DOCTYPE html> <html

Javacript实现颜色梯度变化和渐变的效果代码_javascript技巧

对于本站的导航栏,想做点什么.所以,选择了用js对导航栏的颜色做了梯度的变化处理. 起初,觉得用opacity属性(透明度)来改变颜色的梯度变化.不过,这样会出现一个问题. 每一个导航标签用的是[li],当鼠标浮动到标签上时,通过onmouseover()立即改变[li]的className,并用setInterval()来使其opacity(透明度)由0变到1.不过,当鼠标离开时,对于[li]标签的颜色恢复的处理貌似麻烦了许多.所以,很快就放弃了这个做法,换种思路. 到百度上一搜,看到了一篇很

图像处理------颜色梯度变化 (Color Gradient)

有过UI设计经验的一定对2D图形渲染中的Color Gradient 或多或少有些接触,很多编程 语言也提供了Gradient的接口,但是想知道它是怎么实现的嘛?   本文介绍三种简单的颜色梯度变化算法,就可以很容易实现常见的梯度变化算法 三种都要求提供两个参数即起始颜色RGB值, 最终颜色RGB的值.   垂直梯度颜色变化,效果如下:   水平梯度颜色变化,效果如下:   水平与垂直两个方向叠加梯度变化效果如下:   算法代码及其解释   计算起始颜色和终点颜色RGB之间差值代码如下: flo

.net 信号强度转化为颜色梯度

问题描述 .net 信号强度转化为颜色梯度 最近在做一个将信号,转化为用颜色梯度来表示的功能, 但是却找不.net中关于颜色梯度的控件,请有思路的朋友来我为我解答.

cptutils 1.45发布 颜色梯度处理工具

cptutils 是一款创建和处理颜色梯度的实用工具,主要用于不同格式之间转换.支持的格式包括:ggr (GIMP gradient).cpt GMT color palette table).avl (Arcview Legend).lut (xmedcon).svg 和 grd 3 版本的格式. cptutils 1.45该版本改了SVG的梯度处理.现在svgx方案写入SVG格式,SVG可以预览在文件-p开关的梯度. 软件信息:http://soliton.vm.bytemark.co.uk

cptutils 1.44发布 颜色梯度处理工具

cptutils 是一款创建和处理颜色梯度的实用工具,主要用于不同格式之间转换.支持的格式包括:ggr (GIMP gradient).cpt GMT color palette table).avl (Arcview Legend).lut (xmedcon).svg 和 grd 3 版本的格式. cptutils 1.44该版本添加一个新的包装脚本,梯度转换,从而简化了梯度格式之间的转换. 软件信息:http://soliton.vm.bytemark.co.uk/pub/jjg/en/co

Javascript 颜色渐变效果的实现代码_javascript技巧

下面就是博主的一些思路和解决办法,如果对此没兴趣,想直接使用jquery插件的同学,可以点这里 思路 每一种颜色由RGB组成,每两位为一个16进制数当前颜色代码和目标颜色代码,转换成10进制数后,是有差值的,利用差值,设定总执行次数的步长,计算每一步变更颜色的10进制数利用定时器执行简单的讲,就是将6位颜色代码以每两位转换为10进制数,然后计算两对RGB值的差,根据设定的步长(执行次数),计算每一步需要增加或减少的RGB值,最后变为目标颜色的RGB值 需要解决的问题 将6位颜色代码转换为10进制

10 个很棒的 JavaScript 颜色拾取器插件

MooRainbox JavaScript ColorPicker JPicker – A jQuery Color Picker jPicker 是一个快速.轻量级的 jQuery 插件,提供高级的颜色拾取功能. Color Picker 类似 PhotoShop 的颜色选择器 ExColor jQuery 的颜色选择插件 Izzy Color Picker Flexi Flexi是一个简单.轻量级颜色拾色器,基于SVG/VML技术实现.它没有基于依赖任何JavaScript框架开发,能够将选