当前位置: 首页 > Web前端 > CSS

Css-Mobile适配总结

时间:2023-03-30 19:26:05 CSS

前言之后,大部分业务工作都是基于移动端H5。开发过程中,学到了很多,也遇到了很多问题,比如rememcsspxdevicepx等。本文纯属个人总结,如有问题请亲喷指出~PC端本文主要讲解了移动端的响应式布局,不过在真正进入之前,先了解一些概念。devicepx(设备像素)和csspx(css像素)通常在PC端,我们不需要考虑devicepixels和csspixels的区别。从目前的PC来看,1个设备像素通常等于1个css像素。您可以使用screen.width/height来获取屏幕的宽度和高度设备像素。screen.width//1920screen.height//1080如果你给一个元素的宽度为width:192px;那么您的屏幕(假设您的屏幕宽度为1920像素)可以在一行上显示10个元素。原理是因为1个设备像素在我们的PC中等于1个css像素。当用户放大或缩小屏幕时(按住ctrl+滚动鼠标滚轮,即改变缩放值),就不一样了。此时我们设备的像素没有变化,还是1920*1080,CSS像素的个数没有变化,只是CSS像素的大小发生了变化。假设放大到200%,那么1个css像素就等于2个设备像素,以此类推。以下三张图片引用ppk大师。下面的深蓝色是设备像素,上面的浅蓝色是css像素。一般情况下:缩小时:放大时:取screen.width/height和window.innerWidth/innerHeightscreen.width/heihgt是屏幕的宽高,单位是css像素。window.innerWidth/innerHeight取网页区域的宽高,单位是CSS像素。当您更改缩放值时,屏幕不会改变,内部宽度/高度会改变。viewport的概念viewport是对html元素进行限制的功能,可以理解为html元素的上层元素。听起来有点难以理解,下面说一个例子:假设,你给某个div元素设置了width:50%样式后,当你在浏览器上缩小和放大时,你会发现div元素一直占据着50%Width,我们知道,宽度百分比取决于它的包裹元素(假设是body),那么问题又回到了body的宽度。通常,当没有设置宽度时,所有块级元素都会占据其父元素宽度的100%。所以body和html元素一样宽。那么html元素有多宽呢?默认情况下,它和浏览器窗口一样宽,这就是为什么div总是占据浏览器宽度的50%,而html元素受限于viewport(占据与viewport相同的宽度),换句话说,viewport正好等于浏览器窗口,它不是HTML语言元素,所以你不能用css来影响它。我们可以通过document.documentElement.clientWidth/clientHeight获取视口的宽高,单位是CSS像素。clientWidth/Height和window.innerWidth/innerHeight都可以获得网页区域的大小,但是它们之间还是有区别的。前者不包含滚动条,后者有。html元素的大小我们可以通过document.documentElement.offsetWidth/offsetHeight获取html元素的宽高,单位是css像素。event事件和媒体查询事件的三对属性:pageX/Y:CSS像素相对于html元素的坐标clientX/Y:CSS像素相对于视口的坐标screenX/Y:设备像素Screen的相对坐标-basedmediaquery:基于viewport(documentElement.clientWidth/Height)@mediaalland(max-width:400px)基于screen(screen.width)@mediaalland(max-device-width:400px)Mobileindefault一般情况下,一般来说,移动设备上的视口要大于浏览器的可视区域。这是因为与台式电脑相比,移动设备的分辨率相对较小。为了正常显示那些为桌面浏览器设计的传统网站,移动设备上的浏览器会将其默认视口设置为980px或1024px(或其他值,这是由设备本身决定的),但带来的后果是浏览器将有水平滚动条,因为浏览器可见区域的宽度小于默认视口的宽度。下图列出了某些设备上浏览器的默认视口宽度。以下是关于各个浏览器的视口。三个viewport前面介绍了viewport的概念,但是在移动端,viewport并不是那么好理解。ppk在移动端提出了viewport的三个概念。Layoutviewport即布局视口,是浏览器默认的视口,可以通过document.documentElement.clientWidth获取。图片引用自深入理解viewportvisualviewportlayoutviewport的宽度就是浏览器默认的viewport,所以我们还需要一个viewport来表示可见区域的大小,ppk把这个viewport叫做visualviewport。ppk说可以通过window.innerWidth获取可视视口的宽度,但是我获取的时候发现获取的值是网页区域的值。图片引用自深度理解viewportidealviewport。有两个viewport是不行的,因为我们不希望用户滚动滚动条来浏览我们的网页,也不希望用户盯着缩小的PC网页看,所以我们有第三个viewportviewport.所谓理想视口就是当布局视口等于屏幕宽度时,比如ip6,它的理想视口是375px。设置viewport开发过h5的应该都知道,我们经常会在head标签中复制如下代码:它的作用其实就是设置理想视口。下面是它的6个属性:keyvaluewidth设置布局视口的宽度,为正整数,或者字符串"width-device"initial-scale设置页面的初始缩放值,为数字,可以有decimalsminimum-scale允许用户最小缩放值,它是一个数字,可以有一个小数值。用户允许的最大缩放值是一个数字,可以是十进制值。height设置布局视口的高度。这个属性对我们来说不重要,user-scalable很少用到是否允许用户缩放,取值为“no”或“yes”,no表示不允许,yes表示允许那么如果我们想设置理想的话视口,只需将宽度设置为width-device或将initial-scale设置为1.0即可。前者比较好理解,后者可以设置为1,为什么呢?首先我们要明白,设置为1.0意味着没有缩放,但是这样可以达到理想视口的效果,那么显然缩放是相对于理想视口而言的。当理想视口缩放到100%时,即zooming值为1时,不获取理想视口。如果两个属性都可以设置理想的视口,当两个属性冲突时如何解决冲突?发生这种情况时,浏览器将取两者中较大的值。例如,当width=400,理想视口宽度为320时,取400;当width=400,idealviewport的宽度为480时,取idealviewport的宽度。css像素和设备像素在移动端,1个css像素不等于1个设备像素,而是取决于设备像素比(物理像素(devicepixel)/独立像素(csspixel)),比如Iphone的Retina屏,有2倍屏(ip6s),3倍屏(ip6??plus),即设备像素比值分别为2和3,即1个css像素相当于4个设备像素或9个,如图:和,我们可以通过window.devicePixelRatio获取设备像素比dpr。1px的生成和问题解决的生成公司的设计师傅通常会给出基于ip6s的设计稿,也就是750px(i6s的屏幕是375px,是上面提到的屏幕的2倍,所以有750个物理像素).假设设计稿上有一个1px的边框,我们一般直接这样写:border{border:1pxsolid#ccc;}然后在designreview的时候会回调,因为设计感觉更大了,也就是,他认为这是2px排列。原因是设计稿是750px,里面的1px在真机上其实只有0.5px,所以就有了著名的1px问题。问题解决方案1、直接使用0.5px在iOS8下,苹果系列已经支持0.5px,也就是说当devicePixelRatio=2的时候,我们可以使用mediaquery来处理:版权属于作者。@media(-webkit-min-device-pixel-ratio:2){.border{border-width:0.5px}}这个好用,但是兼容性不是很好。2.使用边框图像或背景。也就是拍一张,一半透明,一半我们想要的颜色,然后填充,具体例子我就不说了。基本上,没有人会使用这种图像。更改颜色修改图片太麻烦了。3.box-shadow.box-shadow-1px{box-shadow:inset0px-1px1px-1px#c8c7cc;}这个颜色有阴影,估计过不了设计大佬的水平。4、PostCSS插件postcss-write-svg直接借助插件帮助我们实现。其实就是postcss帮我们生成图片。@svg1px-border{高度:2px;@rect{fill:var(--color,black);宽度:100%;高度:50%;}}.example{border:1pxsolidtransparent;border-image:svg(1px-borderparam(--color#00b1ff))22stretch;}最后Postcss会编译出对应的css。这种兼容性好,但要看插件。.example{border:1pxsolidtransparent;border-image:url("data:image/svg+xml;charset=utf-8,%3Csvgxmlns='http://www.w3.org/2000/svg'height='2px'%3E%3Crectfill='%2300b1ff'width='100%25'height='50%25'/%3E%3C/svg%3E")22stretch}5.伪类+transform实现原理是去掉border的原始元素,然后使用:before或:after重做边框,将transform的比例缩小一半,原元素相对定位,新制作的边框绝对定位。.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;}这种兼容性好,但是会和伪类冲突,并且它也被我们公司所采用。6、缩小视口的原理是利用meta标签中的视口,也就是上面说的设置视口,将整个页面缩小0.5倍。这主要是因为其他元素必须加倍然后收缩。对于这个小问题而这似乎有点不知所措。不过淘宝灵活的方案(rem布局,见下文)帮我们解决了这个问题。flexible和rem上面提到了flexible和rem的布局方案。刚推出时,它确实很受欢迎。公司部分项目至今仍在使用该方案。下面简单介绍一下它的原理。px,em,rempx:px前面已经提到了,它是一个固定的单位。em:当em作为font-size的单位时,表示父元素的字体大小,当em作为其他属性的单位时,表示自身的字体大小。rem:当rem作用于非根元素时,是相对于根元素的字体大小;rem作用于根元素的字体大小时,是相对于其初始字体大小的。/*作用于根元素,相对于原始大小(16px),所以html的font-size为32px*/html{font-size:2rem}/*作用于非根元素,相对于字体根元素的大小,所以是64px*/p{font-size:2rem}flexiblerem布局原理flexiblerem布局原理是将设计稿裁剪成100份,假设每份的单位是x,那么我们就可以以x为单位,将设计稿等比例放大缩小到对应的屏幕上,这样就不用去适配每个屏幕了。不过上面说的x是不存在的,幸好我们有rem,只要我们把rem设置为1x,那么在开发的过程中,不就达到我们的目的了吗?如何将rem设置为1x?回想一下,我们可以获取视口宽度(document.documentElement.clientWidth),我们可以获取设备像素比(window.devicePixelRatio),我们可以设置html样式(html.style.fontSize='...'),所以简单的实现方案有document.documentElement.style.fontSize=document.documentElement.clientWidth/100+'px';当然,flexible不是那么简单,它还处理不同的dpr,帮助你处理2x屏,3x屏等情况,通过设置viewport的缩放比例,这是0.5px的处理之一上面提到的解决方案。我不会在这里详细介绍。有兴趣的同学可以阅读原文。最后,移动端iOS8及以上和Android4.4及以上已经有vw\vh单位,1vw1vh相当于viewport宽/高的1%,也就是我们上面说的x单位,如果你的手机支持这个api,此单元方案也可用。为什么不用rem解决方案我依稀记得我用rem处理活动页面的时候,被设计者拒绝了。老板认为,当用户使用更大的屏幕时,应该能看到更多的内容,如果设计稿放大或缩小,就会失去原有的感觉。因此,rem方案可能不适合目前的情况。毕竟用mediaquery,px和em可以解决各种响应式的问题,虽然效率会比较低,关于这个,我只是看到知情人网上好像有人提过这样的问题,那些有兴趣可以去看看。为什么很多web项目还是用px而不是rem?总结本文主要是概念性的,也参考了很多文章。要真正理解,你需要参考实际项目。Reference&Quote移动前端开发之viewport深入理解两个viewport的故事—上篇两个viewport的故事—下篇Metaviewport7种解决手机Retina屏1px边框问题的方法说说关于Retinavh下的1px解法,你对vw单位了解多少?Rem布局原理分析