移动端1px细线解决方案总结

2023-11-11 16:59

本文主要是介绍移动端1px细线解决方案总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

移动端1px变粗的原因

为什么移动端css里面写了1px, 实际看起来比1px粗. 其实原因很好理解:这2个’px’的含义是不一样的. 移动端html的header总会有一句

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

这句话定义了本页面的viewport的宽度为设备宽度,初始缩放值和最大缩放值都为1,并禁止了用户缩放. viewport通俗的讲是浏览器上可用来显示页面的区域, 这个区域是可能比屏幕大的.

根据这篇文章http://www.cnblogs.com/2050/p/3877280.html的分析, 手机存在一个能完美适配的理想viewport, 分辨率相差很大的手机的理想viewport的宽度可能是一样的, 这样做的目的是为了保证同样的css在不同屏幕下的显示效果是一致的, 上面的meta实际上是设置了ideal viewport的宽度.

以实际举例: iphone3和iphone4的屏幕宽度分别是320px,640px, 但是它们的ideal viewport的宽度都是320px, 设置了设备宽度后, 320px宽的元素都能100%的填充满屏幕宽. 不同手机的ideal viewport宽度是不一样的, 常见的有320px, 360px, 384px. iphone系列的这个值在6之前都是320px, 控制viewport的好处就在于一套css可以适配多个机型.

看懂的人应该已经明白 1px变粗的原因了, viewport的设置和屏幕物理分辨率是按比例而不是相同的. 移动端window对象有个devicePixelRatio属性, 它表示设备物理像素和css像素的比例, 在retina屏的iphone手机上, 这个值为2或3, css里写的1px长度映射到物理像素上就有2px或3px那么长.

1px解决方案

1.用小数来写px值

IOS8下已经支持带小数的px值, media query对应devicePixelRatio有个查询值-webkit-min-device-pixel-ratio, css可以写成这样

