一条1px的行线 html,移动端H5页面中1px边框的几种解决方法

本文主要是介绍一条1px的行线 html,移动端H5页面中1px边框的几种解决方法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

问题提出

这是一个比较老的问题了,我第一次注意到的时候,是UI设计师来找我麻烦,emmm那时候我才初入前端职场,啥也不懂啊啊啊啊啊,情形是这样的:

设计师拿着手机过来:这些边框都粗了啊,我的设计稿上是1px的

我:????我写的是1px呀,不信你看。(说着拿出了css代码

设计师:不对啊我眼睛看来这个边框比我设计稿上粗很多,看起来好奇怪(emmm果然像素眼

我:那我把它改成0.5px你看看(边说边改了代码

设计师一看,点点头,果然好很多。

后来发现同样的代码在某些安卓机上是有问题的,会导致0.5px的线看不见。

奇了怪了,显然改成0.5px不能解决问题,但是确实1px边框看上去比设计稿上要粗很多,原因何在?

1px边框的表现

我直接使用css去定1px的边框,

html:

  • 1
  • 2

css:

* {

margin: 0;

padding: 0;

}

ul, li{

list-style: none;

}

.hairlines {

width: 300px;

margin: 100px auto;

}

.hairlines li{

position: relative;

margin-top: 10px;

border-bottom: 1px solid #cccccc; // 边框设置成1px

}

得到的截图如下:

bVbeaBy?w=720&h=1280

看上去是比设计稿上要粗很多,设计稿上的应该是下面这样的,大家可以比对一下:

bVbeaEz?w=720&h=1280

解决方法一:伪类+transform

抱着解决问题的心理,虽然当时也没有想清楚原因在哪,但是还是找到了相关的解决方法,其中一些方法中提到使用边框图片border-image或者box-shadow,也可以模拟出想要的1px边框效果,但是我个人觉得不通用,也不是常规解决方法。

最终选择的是使用伪类+transform方法:原理是把原先元素的 border 去掉,然后利用 :before 或者 :after 重做 border ,并 transform 的 scale 缩小一半,原先的元素相对定位,新做的 border 绝对定位。

html同上

css如下:

* {

margin: 0;

padding: 0;

}

ul, li{

list-style: none;

}

.hairlines {

width: 300px;

margin: 100px auto;

}

.hairlines li{

position: relative;

border:none;

margin-top: 10px;

}

.hairlines li:after{

content: '';

position: absolute;

left: 0;

bottom: 0;

background: #cccccc;

width: 100%;

height: 1px;

-webkit-transform: scaleY(0.5);

transform: scaleY(0.5);

-webkit-transform-origin: 0 0;

transform-origin: 0 0;

}

这样的话,画出的线确实细很多,我在之后长达一年的时间里面一般都是使用上面的方法去解决1px边框的问题,但用着用着,我发现了几个问题:

1.为什么是scaleY(0.5)?这个0.5是怎么得出的?是不是所有机型都是要scale缩小到一半,换句话说是不是通用?

2.如果我要同时画一个容器的四个边框怎么办?

3.支不支持圆角边框?

后两个问题改造一下上面的代码,可以找到解决方法(为了方便查看效果,我把平时写法得出的效果和使用伪类得出的效果放一起,这样更容易看出差别):

移动端1px边框问题

* {

margin: 0;

padding: 0;

}

ul, li{

list-style: none;

}

.lines {

width: 200px;

margin: 0 auto;

}

.lines li {

border: 1px solid #cccccc;

height: 50px;

line-height: 50px;

text-align: center;

border-radius: 13px;

margin-top: 10px;

}

.hairlines {

width: 200px;

margin: 0 auto;

border-radius: 3px;

}

.hairlines li{

height: 50px;

line-height: 50px;

border:none;

text-align: center;

position: relative;

margin-top: 10px;

}

.hairlines li:after{

content: '';

position: absolute;

left: 0;

top: 0;

border: 1px solid #cccccc;

border-radius: 26px;

width: 200%;

height: 200%;

-webkit-transform: scale(0.5);

transform: scale(0.5);

-webkit-transform-origin: left top;

transform-origin: left top;

}

粗线

  • 1
  • 2

细线

  • 3
  • 4

这样得出的效果图如下:

bVbebyW?w=720&h=1280

下面的边框明显细很多,更贴近于设计稿。

那么“1.为什么是scaleY(0.5)?这个0.5是怎么得出的?是不是所有机型都是要scale缩小到一半,换句话说是不是通用?”这个问题该怎么回答呢?

这就要回到问题的本质,为什么我明明在css里面写了1px,但是仍然会出现“看起来比平时要粗很多的效果”?

查了资料看了下,原来css中设置的像素并不是跟设备的像素点一一对应,这就是说,我在css中写明1px,实际在手机上,看到的有可能并不是一个像素点占据的宽度。

css的像素是一个抽象的相对的概念,在不同的设备和环境中,所表示的物理像素点是不一样的,在比较老的设备上,屏幕像素密度比较低,这样,确实一个1px的像素就是一个物理像素,但是技术飞速发展,现在的手机屏幕都是高分辨率,在尺寸未变化的情况下,一个屏幕上将充满着更多的像素点,这时一个css的像素(通常称为逻辑像素)将对应多个物理像素点。

那到底一个css的像素宽度上对应多少个物理像素点呢?

这就要提到devicePixelRatio(设备像素比)

devicePixelRatio = 设备上物理像素/独立像素,可以通过window.devicePixelRatio获取,这个像素比恰好可以描述一个css的像素宽度上对应多少个物理像素点,其实就是对应devicePixelRatio个像素点。

当viewport的属性initial-scale为1时,页面大小正常,但initial-scale为0.5时,页面被缩小了1倍,devicePixelRatio为2的设备本来1个CSS像素宽度占2个物理像素宽度,缩小后的1个CSS像素宽度就只占1个物理像素,即实现了真正的1物理像素。

解决方法二:rem + viewport

说到这里,解决方法就很明了了:我们可以在运行的时候拿到设备的devicePixelRatio,动态改变viewport的initial-scale为 1/devicePixelRatio,这样就能保证1px的宽度就是真正的1物理像素宽。其他适配使用rem(因为使用px的话都会被缩小)

代码如下:

移动端1px边框问题

(function () {

var clientWidth = window.screen.width;

var dpr = window.devicePixelRatio;

var vp = document.createElement('meta');

document.documentElement.style.fontSize = clientWidth > 414 ? '20px' : 20 * dpr * clientWidth / 360 + 'px';

vp.name = 'viewport';

vp.content = `initial-scale=${1.0 * 1 / dpr}, maximum-scale=${1.0 * 1 / dpr}, minimum-scale=${1.0 * 1 / dpr}, user-scalable=no, width=device-width`;

var m = document.getElementsByTagName('meta')[0];

m.parentNode.insertBefore(vp, m);

})();

* {

margin: 0;

padding: 0;

}

ul, li{

list-style: none;

}

.lines {

width: 10rem;

margin: 0 auto;

}

.lines li {

border: 1px solid #cccccc;

height: 2.5rem;

line-height: 2.5rem;

text-align: center;

border-radius: 0.6rem;

margin-top: 0.5rem;

}

  • 1
  • 2

得到的效果可以看下图(手机上看更明显一些):

bVbeb0j?w=720&h=1280

从上来看,回到之前的问题,"1.为什么是scaleY(0.5)?这个0.5是怎么得出的?是不是所有机型都是要scale缩小到一半,换句话说是不是通用?"其实并不一定是0.5,在dpr为3的设备上其实应该是0.3333……,也不通用,因为每个手机的dpr可能不一样,但是方法一中的0.5一般因为至少比1px细,所以也差不多可以满足设计师的要求了。

注意点

我后来在自己的项目中使用上面的根据dpr去计算initial-scale这个方法时,发现了一个坑,当时我的页面只是一个说明性的页面,基本上都是文字,我发现这个适配方法使用之后,文字大小并不能适配,现象来看,就是文字不能随着屏幕的变小而变小,但是变大是可以的。

后来查了下,发现是浏览器溢出算法的问题,也就是浏览器检测到文字过小的时候,会将文字放大,以达到不影响阅读的效果。可以在设置文字的时候加上

html {

text-size-adjust: none;

}

这样文字大小也可以适配了。

这篇关于一条1px的行线 html,移动端H5页面中1px边框的几种解决方法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Python依赖库的几种离线安装方法总结

《Python依赖库的几种离线安装方法总结》:本文主要介绍如何在Python中使用pip工具进行依赖库的安装和管理,包括如何导出和导入依赖包列表、如何下载和安装单个或多个库包及其依赖,以及如何指定... 目录前言一、如何copy一个python环境二、如何下载一个包及其依赖并安装三、如何导出requirem

Flutter监听当前页面可见与隐藏状态的代码详解

《Flutter监听当前页面可见与隐藏状态的代码详解》文章介绍了如何在Flutter中使用路由观察者来监听应用进入前台或后台状态以及页面的显示和隐藏,并通过代码示例讲解的非常详细,需要的朋友可以参考下... flutter 可以监听 app 进入前台还是后台状态,也可以监听当http://www.cppcn

MyBatis与其使用方法示例详解

《MyBatis与其使用方法示例详解》MyBatis是一个支持自定义SQL的持久层框架,通过XML文件实现SQL配置和数据映射,简化了JDBC代码的编写,本文给大家介绍MyBatis与其使用方法讲解,... 目录ORM缺优分析MyBATisMyBatis的工作流程MyBatis的基本使用环境准备MyBati

Nginx中location实现多条件匹配的方法详解

《Nginx中location实现多条件匹配的方法详解》在Nginx中,location指令用于匹配请求的URI,虽然location本身是基于单一匹配规则的,但可以通过多种方式实现多个条件的匹配逻辑... 目录1. 概述2. 实现多条件匹配的方式2.1 使用多个 location 块2.2 使用正则表达式

基于.NET编写工具类解决JSON乱码问题

《基于.NET编写工具类解决JSON乱码问题》在开发过程中,我们经常会遇到JSON数据处理的问题,尤其是在数据传输和解析过程中,很容易出现编码错误导致的乱码问题,下面我们就来编写一个.NET工具类来解... 目录问题背景核心原理工具类实现使用示例总结在开发过程中,我们经常会遇到jsON数据处理的问题,尤其是

前端bug调试的方法技巧及常见错误

《前端bug调试的方法技巧及常见错误》:本文主要介绍编程中常见的报错和Bug,以及调试的重要性,调试的基本流程是通过缩小范围来定位问题,并给出了推测法、删除代码法、console调试和debugg... 目录调试基本流程调试方法排查bug的两大技巧如何看控制台报错前端常见错误取值调用报错资源引入错误解析错误

Oracle登录时忘记用户名或密码该如何解决

《Oracle登录时忘记用户名或密码该如何解决》:本文主要介绍如何在Oracle12c中忘记用户名和密码时找回或重置用户账户信息,文中通过代码介绍的非常详细,对同样遇到这个问题的同学具有一定的参... 目录一、忘记账户:二、忘记密码:三、详细情况情况 1:1.1. 登录到数据库1.2. 查看当前用户信息1.

Springboot控制反转与Bean对象的方法

《Springboot控制反转与Bean对象的方法》文章介绍了SpringBoot中的控制反转(IoC)概念,描述了IoC容器如何管理Bean的生命周期和依赖关系,它详细讲解了Bean的注册过程,包括... 目录1 控制反转1.1 什么是控制反转1.2 SpringBoot中的控制反转2 Ioc容器对Bea

Vue中动态权限到按钮的完整实现方案详解

《Vue中动态权限到按钮的完整实现方案详解》这篇文章主要为大家详细介绍了Vue如何在现有方案的基础上加入对路由的增、删、改、查权限控制,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、数据库设计扩展1.1 修改路由表(routes)1.2 修改角色与路由权限表(role_routes)二、后端接口设计

C++实现回文串判断的两种高效方法

《C++实现回文串判断的两种高效方法》文章介绍了两种判断回文串的方法:解法一通过创建新字符串来处理,解法二在原字符串上直接筛选判断,两种方法都使用了双指针法,文中通过代码示例讲解的非常详细,需要的朋友... 目录一、问题描述示例二、解法一:将字母数字连接到新的 string思路代码实现代码解释复杂度分析三、