逻辑像素(设备独立像素):独立于设备的用于逻辑上衡量像素的单位。在移动Web开发中就是指的CSS的逻辑像素。css像素:web编程用到的,在JS和CSS中使用就是CSS像素,是可变的。设备像素比(dpr):用来描述单一方向上,设备物理像素的点数/逻辑像素的点数的比率。值越高,屏幕密度越大。常说的两倍屏、三倍屏,这里面的倍数指的就是dpr。在JS中我们可以通过window.devicePixelRatio来得到当前设备的dpr.在CSS中我们可以通过-webkit-device-pixel-ratio来进行媒体查询.
通过document.documentElement.clientWidth来获取layoutviewport的宽度。
通过window.innerWidth获取
在移动端布局中我们需要的是idealviewport。
页面放大:视口缩小滚动滚动条:视口移动
document.documentElement.clientWidth(不含滚动条)window.innerWidth(含滚动条)注意:在移动端的浏览器中,对页面手动捏合做放大时,document.documentElement.clientWidth不会有任何变化。window.innerWidth在iOS中会等倍数缩小,在Android的不同浏览器中表现差异较大。
移动互联网的早期,屏幕设备的物理像素点宽度多数在320、480、640等。而互联网世界的绝大多数站点又是针对PC设计的,其文档宽度普遍在800px以上。如果浏览器和针对PC制作的网页都不做任何处理,那么在窄屏设备上加载网页,我们看到的效果便是默认显示网页的左上角部分,然后通过水平和竖直方向的滚动来浏览网页的其他部分。首先,我们看不到网页全局的样子。其次,我们需要通过不断的滚动来保证阅读内容的连续性。这样的体验,有点过于糟糕了。
为了优化“最初为PC设计的网页”在移动设备的浏览体验,移动浏览器厂商们想了一个方案,那就是增大页面载入时初始视口的宽度,比如Android和iOS都比较常见的980px。按照2.1里的viewport的解释,如此的设计,会把逻辑层画布中980px的图像投影显示到320px的屏幕上,看到的效果便是一个挤在一起看不清楚细节的缩小版页面。不过,该方案依然会有很多问题:●对缩小版页面内细节内容的浏览,依然要依靠放大和滚动,体验不好;●如果为PC设计的网页的CSS宽度描述大于980px,那么在移动端展示时,初始页面依然会有滚动条;●限制了依据视口宽度做媒体查询(Mediaqueries)机制的有效性,因为视口宽度初始为980px,浏览器不会以640px、480px或更低分辨率来启动对应的媒体查询。
●针对较宽(比如2000px)PC设计的页面,我们可以设置viewport宽度为2000,以使得移动设备中初始渲染的页面效果刚好不出现滚动条;●利用了媒体查询做了移动端适配的页面,我们可以设置viewport宽度为device-width,以保证媒体查询技术的有效性,同时还能保证横竖屏切换时,px单位做大小描述的页面元素的视觉大小一致性;●需要充分利用屏幕物理像素点做1像素极细边线的页面,我们可以设置viewport缩放倍数为1/dpr,以使得css中的1px刚好对应设备物理像素中的1个点;●需要根据屏幕宽度弹性伸缩的页面,我们可以结合各种相对长度单位(%/rem/vw等),设置合适的viewport,以实现布局伸缩和内容大小固定的完美统一。
以iPhone6s手机+Safari浏览器举例,对上述属性做详细说明。设备参数说明:●操作系统:iOS12.3.1●屏幕物理分辨率:750*1334●屏幕逻辑分辨率:375*667(screen.width/height)●设备像素比(dpr):2(window.devicePixelRatio)●浏览器默认视口宽度:980(document.documentElement.clientWidth)
1
width=device-width和initial-scale=1是等效的。
作为开发者,我们要做的,就是避免冲突。要么只写一个,要么两个都计算正确。从语义表达角度看,建议只设置"width"。从计算方便角度看,可以只设置initial-scale。
跨屏适配的需求,根据业务类型,一般有两种UI设计方案:●根据屏幕宽度,UI布局弹性伸缩或流动。这种方式被称为响应式设计(_ResponsiveDesign_);●把屏幕按宽度范围分为有限的几个区段,为每个区段定制固定的UI,相当于为专门的设备设计专门的UI。这种方式被称为自适应设计(_AdaptiveDesign_)。
响应式。屏幕适配无粒度区分,同一设备上做宽度变化时,内容布局无缝圆滑变化;技术实现通常为,一套代码适配所有屏幕。
自适应。屏幕适配有粒度区分,原则上不做过渡态的UI设计,同一设备上做宽度变化时,内容布局卡顿式梯级变化;技术实现通常为,多个屏幕对应多套代码。(演示如下图)
响应式设计方案,常见于PC、移动等多端共用一套代码的场景。典型的Web站点如GitHub浏览这类站点时,随着屏幕的缩小,你会看到页面模块的布局结构在伸缩、流动或显隐变化,文字图片等主体内容在布局容器内流动填充、其大小也一直在做梯级变化。
为了在特定设备上实现最好的用户体验,越来越多的产品,开始针对特定屏幕设计固定的UI,绝大多数移动端产品都有了区分于PC的专门的m站。其技术实现通常为:服务器根据浏览器请求的user-agent判断设备类型,然后返回(或重定向)对应的站点内容。
移动端的屏幕宽度差距比较小(4-8英寸),UI页面通常也会保持一致的布局方式,只是文字、图标、大图片等可能会根据业务需要做一些定制化的处理。
移动端多屏适配的需求,常见主要有两类:1、布局伸缩式(布局伸缩,内容大小固定或梯级变化);2、等比缩放式(布局和内容完全等比例缩放)。
对应的技术方案一般也是对视口(viewport)、媒体查询(mediaqueries)、单位(px/%/rem/vw)的组合使用。
如上图,布局伸缩式适配需求,常见于排版比较简单的信息流展示类业务。其布局特点一般为横向伸缩,竖向高度固定或由内容填充决定;文字图标等网页内容一般会固定大小,且在宽屏窄屏上的视觉大小保持一致。
如上图,等比缩放式适配需求,广泛应用于各种产品类、运营类等业务场景。其布局特点简单粗暴,就是根据屏幕宽度整个页面等比缩放。
remrem是CSS3新增的相对于根元素html的font-size计算值的大小的倍数单位。早期的移动端等比缩放的适配方案都是基于rem。●设置viewport宽度为device-width或其他固定值,以得到px为单位的文字、图标或边线等期望的渲染效果●css单位使用rem,js根据viewport宽度以及css中rem的换算系数,动态计算并设置html根节点font-size,以实现整个页面内容的等比例缩放
注:一些文本段落展示类的需求,UI设计师可能会希望宽屏比窄屏在一行内可以展示更多的文字。这时就需要引入媒体查询,并且对字号使用px单位做特殊处理。
viewportunits
1vw即表示当前视口宽度的1%,我们可以利用这一点替代“rem+根节点font-size”的等比缩放实现。举个例子,750px的UI稿中,宽度75px的按钮,在css中的宽度描述即为:width:10vw。
viewportmetaonly看起来viewportunits方案是目前最简单可行的方案了,UI稿里的标注直接都转换成vw单位就可以了,html中不需要做任何js处理。那么,是不是还可以更简单一些呢?
回到本文最初的起点,
我们做的ui稿中的px到css的rem、vw这些单位的转换,核心目的就是在不同的屏幕上高保真还原设计稿。
那么,我们直接把web容器视口的大小定为和UI稿一样的px大小不就可以了?是的,不再需要做任何单位的转换。而且,完美实现UI稿的高保证还原。完全不需要担心什么0.5px细线问题。然而,当前前端圈内viewportmetaonly方案并未成为主流方案,个人认为,原因主要是——业务场景中,存在非等比缩放类的适配需求,比如布局只要横向伸缩、字号要px固定等。如果100%确定当前业务可以完全等比缩放式适配,那么,强烈推荐使用该方案。
主要是跟一个东西有关,DPR(devicePixelRatio)设备像素比,它是默认缩放为100%的情况下,设备像素和CSS像素的比值。
window.devicePixelRatio=物理像素/CSS像素目前主流的屏幕DPR=2(iPhone8),或者3(iPhone8Plus)。拿2倍屏来说,设备的物理像素要实现1像素,而DPR=2,所以css像素只能是0.5。一般设计稿是按照750来设计的,它上面的1px是以750来参照的,而我们写css样式是以设备375为参照的,所以我们应该写的0.5px就好了啊!试过了就知道,iOS8+系统支持,安卓系统不支持。
通过JavaScript检测浏览器能否处理0.5px的边框,如果可以,给html标签元素添加个class。
if(window.devicePixelRatio&&devicePixelRatio>=2){vartestElem=document.createElement('div');testElem.style.border='.5pxsolidtransparent';document.body.appendChild(testElem);}if(testElem.offsetHeight==1){document.querySelector('html').classList.add('hairlines');}document.body.removeChild(testElem);div{border:1pxsolid#bbb;}.hairlinesdiv{border-width:0.5px;}优点:简单,不需要过多代码。缺点:无法兼容安卓设备、iOS8以下设备。
利用css对阴影处理的方式实现0.5px的效果
.box-shadow-1px{box-shadow:inset0px-1px1px-1px#c8c7cc;}优点:代码量少、可以满足所有场景缺点:边框有阴影,颜色变浅
同时通过设置对应viewport的rem基准值,这种方式就可以像以前一样轻松愉快的写1px了。在devicePixelRatio=2时,输出viewport:
单条border样式设置:将伪元素设置绝对定位,并且和父元素的左上角对齐,将width设置100%,height设置为1px,然后进行在Y方向缩小0.5倍。
.scale-1px{position:relative;border:none;}.scale-1px:after{content:'';position:absolute;bottom:0;background:#000;width:100%;height:1px;-webkit-transform:scaleY(0.5);transform:scaleY(0.5);-webkit-transform-origin:00;transform-origin:00;}四条boder样式设置:为伪元素设置绝对定位,并且和父元素左上角对其。将伪元素的长和宽先放大2倍,然后再设置一个边框,以左上角为中心,缩放到原来的0.5倍。