.border { border: 1px solid #999 }
@media screen and (-webkit-min-device-pixel-ratio: 2),@media screen and (min-device-pixel-ratio: 2){.border { border: 0.5px solid #999 }
}
@media screen and (-webkit-min-device-pixel-ratio: 3),
@media screen and (min-device-pixel-ratio: 3) {.border { border: 0.333333px solid #999 }
}

如果使用less/sass的话只是加了1句mixin

缺点: 安卓与低版本IOS不适用, 这个或许是未来的标准写法, 现在不做指望

2.border-image

<code>这里写图片描述</code>

这样的1张6X6的图片, 9宫格等分填充border-image, 这样元素的4个边框宽度都只有1px

@media screen and (-webkit-min-device-pixel-ratio: 2){ .border{ border: 1px solid transparent;border-image: url(border.gif) 2 repeat;}
}

图片可以用gif, png, base64多种格式, 以上是上下左右四条边框的写法, 需要单一边框只要定义单一边框的border, 代码比较直观.

border-image兼容性:

这里写图片描述

缺点: 对于圆角样式, 将图片放大修改成圆角也能满足需求, 但这样无形中增加了border的宽度,存在多种边框颜色或者更改的时候麻烦

3 background渐变

背景渐变, 渐变在透明色和边框色中间分割, frozenUI用的就是这种方法, 借用它的上边框写法:

@media screen and (-webkit-min-device-pixel-ratio: 2){.ui-border-t {background-position: left top;background-image: -webkit-gradient(linear,left bottom,left top,color-stop(0.5,transparent),color-stop(0.5,#e0e0e0),to(#e0e0e0));}
}

这样更改颜色比border-image方便, 兼容性

这里写图片描述

缺点: 代码量大, 而且需要针对不同边框结构, frozenUI就定义9种基本样式,而且这只是背景, 这样做出来的边框实际是在原本的border空间内部的, 如果元素背景色有变化的样式, 边框线也会消失.最后不能适应圆角样式

4 :before, :after与transform

之前说的frozenUI的圆角边框就是采用这种方式, 构建1个伪元素, 将它的长宽放大到2倍, 边框宽度设置为1px, 再以transform缩放到50%.

.radius-border{position: relative;
}
@media screen and (-webkit-min-device-pixel-ratio: 2){.radius-border:before{content: "";pointer-events: none; /* 防止点击触发 */box-sizing: border-box;position: absolute;width: 200%;height: 200%;left: 0;top: 0;border-radius: 8px;border:1px solid #999;-webkit-transform(scale(0.5));-webkit-transform-origin: 0 0;transform(scale(0.5));transform-origin: 0 0;}
}

需要注意是没有:before, :after伪元素的

优点: 其实不止是圆角, 其他的边框也可以这样做出来

缺点: 代码量也很大, 占据了伪元素, 容易引起冲突

5 flexible.js

这是淘宝移动端采取的方案, github的地址:https://github.com/amfe/lib-flexible. 前面已经说过1px变粗的原因就在于一刀切的设置viewport宽度, 如果能把viewport宽度设置为实际的设备物理宽度, css里的1px不就等于实际1px长了么. flexible.js就是这样干的.

里面的scale值指的是对ideal viewport的缩放, flexible.js检测到IOS机型, 会算出scale = 1/devicePixelRatio, 然后设置viewport

metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');

devicePixelRatio=2时输出meta如下, 这样viewport与ideal viewport的比是0.5, 也就与设备物理像素一致

<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">

另外html元素上的font-size会被设置为屏幕宽的1/10, 这样css可以以rem为基础长度单位进行改写, 比如rem是28px, 原先的7px就是0.25rem. border的宽度能直接写1px.

function refreshRem() {var width = docEl.getBoundingClientRect().width;if (width / dpr > 540) { //大于540px可以不认为是手机屏width = 540 * dpr;}var rem = width / 10; docEl.style.fontSize = rem + 'px';flexible.rem = win.rem = rem;
}

px和rem相互转换的计算方法会暴露在window.lib.flexible中. 这样可以为less/sass编写宏方法. 具体的css改写方法参照大漠的文章http://www.w3cplus.com/mobile/lib-flexible-for-html5-layout.html

项目中特别指出了为了防止字体模糊, 出现奇数字号的字体, 字体的实际单位还是要以px为单位.

缺点: 不适用安卓, flexible内部做了检测 非iOS机型还是采用传统的scale=1.0, 原因在于安卓手机不一定有devicePixelRatio属性, 就算有也不一定能响应scale小于1的viewport缩放设置, 例如我的手机设置了scale=0.33333333, 显示的结果也与scale=1无异.

综合使用

对于IOS, flexible.js处理的已经很好了, 对于Android,方法2,3,4结合起来大体可以满足要求. flexible.js虽然不适用于安卓, 但它里面的这一段代码可以用来做对安卓机的部署.

if (!dpr && !scale) {var isAndroid = win.navigator.appVersion.match(/android/gi);var isIPhone = win.navigator.appVersion.match(/iphone/gi);var devicePixelRatio = win.devicePixelRatio;if (isIPhone) {// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                dpr = 3;} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){dpr = 2;} else {dpr = 1;}} else {// 其他设备下,仍旧使用1倍的方案dpr = 1;}scale = 1 / dpr;
}

这里对安卓做检测, 如果是安卓, js动态加载css.

var link = document.createElement('link');
link.setAttribute("rel","stylesheet");
link.setAttribute("type","text/css");
link.setAttribute("href",".......Android.css");
document.querySelector('head').appendChild(link);

这篇关于移动端1px细线解决方案总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/391527

相关文章

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

Node.js 数据库 CRUD 项目示例详解(完美解决方案)

《Node.js数据库CRUD项目示例详解(完美解决方案)》:本文主要介绍Node.js数据库CRUD项目示例详解(完美解决方案),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考... 目录项目结构1. 初始化项目2. 配置数据库连接 (config/db.js)3. 创建模型 (models/

Vuex Actions多参数传递的解决方案

《VuexActions多参数传递的解决方案》在Vuex中,actions的设计默认只支持单个参数传递,这有时会限制我们的使用场景,下面我将详细介绍几种处理多参数传递的解决方案,从基础到高级,... 目录一、对象封装法(推荐)二、参数解构法三、柯里化函数法四、Payload 工厂函数五、TypeScript

jupyter代码块没有运行图标的解决方案

《jupyter代码块没有运行图标的解决方案》:本文主要介绍jupyter代码块没有运行图标的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录jupyter代码块没有运行图标的解决1.找到Jupyter notebook的系统配置文件2.这时候一般会搜索到

Linux samba共享慢的原因及解决方案

《Linuxsamba共享慢的原因及解决方案》:本文主要介绍Linuxsamba共享慢的原因及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux samba共享慢原因及解决问题表现原因解决办法总结Linandroidux samba共享慢原因及解决

找不到Anaconda prompt终端的原因分析及解决方案

《找不到Anacondaprompt终端的原因分析及解决方案》因为anaconda还没有初始化,在安装anaconda的过程中,有一行是否要添加anaconda到菜单目录中,由于没有勾选,导致没有菜... 目录问题原因问http://www.chinasem.cn题解决安装了 Anaconda 却找不到 An

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

MySQL新增字段后Java实体未更新的潜在问题与解决方案

《MySQL新增字段后Java实体未更新的潜在问题与解决方案》在Java+MySQL的开发中,我们通常使用ORM框架来映射数据库表与Java对象,但有时候,数据库表结构变更(如新增字段)后,开发人员可... 目录引言1. 问题背景:数据库与 Java 实体不同步1.1 常见场景1.2 示例代码2. 不同操作

java常见报错及解决方案总结

《java常见报错及解决方案总结》:本文主要介绍Java编程中常见错误类型及示例,包括语法错误、空指针异常、数组下标越界、类型转换异常、文件未找到异常、除以零异常、非法线程操作异常、方法未定义异常... 目录1. 语法错误 (Syntax Errors)示例 1:解决方案:2. 空指针异常 (NullPoi

使用DrissionPage控制360浏览器的完美解决方案

《使用DrissionPage控制360浏览器的完美解决方案》在网页自动化领域,经常遇到需要保持登录状态、保留Cookie等场景,今天要分享的方案可以完美解决这个问题:使用DrissionPage直接... 目录完整代码引言为什么要使用已有用户数据?核心代码实现1. 导入必要模块2. 关键配置(重点!)3.