阅读过几篇关于 px rem 的文章,感觉 rem 很强大。但是自己接触到的公司项目全部都使用 px,想知道为什么。是我司技术更新落后了吗?

我们当然有在用 vw 和 vh,但是只是在 layout 层级,组件层使用 px。

人数赞同最多的回答

先抛出观点:

  • 本文建议读者不要使用flexible或者其他修改viewport致使viewport width不等于device-width的方案(因为这会导致一些bug)
  • 本文建议读者不要使用以rem或者小程序rpx来实现等比缩放为主的布局手段,而使用面向逻辑像素px为主,面向等比缩放的vx和vxxx(vw/vh/vmax/vmin)为辅助的布局单位,搭配一些flex等布局手段
  • 本文建议读者一般情况遵循:同样观看距离情况下,大屏看的更多而不是大屏看的更大的设计最佳实践来进行布局,并且以这种最佳实践作为理论依据来传递给设计师(当然你觉得等比缩放才是合理的,请看其他回答,该回答不适合你)
  • 本文没有鼓吹读者使用响应式布局,也没有鼓吹读者盲目忽略兼容性使用vx和vxxx,同时也没有反对读者使用rem这个单位本身原有的定义来实现一些布局

吐槽

你们老是鼓吹rem的,醒醒吧,别再看网上大片大片的rem文章

flexible方案已经废坑了,已经废坑了,已经废坑了

对,flexible已经不维护了,原因自己看flexible的github

px没有问题,用rem来实现自适应才有问题(因为它是vx,vxxx单位的备胎),能问这种问题的人,应该认真研究一下viewport。

下面简单介绍下上面的几个知识点:

①:flexible.js

rem是相对于根元素<html>,这样就意味着,我们只需要在根元素确定一个px字号,则可以来算出元素的宽高。1rem=16px(浏览器html的像素,可以设定这个基准值),假如浏览器的html设为64px,则下面的元素则1rem=64px来运算。

阿里团队开源的一个库flexible.js作用就是通过rem和px之间的换算,把设计稿从px转到rem。兼容自适应各种移动端设备。

flexible.js关键代码(通过js来调整html的字体大小,而在页面中的制作稿则统一使用rem这个单位来制作):

