Skip to content

响应式设计专刊

适配方案

一般而言,常用的有以下几种适配方案。当然前提是都要先设置好viewport,一般是initial-scale为1。之前也有了解实践过在dpr为2或3时设置initial-scale为.5或是.33,可是我还是觉得没什么必要哎…或许是没有领会到这样设置的用途。

全军px系列

即padding,font-size。margin都以px为单位,优点是方便,在大屏下也显得蛮优雅的,缺点是不少地方不能写死,比如宽度尽可能的按百分比来,等分定位的话可以用flex等。

现在的 vw/vh 系列

px2viewport 就 ok 方便控制其他的引入组件。

 module: {
    rules: [
      {
        test: /\.(less|css)$/,
        use: [
          { loader: 'style-loader' },
          { loader: 'css-loader' },
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  'postcss-preset-env',
                  {
                    'postcss-px-to-viewport': {
                      unitToConvert: 'px',
                      viewportWidth: 750,
                      unitPrecision: 6,
                      propList: ['*'],
                      viewportUnit: 'vw',
                      fontViewportUnit: 'vw',
                      selectorBlackList: ['wrap'],
                      minPixelValue: 1,
                      replace: true,
                      // 注:下面有问题,只处理组件包就 ok 了
                      // exclude: [/node_modules/],
                      // include: [/\/node_modules\/antd-mobile\//],
                      landscape: false,
                    },
                  },
                ],
              },
            },
          },
          {
            loader: 'less-loader',
            options: {
              lessOptions: { javascriptEnabled: true },
            },
          },
        ],
      },
    ],
  },

注意 viewport 这里是 750。一般组件库会以 375 为 base,像 antd-mobile 亦提供了 750 为 base 的引入版本。

rem系列

用rem的话,根字体大小一般以屏幕css宽度/10来计算,当然也有不同的实践。优点是任何定位都可以根据rem写死…毕竟可以理解成不同的屏幕大小整个就是一等比缩放。字体可以按rem,也可以按px。缺点是pad下会显得过于大了。

脍炙人口的flexible.js设置方案如下:

(function flexible (window, document) {  
  var docEl = document.documentElement  
  var dpr = window.devicePixelRatio || 1  

  // adjust body font size  
  function setBodyFontSize () {  
    if (document.body) {  
      document.body.style.fontSize = (12 \* dpr) + 'px'  
    }  
    else {  
      document.addEventListener('DOMContentLoaded', setBodyFontSize)  
    }  
  }  
  setBodyFontSize();  

  // 关键拉 set 1rem = viewWidth / 10  
  function setRemUnit () {  
    var rem = docEl.clientWidth / 10  
    docEl.style.fontSize = rem + 'px'  
  }  

  setRemUnit()  

  // reset rem unit on page resize  
  window.addEventListener('resize', setRemUnit)  
  window.addEventListener('pageshow', function (e) {  
    if (e.persisted) {  
      setRemUnit()  
    }  
  })  

  // detect 0.5px supports  
  if (dpr >= 2) {  
    var fakeBody = document.createElement('body')  
    var testElement = document.createElement('div')  
    testElement.style.border = '.5px solid transparent'  
    fakeBody.appendChild(testElement)  
    docEl.appendChild(fakeBody)  
    // offsetHeight是包括border的,所以由此判断  
    if (testElement.offsetHeight === 1) {  
      docEl.classList.add('hairlines')  
    }  
    docEl.removeChild(fakeBody)  
  }  
}(window, document))

ps: 实现极细border

0.5px的border又称为hairlines。那么当然要先判断当前浏览器资不资词0.5px的border-width,这个在上面的flexible.js里就包括拉!如不支持,可通过其他方式实现极细border的方案,主要有两种:一是按border来写,另一是不按border来写…

依然按border来写的话,可以①通过border-background设置一半透明一半有线的背景。②将viewport缩小一倍,即initial-scale=.5。

不按border来写的话,即各种伪造border。比如在::after里面放一个1px高的div线再scale(0.5)阿,通过border-image来乔装阿…这种。

历史调研

美团

image-20230227145223392

375宽度 html的font-size: 31.25px

320宽度font-size: 26.67px

值得借鉴之处:

整个主要部分被一个wrapper包了起来:(max-width: 12rem 约414px)/…如果我scale .5的话就大概是820px。这样可以保证pc网页打开宽度也不会太宽。那么html的font-size当然就是以这个wrapper的宽度来计算。

----我自己试了了一下 其余的挺好 有两个需要注意的点

①fixed-position定位的元素

width 100%的话会变成全屏那么长

②scale必须是1!因为viewport只在手机页面上才生效,而这个wrapper的max-width表示的应该是pc页面和手机页面的临界值。而pc页面的显示效果就是1:1。如果按我scale .5的话 换算成手机页面width 都有六七百宽 岂不是都比414px大了,如果还要再加上一条区分是否pc/mobile页面的条件来动态改变wrapper的max-width的话 又略显麻烦了

知乎

image-20230227145259169

采用 px 的方式,如果是 iPad 的话采取 pc 端样式

我的疑惑:岂不是大屏显示的字一行多 小屏显示的一行字少?那么做“xxxx....”这样截取某些字数时,字数要如何选择呢?唔…果然不同屏幕多少行不固定的!

手淘

image-20230227145342865

375宽度:112.5px 就是10: 1*3的关系!手淘有设置根font-size,但是计算方案比较不同,iPhone6对应的html的font-size是100px,另外布局中的样式几乎都是实时计算出来的行内样式,单位px。

至于为什么要设计成33.3% 意为放大三倍 那么是为了考虑到dpr为3的比如iphone6这种手机 字体和css控制的东西不会有问题 但是图片可能就会放大而显得模糊了。

这样子设计的话 一个小logo图很可能就是200px多 所以可以实现在iphone上的1:1展示。

不过其实嘛 图片做大一点就好咯!

天猫

image-20230227145411365

375宽度:37.5px 就是10:1的关系!

手机京东

https://m.jd.com/ 终于找到用rem方案的了!并且是全rem形式。不过京东的根字体大小是根据media query设置的:

@media only screen and (min-width:320PX) and (max-width:360PX){html{font-size:13.65px}}  
@media only screen and (min-width:360PX) and (max-width:375PX){html{font-size:15.36px}}  
@media only screen and (min-width:375PX) and (max-width:390PX){html{font-size:16px}}  
@media only screen and (min-width:390PX) and (max-width:414PX){html{font-size:16.64px}}  
@media only screen and (min-width:414PX) and (max-width:640PX){html{font-size:17.664px}}  
@media screen and (min-width:640PX){html{font-size:27.31px}} 

4. Refs

完全理解px,dpr,dpi,dip

Android屏幕适配:最全面的解决方案

再聊移动端页面的适配

如何在Vue项目中使用vw实现移动端适配