上部分我们逐一分析了各浏览器的可行方法,这部分将搞鼓出一个统一的类来实现跨浏览器的线性渐变。
先来IE的,这是最大的用户群,如果这部分开发不出来,基本可以说不用做了。IE虽然有Gradient滤镜,但对比其他浏览器的实现特弱,没有多重渐变(stop-color),不能实现角度渐变,而且还经常失效。我的思路是这样,假如有一个带文本的DIV,要实现多重线性渐变,我们首先得把它里面的文本取出来,然后里面放几个DIV,有几重就放几个,然后把它们渐变。如果是垂直渐变,这好办,什么也不用做,只需设置其滤镜与各个高就行了。如果水平,就让其浮动或绝对定位,放到适当的位置,设置其滤镜与宽。但渐变滤镜竟然会在浮动后或定位后失效,这是在使用透明滤镜时闻所未闻的。没有办法,祭出上古神器table。但设置长与宽时,使用style来设置是不顶用的,一定要用DOM属性。渐变则由它的td元素负责。为了去除table元素与td元素之间,td元素与其内容之间的空白,我们还得用到cellPadding与cellSpacing。
//④使用IE滤镜实现渐变 function setFilter(el,start,end,type){ el.style.filter = "progid:DXImageTransform.Microsoft.Gradient(enabled='true',startColorstr="+start+",GradientType="+type+", endColorstr="+end+")"; } //③每个渐变体的实现,是用table还是div function createStop(parent,top,left,width,height,type){ if(type){ var table = document.createElement("table"); parent.appendChild(table); var tr = table.insertRow(0), td = tr.insertCell(0) table.height = height+"px"; table.width = width+"px"; table.cellPadding = 0; table.cellSpacing = 0; table.style.cssText = "position:absolute;top:"+top+"px;left:"+left+"px" td.innerHTML =" "; return td; } var div = document.createElement("div"); parent.appendChild(div); div.style.height = height+"px"; div.style.width = width+"px"; return div; } //②渐变的具体实现,确定要使用多少渐变体,每个渐变体的颜色(是渐变色还是纯色)与长宽坐标 var IEgradient = function(entity,stops,width,height,type){ var offset,color,beforeColor,stopWidth,stopHeight,left,top,stop; for(var i=0,j=0,l=stops.length;i<l;i++,j++){ offset = stops[i].split(",")[0]; color = stops[i].split(",")[1]; stopWidth = (offset/100 * width).toFixed(1); stopHeight = (offset/100 * height).toFixed(1); switch(i){ case 0 : beforeColor = color; left = stopWidth; top = stopHeight; if(offset != 0){ //插入一个纯色的table stop = type? createStop(entity,0,0,stopWidth,height,type) : createStop(entity,0,0,width,stopHeight,type); stop.style.backgroundColor = color; } break; case l-1: //先插入一个渐变的table var w2 = ((100-offset)/100 * width).toFixed(1), h2 = ((100-offset)/100 * height).toFixed(1), stop = type? createStop(entity,0,left,width - left -w2,height,type): createStop(entity,0,0,width,height - top -h2,type); setFilter(stop,beforeColor,color,type); if(offset != 100){ //再插入一个纯色的table var stop2 = type? createStop(entity,0,stopWidth,w2,height,type): createStop(entity,0,0,width,h2,type); stop2.style.backgroundColor = color; } break; default : //插入一个渐变的table stop = type ? createStop(entity,0,left,stopWidth - left,height,type) : createStop(entity,0,0,width,stopHeight-top,type); setFilter(stop,beforeColor,color,type); beforeColor = color; left = stopWidth; top = stopHeight; break; } } } //①渐变的主体函数 var gradient = function(id){ var entity = document.getElementById(id), options = arguments[1] || {}, width = options.width, height = options.height, type = options.type , stops = options["color-stop"]; entity.style.position = "relative"; var content = entity.innerHTML; entity.innerHTML = ""; //向目标对象进行渐变。 IEgradient(entity,stops,width,height,type); //把原来的内容重新加入的目标对象。 var contentDiv = document.createElement("div"); contentDiv.style.cssText = "position:absolute;top:0;left:0"; contentDiv.innerHTML = content; entity.appendChild(contentDiv); }
safari,chrome与opera打算都用SVG实现。为了减少函数的长度,特意搞了两个辅助函数。
var createSVG = function(tag){ return document.createElementNS("http://www.w3.org/2000/svg",tag); }; var attr= function(node,bag){ for(var i in bag){ if(bag.hasOwnProperty(i)) node.setAttribute(i,bag[i]) } }; var COSgradient = function(entity,stops,width,height,type){ var svg = createSVG("svg"); attr(svg,{width:width+"px",height:height+"px"}) entity.appendChild(svg); var defs = createSVG("defs"); svg.appendChild(defs); var linearGradient = createSVG("linearGradient"); defs.appendChild(linearGradient); attr(linearGradient,{id:"nasami",x1:"0%",y1:"0%"}) if(type){ attr(linearGradient,{x2:"100%",y2:"0%"}) }else{ attr(linearGradient,{x2:"0%",y2:"100%"}) } for(var i=0,j=0,l=stops.length;i<l;i++,j++){ var offset = stops[i].split(",")[0] + "%", color = stops[i].split(",")[1], stop = createSVG("stop"); attr(stop,{offset:offset,"stop-color":color}); linearGradient.appendChild(stop); } var rect = createSVG("rect"); svg.appendChild(rect); attr(rect,{x:"0px",y:"0px",width:width+"px",height:height+"px",fill:"url(#nasami)"}); }
firefox则利用其私有属性:
var FFgradient= function(entity,stops,width,height,type){ var cssText = ";background: -moz-linear-gradient(" cssText += type? "top,bottom," :"left,right,"; for(var i=0,j=0,l=stops.length;i<l;i++,j++){ var offset = stops[i].split(",")[0] + "%", color = stops[i].split(",")[1]; cssText += "color-stop("+[offset,color]+")," } cssText = cssText.replace(/,$/,"")+") no-repeat;"; entity.style.cssText = cssText+"width:"+width+"px;height:"+height+"px;" }
不过今天研磨一下,发现firefox还是支持SVG的线性渐变的,因此纠正我原来的观点。上面的函数只是作用一种实现手段放在这里,它并没有整合到我最终的版本中(虽然它比SVG实现短很多。)这样一来,在老一点版本的firefox中我们也能实现线性渐变了。
下面这个运行框里的渐变效果可在所有主流浏览器中正常运作。
再把它做成类。扼要说明一下:它的第一个参数为IE,第二个为哈希。哈希中的各参数都为必选的,width,height的单位为px;type为0或者1,0代表垂直,1为水平;color-stop代表渐变体,由一个字符串数组构成,每个字符串都是由数字加逗号加颜色值组成,数字表代偏移量,单位为%,颜色值可以是red,green等名词,也可以是六位或三位的哈希值。渐变体至少要有一个。
new Gradient("gradient",{width:800,height:100,type:0,"color-stop":["0,red", "16,orange","32,yellow","48,green","64,blue","80,indigo","100,violet"]})