;(function(win, lib) {
var doc = win.document;
var docEl = doc.documentElement;
var metaEl = doc.querySelector('meta[name="viewport"]');
var flexibleEl = doc.querySelector('meta[name="flexible"]');
var dpr = 0;
var scale = 0;
var tid;
var flexible = lib.flexible || (lib.flexible = {}); if (metaEl) {
console.warn('将根据已有的meta标签来设置缩放比例');
var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
if (match) {
scale = parseFloat(match[1]);
dpr = parseInt(1 / scale);
}
} else if (flexibleEl) {
var content = flexibleEl.getAttribute('content');
if (content) {
var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
if (initialDpr) {
dpr = parseFloat(initialDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
if (maximumDpr) {
dpr = parseFloat(maximumDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
}
} 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;
} docEl.setAttribute('data-dpr', dpr);
if (!metaEl) {
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(metaEl);
} else {
var wrap = doc.createElement('div');
wrap.appendChild(metaEl);
doc.write(wrap.innerHTML);
}
} function refreshRem(){
var width = docEl.getBoundingClientRect().width;
if (width / dpr > 540) {
width = 540 * dpr;
}
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
} win.addEventListener('resize', function() {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}, false);
win.addEventListener('pageshow', function(e) {
if (e.persisted) {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
}, false); if (doc.readyState === 'complete') {
doc.body.style.fontSize = 12 * dpr + 'px';
} else {
doc.addEventListener('DOMContentLoaded', function(e) {
doc.body.style.fontSize = 12 * dpr + 'px';
}, false);
} refreshRem(); flexible.dpr = win.dpr = dpr;
flexible.refreshRem = refreshRem;
flexible.rem2px = function(d) {
var val = parseFloat(d) * this.rem;
if (typeof d === 'string' && d.match(/rem$/)) {
val += 'px';
}
return val;
}
flexible.px2rem = function(d) {
var val = parseFloat(d) / this.rem;
if (typeof d === 'string' && d.match(/px$/)) {
val += 'rem';
}
return val;
} })(window, window['lib'] || (window['lib'] = {}));

从上面的代码,主要是改变了dpx和document的font-size大小。大小为docEl.getBoundingClientRect().width / 10 + 'px';

详细可参考地址:《flexible.js 布局详解》

css里边px到底是什么

都9102了

都不知道px是viewport像素,

不是物理像素,不是逻辑像素,不是渲染像素

这里简单解释一下viewport像素,物理像素,逻辑像素,渲染像素

首先物理像素,逻辑像素,渲染像素的关系

下图是部分iphone设备的逻辑像素(下图为像素,其实应该翻译为点 Points),渲染像素,物理像素的指标,看了应该清晰这三者之间的关系

物理像素(physical pixel)就是反映显示屏的硬件条件,反映的就是显示屏内部led灯的数量,可以简单理解,一组三色led代表一个物理像素,当然根据屏幕物理属性以及处理led的方法不一样。强调这是物理的,因为这是一个纯硬件指标。比如我把屏幕锯了一半,物理像素就只有一半。
注:LED,发光二极管,是一种固态的半导体器件,它可以直接把电能转化为光能。
渲染像素(render pixel),则是在系统内部对物理像素的分配进行再一次的调整,在pc上,渲染像素其实就是设置里边的分辨率。对于显示设备,系统为显示设备提供渲染尺寸,由显示设备的“缩放引擎”(带存储器阵列的数字视频处理器)处理。这种“缩放引擎”一般内部有一系列的合理分辨率和一个推荐分辨率。一般推荐分辨率就是最大渲染像素,也是设备的物理分辨率(为了最佳表现)。这是一个软硬件(偏硬)结合的缩放方案。由于部分设备不能设置渲染像素,所以下文部分场景为了简化模型,直接跳过渲染像素,直接等同于物理像素
逻辑像素/点(device point / device pixel / point ),是为了调和距离不一样导致的差异,将所有设备根据距离,透视缩放到一个相等水平的观看距离之后得到的尺寸,是一个抽象的概念,这个单位就是ios开发的px,安卓开发的dp。对于pc,包括win(8+) linux,mac,由各自系统的或者对应软件(比如webview内部)提供的图像界面处理引擎处理进行缩放

在win上,可以通过显示设置缩放比例来调整部分应用的逻辑像素。对于linux,可以通过x和wayland的缩放比例来调整

但是,由于这个是一个纯软件的方案,如果部分软件不遵循开发规则,或者使用老旧的api,就会导致逻辑像素不合理,导致缩放问题。例如win10中部分旧的软件在高分屏的设备会导致界面偏小。因为他们实际是使用的是渲染像素而不是逻辑像素

各种设备,手机,平板,笔记本等逻辑像素

手机:逻辑像素在3xx-4xx(短边)之间

平板:10寸平板7xx-8xx(短边)

笔记本:13寸 1280 (长边)

24寸显示屏:1920(长边)

你会发现如果设置width=device-width下,无论是否高分屏,在浏览器得到的screen.width仍然符合上述的尺寸

逻辑像素的引入,简单来说,就是为了消除了不同屏幕观看距离和不同ppi(见下文)之间的差异,衍生出来的一个虚拟的尺寸

ppi(pixel per inch) 每英寸像素,指的是屏幕在每英寸的物理像素,更高的ppi意味着屏幕的清晰度更佳。

所谓高分屏,其实就是指ppi大于同类设备的屏幕。比如对于桌面设备,大于96ppi。对于移动设备,大于160ppi

所谓视网膜屏,其实就是指在该观看距离内超出人类的辨认能力的屏幕。比如对于桌面设备,大于192ppi。对于移动设备大于326ppi

ppi,对于移动设备而言,一般来说ppi以160为一个档次

也就是假设一个ppi160,2寸x3寸的屏幕,物理像素应该是320x480。同理ppi320,同样尺寸的屏幕,物理像素是640x960

由于它们尺寸一致,假设它们观看距离一致,那么消除掉ppi的影响,他们的逻辑像素是一致的

也就是

逻辑像素长度 = 物理像素长度 * 160 / ppi

得出都是 320 x 480

当然,由于生产标准不一致,不可能做到绝对的160ppi作为标准,所以ppi的等级划分是动态的

dpr (device point ratio / device pixel ratio) 渲染像素与逻辑像素的比例。由于渲染像素一般等于逻辑像素,如果ppi是以160为基准的话,那么 dpr = ppi / 160

多少倍屏或者多少x(三倍屏,3x,意思就是3dpr),一般来说就是说的是这个值

viewport像素又是什么,它本质是DIP(Device Independent Pixels),中文意思设备无关像素,是与上述所有像素都无绝对逻辑关系的一个单位。其实是浏览器内部对逻辑像素进行再处理的结果,简单来理解就是调整逻辑像素的缩放来达到适应设备的一个中间层

对于pc,viewport是不生效的,所以在pc上,px其实就是逻辑像素(chrome)。但是逻辑像素是与软件实现有关的,所以会出现一些问题。比如在win上,对于部分国产马甲浏览器,viewport内部没有适配系统的缩放等级,导致渲染的内容过小

如果你像评论区的某些看客一样麻木认为pc的px就是物理像素,那么你可能就不知道怎么解决了,甚至百度半天都找不到答案

比如这个问题

谷歌浏览器的100%显示和搜狗125%显示大小相同?

面向逻辑像素开发的基本开发流程

  • 1. 在head 设置width=device-width的viewport
  • 2. 在css中使用px
  • 3. 在适当的场景使用flex布局,或者配合vw进行自适应
  • 4. 在跨设备类型的时候(pc <-> 手机 <-> 平板)使用媒体查询
  • 5. 在跨设备类型如果交互差异太大的情况,考虑分开项目开发

那么viewport width=device-width是什么意思,其实就是让viewport的尺寸等于逻辑像素的尺寸

关于px的疑问

那有朋友就问,不同设备的物理像素是不一样的呀,我怎么实现不同物理像素的布局,如果设计师给你一张图,怎么将它转为我想要的在css里边的px

首先,你要读懂设计师给你设计图的意图,一般国内的设计师,给出手机版的设计图,一般是750px,注意这里的px,并不是我们的px(逻辑像素),其实是物理像素,因为设计师是根据iphone6或者同等设备来进行设计的,那么要知道iphone6的逻辑像素其实是 375,dpr是2,那么拿到手的设计稿,转换为逻辑像素,就得除以2,我们叫这种设计图,叫两倍图

同理,如果是375 + 375 + 375大小,那么我们就得除以3,叫三倍图

如果设计团队有使用墨刀或者蓝湖,你可以在两者里边设置你的查看尺寸,得到我们需要的逻辑像素

如果设计师不用蓝湖等工具,给你的并不是375的倍数怎么办,我先说办法,原因你们自己琢磨,我不细致分析

最简单的方法,设计师给你的图的物理宽度w,除以一个数x,如果得的出来的商在360 - 414之间,那么你换算的公式为【你在设计图测量出来的物理像素数除以x】,那么dpr就是x,也就是x倍图

那么朋友又会问,不同设备逻辑像素也不一样呀

对,不一样,但问题为什么我们要将它们弄成一样?其实,不一样,才是合理的。我暂且不说原因,原因后面的文章解释

那么不一样的情况,怎么布局?那就靠你们技术手段,flex,流式布局,vw等

总结

  • 设计师给的设计稿都是物理像素(比如750px),我们实际处理的是移动端的屏幕尺寸px是逻辑像素(比如iphone6的逻辑像素是375);由于PC端viewport是不生效的,所以pc端的px就是逻辑像素(chrome)
  • ppi(pixel per inch) 每英寸像素,指的是屏幕在每英寸的物理像素,更高的ppi意味着屏幕的清晰度更佳。对于移动设备而言,一般来说ppi以160为一个档次。
  • dpr (device point ratio / device pixel ratio) 渲染像素与逻辑像素的比例。由于渲染像素一般等于逻辑像素,如果ppi是以160为基准的话,那么 dpr = ppi / 160.
  • 逻辑像素长度 = 物理像素长度 * 160 / ppi,也即是逻辑像素长度 = 物理像素长度 * 1/dpr;

知乎问题地址及详细答案:《为什么很多web项目还是使用 px,而不是 rem?》

知乎问题:为什么很多web项目还是使用 px,而不是 rem?的更多相关文章

  1. 献给那些每次调试时都要启动很多WEB项目的苦逼程序猿

    当一个解决方案包含多个WEB项目的时候,只要按F5调试,其它用不着的WEB项目也会自动添加到托盘里.很多新手都不知道如何解决这个问题,我也是刚知道. 在网上找了很多资料看到有2种解决方法: 1.把WE ...

  2. 小型web项目的模块化(转)

    背景   目前团队中新的 Web 项目基本都采用了 Vue 或 React ,加上 RN,这些都属于比较重量级的框架,然而对于小型 Web 页面,又显得过大.早期的一些项目则使用了较原始的 HTML ...

  3. 在WEB项目中调用QQ通讯组件打开QQ聊天界面

    在很多WEB项目中,需要提供在线服务的功能,加上自己的联系方式,例如:QQ,不用添加QQ好友也可以交谈,那这到底是怎么实现的呢? 对于这个功能,需要提到一个组件,即“QQ通讯组件”.QQ通讯组件是一种 ...

  4. 原创一看便知、Maven创建web项目

    创建maven-项目    如果 pom.xml 文件报错 右击项目-->Maven-->update Project 详细步骤   上图中Next 2.继续Next 3.选maven-a ...

  5. IntelliJ IDEA WEB项目的部署配置

    以下内容是我网上找的比较全面了,其中关于facets配置很多地方都没有说明,其实很重要,我加入了自己的理解.其他来自网络.在导入一个项目有问题时,建议先创建一个正确的web项目,然后对比配置项,一般就 ...

  6. MyEclispe发布web项目-遁地龙卷风

    (-1)写在前面 我用的是MyEclipse8.5. 还记得以前帮助一个女同学解决问题的时候,特意情调了要先启动服务在发布项目,其实单独的时候都是知道的,总和起来后就容易片面的给出结论.因为不会发生问 ...

  7. ASP.NET 5 Web 项目

    在Mac OS X Yosemite 10.10.3 中搭建第一个 ASP.NET 5 Web 项目 终于有时间在 Mac 上安装一下 ASP.NET 5,网上有许多教程,但是多数的时间比较早了,版本 ...

  8. web项目自定义路由_实现静态资源URL控制

    前言: IIS会默认把:图片.JS.HTML.CSS这些文件当成静态资源处理,为了减少服务器压力,默认这些静态资源是不走URL路由规则控制的. 作为小白及初学者,本人对这些了解甚少,补充基础知识吧: ...

  9. java web项目为什么我们要放弃jsp?

    前戏: 以前的项目大多数都是java程序猿又当爹又当妈,又搞前端(ajax/jquery/js/html/css等等),又搞后端(java/mysql/Oracle等等). 随着时代的发展,渐渐的许多 ...

  10. 《Maven实战》笔记-8-构建部署Web项目

      一.Web项目结构 1.显式指定Web项目打包方式为war:   2.默认目录 根据“约定大于配置”的规则,Web项目的类及资源文件默认位置为src/main/java和src/main/reso ...

随机推荐

  1. 透视开源生态,OSGraph——GitHub全域数据图谱的智能洞察工具

    "透视开源生态,OSGraph--GitHub全域数据图谱的智能洞察工具 OSGraph (Open Source Graph) 是一个开源图谱关系洞察工具,基于GitHub开源数据全域图谱 ...

  2. 使用post请求登陆

    1.使用post请求登陆 import requests import matplotlib.pyplot as plt url = 'https://www.ptpress.com.cn/login ...

  3. django 如何查询汇总的求和时避免没有数据导致的错误

    django 如何查询汇总的求和时避免没有数据导致的错误 在 Django 中,如果你希望对某个字段进行求和操作,并在没有数据时返回默认值,可以使用 aggregate 结合 Coalesce 函数. ...

  4. oeasy教您玩转linux 010216 随机诗词 fortunezh

    我们来回顾一下 上一部分我们都讲了什么? 下载fortune 输出重定向到cowsay 多重输出重定向 fortune的细节 有没有中️文的fortune呢 # 搜索一下fortune apt sea ...

  5. [oeasy]python0029_放入系统路径_PATH_chmod_程序路径_执行原理

    ​ 放入路径 回忆上次内容 上次总算可以把 sleep.py 直接执行了 sleep.py文件头部要声明好打开方式 #!/usr/bin/python3 用的是 python3 解释 sleep.py ...

  6. C# 常用类和命名空间

    Array类 用括号声明数组是C#中使用Array类的记号.在后台使用C#语法,会创建一个派生于抽象基类Array的新类.这样,就可以使用Array类为每个C#数组定义的方法和属性了. Array类实 ...

  7. ABC357

    A link 循环加每一个数,加到哪个数不能加了输出前一个数,注意如果加到最后还能加,记得输出\(n\). 点击查看代码 #include<bits/stdc++.h> using nam ...

  8. SpringTask

    SpringTask是spring提供的一个任务调度工具,按照约定的时间自动执行代码逻辑 定时任务框架,即定时自动执行某段代码 应用场景:信用卡每月还款提醒,火车售票系统处理未支付订单 cron表达式 ...

  9. [春秋云镜] Initial

    [春秋云镜] Initial **整套网络环境拓扑:** ​​ 一.打进内网 开局一个ip:39.101.184.25,fscan扫一下 ​​ 存在thinkphp5.0.23的漏洞,可以rce,我们 ...

  10. Mysql查询几天前或几天后的日期

    查询 当天±天数 后的日期."-14"表示14天前的日期,"14"表示14天后的日期 NOW()精确到时分秒,CURDATE()只精确到天 #查询今天 1.se ...