一、背景介绍:
Retina是一种新型高分辨率的显示标准,是把更多的像素点压缩至一块屏幕里,从而达到更高的分辨率并提高屏幕显示的细腻程度;同时CSS样式表中px单位是一个相对值,并不是绝对值,实际在Retina屏幕中渲染元素的时候,会根据实际的dpr渲染对应的物理像素点,导致CSS代码中1px高度的边框,在实际设备浏览器渲染的时候往往不是1个物理像素高度,可能是2个物理像素高度,甚至是3个物理像素高度,造成设计稿和实际开发的页面显示有出入,影响用户UI体验。
二、现有方案
现有的解决方法大概有两种:
1. 使用1像素高度的背景图片来设置边框
问题点:维护成本比较高,如果变更边框颜色,则需要重新生成新图片。
2. 通过CSS属性border: 0.5px来设置
问题点:存在兼容性问题,在某些设备可能无法识别0.5px,导致元素无法渲染。
三、本方案目的
本方案根据设备参数devicePixelRatio设备像素比,从而精确实现Retina屏幕下1px边框显示问题,同时防止颜色失真。
四、本方案效果
1. 根据不同设备的devicePixelRatio设备像素比,动态调整不同Retina屏幕下1px边框物理像素点高度;
2. 高度还原设计稿,提高用户UI体验。
五、本方案实施方式
1. 在WEB页面DOM元素解析完成后,通过JS获取设备devicePixelRatio参数;
2. 通过JS判断CSS样式前缀;
3. 通过CSS函数linear-gradient()设置边框背景,利用设备参数devicePixelRatio设置起始颜色(边框颜色)的渐变高度比例,将结束颜色设置为透明(transparent);
4. 设置元素backgound-size属性;
上述代码解读:通过JS获取设备参数devicePixelRatio(例如dpr为2,那么实际渲染的物理像素为2*2px,4个像素点,高度为2个像素),利用CSS函数linear-gradient()颜色渐变,设置起始颜色(边框颜色)渐变终点位置(即1/dpr的高度,即为1个像素高度),设置其余背景颜色为透明,同时设置背景颜色的尺寸(background-size)。
附录:
附录(1) 1px实现代码样例
// 获取dom元素var divStyle = document.getElementsByClassName('retina-background-size')[0].style;// 常见css前缀var render = { webkit: 'webkitTransform', moz: 'MozTransform', ms: 'msTransform', o: 'OTransform', dafault: 'transform'};// 判断css前缀类型var getPrefix = (() => { for(let key in render) { if(divStyle[render[key]] !== undefined) { return key; } }})();// 设置css前缀functionfunction stylePrefix() { if(getPrefix === 'dafault') { return ''; } return '-'+getPrefix+'-';};// 获取设备像素比(dpr)var ratio = Math.floor(1 / window.devicePixelRatio * 100) / 100;var endPosition = ratio *100 + '%';divStyle.background = stylePrefix() + 'linear-gradient(bottom, red ' + endPosition + ', transparent ' + endPosition + ') no-repeat center bottom';divStyle.backgroundSize = '100% 1px';
附录(2) 上述代码在2dpr设备生成的元素样式表样例
附录(3) 2dpr设备上实际效果对比图
附录(4) 上述代码在3dpr设备生成的元素样式表样例
附录(5) 3dpr设备上实际效果对比图
附录(6) 名词解释说明
1. ratio是devicePixelRatio设备像素比(物理像素/设备独立像素)保留2位小数后的值。
2. CSS linear-gradient() 函数用于创建一个表示两种或多种颜色线性渐变的图片。其结果属于数据类型,是一种特别的数据类型。
3. Linear-gradient() 函数第一个参数指定渐变的方向或角度,后面的参数指的是渐变的颜色以及颜色起点和终点位置(第一个颜色可以省略起点位置,最后一个颜色可以省略终点位置)。