响应式开发,还原视觉稿px,vw,rem如何选择?

560 阅读5分钟

加入公司以来,都是参与已有旧项目的功能迭代和维护,一直没有从0到1搭建过一个项目。所以每次接到一个需求之后就机械化的当切图仔(量ui稿尺寸,还原)根据ui稿还原页面和功能。

有时候会注意到,都是需要做响应式开发,有的项目运行后还是px,有的项目则会转成rem,或者vw单位。

而且视觉上差不多大小,有的项目ui稿单位的单位很大,而有的则正常。比如一个视觉上看着一样大小的字体,在这A项目里面量出来上12pxB项目里面量出来就变成了24px,然后最后页面上呈现的效果又是一样的大小。

疑问

  1. 为什么不同UI稿之间为什么量相同大小的组件(px)大小为什么会有差距。
  2. 为什么有的项目会将单位转成rem,有的项目转成vw,有的则保持px
  3. 我构建项目的时候该如何去选择单位(px,rem,vw)去做响应式开发以及以及不同的设计稿我该如何还原?

研究

疑问1

对于疑问1,之前一直有一个误区:

css单位的px===设计稿上的px

而其实仔细想想就能发现,设计稿的的大小是固定的,而用户的屏幕大小则不固定,那么实际稿(固定)大小是多少呢?

回过头去看发现,A项目设计稿总宽度为375px,而B项目设计稿宽度则为750px,欸...这不刚好两倍关系吗?那么其实A项目设计稿的1px是等于B项目设计稿的2px,所以打开页面A项目应该在375px屏幕尺寸下看才能完整还原设计稿。

疑问2,3

要搞清楚项目如何选择px,rem,vw等单位,那么首先应该搞清楚他们原理。

了解了真相,你才能得到真正的自由![旺柴]

看到这些单位,其实作用都清楚,响应式布局,说说都是如何做的?

1. px

css基础单位,不具备响应式能力,但是可以结合另一个可能会忽略的布局%,基本组件固定px+%布局实现自适应。

比如类似下面这种布局方式,组件不随屏幕大小变化而响应式变化,但是页面整体内容不会因为屏幕尺寸改变打乱布局,我总结了一下必须满足下面条件(欢迎补充)

  1. 没有比如flex,grid之类的多列自适应的布局(布局大小不会改变内部组件尺寸和间距)

image.png

2. rem

rem: 相对于根元素的字体大小。例如:

html { font-size: 16px; }
div { width: 10rem; } /* 10rem = 160px */

核心原理,只要根据根元素font-size随屏幕的宽度变化,页面所有使用rem的元素都会按照比例缩放,实现全部元素响应式。

移动端响应式关键原因

移动端屏幕差异大:

  • iPhone SE 320px
  • iPhone 13 390px
  • iPad 768px

如果直接用 px,布局固定,低分辨率小屏幕会溢出,高分辨率大屏幕显得小。

现在常用的计算公式:

                         屏幕宽度
     Html font-size = -------------     
                            10 

例如根据上面提到的A项目375px的设计稿

实现有两种方案:

  1. js动态计算
  function setRemUnit () {
    var rem = docEl.clientWidth / 10
    docEl.style.fontSize = rem + 'px'
  }

  setRemUnit()

  1. css媒体查询(固定区间)
html { font-size: 16px; }
@media (max-width: 375px) {
  html { font-size: 14px; }
}
@media (min-width: 376px) and (max-width: 768px) {
  html { font-size: 18px; }
}

接下来再通过postcss-pxtorem将px转换为rem

{
 rootValue: 37.5,
 unitPrecision: 5,
 propList: ['*'],
 selectorBlackList: [],
 replace: true,
 mediaQuery: false,
 minPixelValue: 0,
 exclude: /node_modules/i
}

如上面根据postcss-to-rem将375px设计稿转换逻辑和上面公式差不多,比如一个12px的尺寸,转换rem

                         12
                   ---------------   =  0.32rem
                        37.5

实验一下:


.container {
  font-size: 12px;
  width: 150px;
  height: 150px;
  background: skyblue;
  display: flex;
  justify-content: center;
  align-items: center;
  color: aliceblue;
}

这里用font-size12px来计算,

     12 / 37.5 = 0.32rem

结果,符合预期。

image.png

这样rem + js的响应式方案就完整了。

3. vw

vw是视口百分比, 1vw = 视口宽度的1%。

转换公式

                      px    
     px -> vw = ------------- ✖️ 100px       
                   设计稿宽度

那用vw相比rem做响应式开发就变得非常简单了,不需要js计算,不需要媒体查询,和postcss-to-viewport计算逻辑完美契合,一步到位,轻松实现响应式开发。

{
  unitToConvert: 'px', // 原始单位
  viewportWidth: 375,  // 设计稿尺寸
  unitPrecision: 5, // 保留5位小数
  propList: ['*'],
  viewportUnit: 'vw', // 转换后的视口单位
  fontViewportUnit: 'vw', // 转换后的字体单位
  selectorBlackList: [],
  minPixelValue: 1,
  mediaQuery: false,
  replace: true,
  exclude: undefined,
  include: undefined,
  landscape: false
}

配置完成之后启动项目。

image.png

总结

remvw都是实现响应式布局的,px需要结合%实现响应式布局。

区别:

px+%只能实现布局响应式,页面内元素不会随屏幕大小发生变化而变化。

优点: 任何屏幕尺寸下都能保证页面内组件和设计稿的完整还原。

缺点: 有局限性, 如上。

remvw则是布局和页面元素都会随屏幕变化而响应式变化。

优点:没有对布局的局限性,任何场景都能用。

缺点: 在移动端横屏情况下字体和元素会拉升的比较大,不协调(其实就是不可用,在移动端横屏和平板情况下)。

---------------------补充---------------------

rem之前常用flexible.js来定制根元素fontsize,目前也不建议推荐使用,建议使用viewport方案。因此,在remvw选择上,直接使用vw即可。

image.png