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

响应式布局常用方案对比(媒体查询、百分比、rem、vw-vh)

时间:2023-04-05 18:41:56 HTML5

我的博客原文地址:原文地址如果文章对你有帮助,你的star就是对我最好的鼓励~简介:在前端开发中,静态网页通常需要适配不同分辨率的设备。常用的自适应方案包括媒体查询、百分比、rem和vw/vh等。本文从px为单位出发,分析px在移动端布局中的不足,然后介绍几种不同的自适应方案。px和viewport媒体查询百分比自适应场景下rem方案使用vw/vh实现自适应1.px和viewport在静态网页中,我们经常以像素(px)为单位来描述一个元素的宽度高度和位置信息。在PC端,一般认为在CSS中,1px所代表的真实长度是固定的。那么,px真的是设备无关的,是不是像长度单位米、分米一样是固定大小的呢?答案是不。下图1.1和图1.2分别为PC端和移动端下的显示结果。在网页中,我们设置的font-size统一为16px。

图1.1font-size为16px在PC端显示结果

图1.2移动端font-size为16px显示结果

从上面两张图的对比可以看出,字体都是16px的。很明显,文字在PC端显示正常,但是在移动端,文字很小,几乎看不到,这说明在css中1px不是一个固定大小。直观上,我们发现移动端1px代表的长度较小,文字显示不清晰。那么是什么决定了css中1px的真实长度呢?为了弄清楚这个概念,我们首先介绍像素和视口的概念1.像素像素是网页布局的基础。像素代表计算机屏幕可以显示的最小区域。像素分为两类:CSS像素和物理像素。我们在js或者css代码中使用的px单位指的就是css像素。物理像素也称为设备像素,只与设备或硬件有关。同样尺寸的屏幕,设备密度越高,物理像素越多。下表是css像素和物理像素的具体区别:|css像素|是为web开发者提供的,css中使用的抽象单元||-|:-:||物理像素|只和设备的硬件密度有关,任何设备的物理像素都是固定的|那么CSS像素和物理像素之间的转换关系是怎样的呢?要想弄清楚CSS像素和物理像素之间的转换关系,首先要了解什么是viewport。2.视口广义的视口是指浏览器显示内容的屏幕区域,狭义的视口包括布局视口、视觉视口和理想视口(一)布局视口(layoutviewport)布局视口定义默认移动端pc网页的布局行为改变,因为通常pc的分辨率较大,默认布局视口为980px。也就是说,如果不设置网页的视口,PC端的网页会默认根据布局视口显示在移动端。因此,我们可以清楚地看到,当使用默认布局视口时,根植于PC端的网页在移动端会显示模糊。(2)视觉视口(visualviewport)视觉视口表示在浏览器中看到的网站的显示区域。用户可以通过缩放来查看网页显示的内容,从而改变视觉视口。视觉视口的定义就像拿着放大镜从不同的距离观察同一个物体。视觉视口只是类似放大镜显示的内容,所以视觉视口不会影响布局视口的宽高。(3)理想视口(idealviewport)或者应该叫做“ideallayoutviewport”,在移动设备中指的是设备的分辨率。换句话说,理想的视口或分辨率是给定设备物理像素的最佳“布局视口”。在上述视口中,最重要的是理清了理想视口的概念。在移动端,理想视口或分辨率与物理像素之间的关系是什么?为了明确分辨率和物理像素的关系,我们引入一个DPR(Devicepixelratio)设备像素比来表示,它可以写成:1DPR=物理像素/分辨率在没有缩放的情况下,一个cssApixel对应一个dpr,也就是说不缩放1CSSpixel=physicalpixel/resolution另外,在移动端的布局中,我们可以通过viewportmeta标签来控制布局。例如,一般情况下,我们可以使用下面的标签让移动端在理想视口下布局:以上meta标签各属性详细介绍如下:|属性名称|价值|说明||-|:-:|-:||宽度|正整数|以像素为单位定义布局视口的宽度||身高|正整数|定义布局视口的高度,以像素为单位,很少使用||初始规模|[0,10]|初始缩放,1表示不缩放||最小尺度|[0,10]|最小缩放比例||最大尺度|[0,10]|最大缩放比例||在终端布局中,我们将在meta标签中将宽度设置为device-width。device-width一般表示分辨率的宽度。通过设置width=device-width,我们将布局视口设置为理想视口。嘴。3.px与自适应上面我们了解到,通过视口meta标签将布局视口设置为理想视口时,1个css像素可以表示为:1个CSS像素=物理像素/分辨率。让我们知道PC端布局视口通常是980px,移动端以iphone6为例,分辨率为375667,也就是说布局视口理想情况下是375px。比如现在我们有一个750px1134px的视觉稿,那么在PC端,一个css像素可以这样计算:PC端:1个CSS像素=物理像素/分辨率=750/980=0.76px在iphone6下:iphone6:1个CSS像素=物理像素/分辨率=750/375=2px也就是说在PC端,一个CSS像素可以用0.76个物理像素表示,而在iphone6中一个CSS像素表示2个物理像素.另外,不同的移动设备有不同的分辨率,即一个CSS像素可以表示的物理像素是不同的。因此,如果在CSS中仅仅使用px作为长宽的单位,其结果是无法通过一套样式来实现。两端自适应。2、媒体查询我们上面提到,在不同的设备下,在css文件中,1px所代表的物理像素大小是不同的,所以不可能通过一套样式来实现每一端的自适应。由此我们想到:如果一套样式还不够,是否可以每个设备都有不同的一套样式来达到自适应的效果呢?答案是肯定的。使用@media媒体查询可以针对不同的媒体类型定义不同的样式,尤其是响应式页面,可以针对不同的屏幕尺寸编写多套样式,从而达到自适应的效果。例如:@mediascreenand(max-width:960px){body{background-color:#FF6699}}@mediascreenand(max-width:768px){body{background-color:#00FF66;}}@mediascreenand(max-width:550px){body{background-color:#6633FF;}}@mediascreenand(max-width:320px){body{background-color:#FFFF00;}}以上代码通过mediaQuery定义了几组样式,通过max-width设置样式生效时的最大分辨率。上面的代码分别为0到320px、320px到550px、550px到768px、768px到960px分辨率的屏幕设置了不同的背景。颜色。通过媒体查询,你可以通过为不同分辨率的设备编写不同的样式来实现响应式布局。例如,我们为不同分辨率的屏幕设置不同的背景图片。比如为小屏手机设置@2x图片,为大屏手机设置@3x图片,可以通过媒体查询轻松实现。但是,媒体查询的缺点也很明显。如果浏览器大小变化时需要更改的样式太多,那么多套样式代码会很繁琐。3.百分比除了使用px结合媒体查询来实现响应式布局,我们还可以使用百分比单位“%”来实现响应式效果。例如,当浏览器的宽度或高度发生变化时,可以使用百分比单位,使浏览器中组件的宽度和高度随着浏览器的变化而变化,从而达到响应式的效果。要想理解百分比布局,首先要理解的问题是:CSS中子元素中的百分比(%)是谁的百分比?直观的理解,我们可能认为子元素的百分比完全是相对于直接父元素的,高度的百分比是相对于高度的,宽度的百分比是相对于宽度的。当然这个理解是对的,但是按照CSS盒子模型,除了height和width属性,还有padding,border,margin等属性。那么这些属性设置成百分比,是不是以父元素的属性为准呢?另外,border-radius、translate等属性中也有百分比,它们是相对于什么的?我们来详细分析一下。1.百分比的具体分析(1)子元素高宽百分比子元素的高度或宽度使用的百分比是相对于子元素的直接父元素,宽度是相对于父元素的宽度元素,高度是相对于父元素的高度。例如:
如果设置:.father{width:200px;高度:100px;}.child{宽度:50%;height:50%;}显示效果为:(2)top和bottom,left和right子元素top和bottom如果设置了百分比,相对于直接非静态定位(默认定位)的父元素的高度,则相对于直接非静态定位(默认定位)父元素的宽度,同一子元素的左侧和右侧(如果设置了百分比)。显示效果为:(3)如果padding子元素的padding设置为百分比,不管是垂直还是水平,都是相对于直接父元素的宽度,与父元素的高度无关元素。例如:.parent{width:200px;高度:100px;背景:绿色;}.child{宽度:0px;高度:0px;背景:蓝色;白颜色;填充顶部:50%;padding-left:50%;}显示效果为:子元素初始宽高为0,父元素可以通过padding扩展。上图中蓝色部分是一个边长为100px的正方形,表示padding不分宽高。如果设置为Percentages是相对于父元素的宽度。(4)margin和padding一样,margin也是。如果子元素的边距设置为百分比,不管是垂直还是水平,都是相对于直接父元素的宽度。这里不举具体例子。(5)border-radiusborder-radius不同,如果border-radius设置为百分比,是相对于自身宽度的,例如:setborder-radiusas百分比:.trangle{width:100px;高度:100px;边界半径:50%;背景:蓝色;margin-top:10px;}显示效果为:除了border-radius,还有translation,background-size等都是相对的,这里就不举例了。2.百分比单位布局应用百分比单位在布局中的应用还是比较广泛的,这里有一个应用。比如我们要实现一个固定长宽比的矩形,比如长宽比为4:3的矩形,我们可以根据padding属性来实现,因为padding的百分比单位是相对于parent的不管它是垂直的还是水平的。元素的宽度,所以我们可以设置padding-top为百分比来实现,长宽自适应的矩形:设置样式让它自适应:.trangle{高度:0;宽度:100%;padding-top:75%;}通过设置padding-top:75%,就是相对宽度的75%,所以设置了一个长宽高比例恒定的矩形,具体效果如下图:3.百分比单位的缺点从上面对百分比单位的介绍,我们不难看出,如果全部使用百分比单位来实现响应式布局,有两个明显的缺点:(1)计算困难,如果我们要定义宽度根据设计稿,元素的高度必须换算成百分比单位。(2)从第1节可以看出,如果每个属性都使用百分比,则相对于父元素的属性是不唯一的。例如,width和height是相对于父元素的宽高,而margin和padding是相对于父元素在垂直和水平方向的宽度,border-radius是相对于元素本身等,这使得我们很容易使用百分比单位使布局问题变得复杂。四、自适应场景下的rem解决方案1.rem单元首先我们来看一下什么是rem单元。rem是一个灵活的、可扩展的单位,它被转换为像素并由浏览器显示。与em单位不同,rem单位仅与浏览器根元素(HTML元素)的字体大小相关,与嵌套级别无关。默认情况下,html元素的font-size为16px,所以:1rem=12px为了计算方便,通常可以将html的font-size设置为:html{font-size:62.5%}本例中:1rem=10px2。响应式布局是通过rem实现的。rem单位是相对于根元素html的font-size来确定的。根元素的字体大小相当于提供了一个基准。当页面大小发生变化时,只需要改变font-size的值,那么以rem为固定单位的元素的大小也会随之改变。因此,如果通过rem实现响应式布局,只需要根据视图容器的大小动态改变font-size即可。函数refreshRem(){vardocEl=doc.documentElement;varwidth=docEl.getBoundingClientRect().width;varrem=宽度/10;docEl.style.fontSize=rem+'px';flexible.rem=win.rem=rem;}win.addEventListener('resize',refreshRem);上面代码中,view容器被分成10份,font-size用宽度的十分之一来表示。最后在header标签中执行这段代码,可以动态定义font-size的大小,这样1rem在不同的视觉容器中代表不同的大小,使用rem固定单位可以实现布局自适应不同的容器。3、如果rem2px和px2rem在响应式布局中使用了rem单位,那么就存在单位转换的问题。rem2px表示从rem转换为px。这个就不说了,只要把rem乘以对应font-size里的size,就可以换算成px了。更多的应用是px2rem,意思是从px转换为rem。比如给定的视觉稿是750px(物理像素),如果我们要用rem来表示所有的布局单位,比较笨的做法是把所有的元素比如高和宽都乘以相应的比例,现在转换视觉稿转化为rem单位,然后用rem来一一表示。还有一个更方便的方案是我们在css中还是用px来表示元素的大小,最后在写完css代码之后,将css文件中的所有px单位都转换成rem单位。px2rem的原理也很简单,重点是对以px为单位的css文件进行预处理,处理后将px全部转为rem单位。可以通过两种方式实现:1)webpackloader的形式:npminstallpx2rem-loader在webpack的配置文件中:module.exports={//...module:{rules:[{test:/\.css$/,use:[{loader:'style-loader'},{loader:'css-loader'},{loader:'px2rem-loader',//这里的选项options:{remUni:75,remPrecision:8}}]}]}}2)在webpack中使用postcss插件npminstallpostcss-loader在webpack的插件中:varpx2rem=require('postcss-px2rem');module.exports={module:{loaders:[{test:/\.css$/,loader:"style-loader!css-loader!postcss-loader"}]},postcss:function(){return[px2rem({remUnit:75})];}}4。rem布局应用例如网易新闻的移动端页面就使用了rem布局,具体示例如下:五、rem布局的缺点通过rem单元可以实现响应式布局,特此介绍相应的postcss相关插件,免去了设计稿中px到rem的计算。国外一些网站也使用rem单位。这里说的rem实现布局的缺点,或者说小缺陷是:在响应式布局中,必须通过js动态控制根元素的font-size。也就是说css样式和js代码有一定的耦合性。并且更改字体大小的代码必须放在css样式之前。五、通过vw/vh自适应1.什么是vw/vh?css3中引入了一个新的单位vw/vh,与viewwindow有关。vw表示相对于视图窗口的宽度,vh表示相对于视图窗口的高度,除了vw和vh之外,还有两个相关单位vmin和vmax。各单位的具体含义如下:单位含义vw是相对于窗宽的,窗宽相对于窗高是100vwvh,窗高是100vhvminvw和窗高中较小的值vh,vmaxvw和vh中较大的值这里我们求窗口宽高为100vw/100vh,所以vw或vh,以下简称vw,非常类似于一个百分比单位。vw和%的区别是:单位%的意义大多是相对于祖先元素的,也有相对于自身的,比如(border-radius,translate等)vw/vh是相对于元素的大小窗户。从对比中我们可以发现,vw单位和Percentages都差不多,但是还是有区别的。我们介绍了转换百分比单位的难度。这里的vw更像是一个“理想的百分比单位”。任何层级元素,在使用vw单位的情况下,1vw等于视图宽度的百分之一。2.vw单位转换同理,如果要将px转换成vw单位,也很简单,只要确定视图(布局视口)的窗口大小即可,如果我们将布局视口设置为分辨率大小,例如,对于iphone6/7375*667分辨率,那么px可以通过下面的方式转换成vw:1px=(1/375)*100vw另外也可以通过相应的插件预处理css做自动转换postcss,postcss-px-to-viewport可以自动将px转为vw。postcss-px-to-viewport默认参数为:vardefaults={viewportWidth:320,viewportHeight:568,unitPrecision:5,viewportUnit:'vw',selectorBlackList:[],minPixelValue:1,mediaQuery:false};通过指定窗口的宽度和高度,以及转换精度,可以将px转换为vw。3、vw/vh单位的兼容性可以在https://caniuse.com/查看各版本浏览器对vw单位的支持情况。从上面我们发现大部分浏览器都支持vw单位,但是ie9-11不支持vmin和vmax。考虑到vmin和vmax单位并不常用,因此大多数高版本浏览器都很好地支持vw单位。但是opera浏览器整体上并不支持vw单元。如果需要兼容opera浏览器的布局,不推荐vw。摘要:本文介绍布局中常用的单位,如px、%、rem和vw等,以及不同单位在响应式布局中的优缺点。