响应式或自适应布局的流派

2024-09-30 07:41:49 浏览数 (1)

响应式或自适应布局的流派

(此图有可能名称反了,但不重要,我个人更偏向于 bootstrap 被叫作响应式的)

本文旨在罗列实现响应式或自适应布局的几种方案。

前言

四种设备:移动端、PC 端、超大屏、高清屏

两种环境:没 device-width、有 device-width

其他注意事项:毛细线、多端兼容、设计稿还原精度

在 @media  出现之前,大家是怎么过的呢?

PC 页面大多是给容器定宽的,手机上屏宽等于定宽,想看清内容就得靠缩放拖拽。

弊端在哪呢,每进一页就要放大一次,PC 端与移动端设计必然多套。

栅栏布局 方案

随后 @media  和  viewport device-width 的组合拳之下,偷懒的方案栅栏布局横空出世。

如果将元素或内容看作是一个个的区块,那么搬运一下位置岂不是挺方便的嘛,

将宽度分为 12 栏,左边占 3 栏,中间占 7 栏,右边占 2 栏;

当宽度变小时,左边占 12 栏跑到上面去,中间占 9 栏,右边占 3 栏,相应变化。

且  device-width 自动会让文字跟随屏幕放大,

原本 PC 端 3 栏的内容,到移动端看到 12 栏的内容,一眼所能看到的信息量是相近的。

很明显,栅栏布局能非常方便且粗浅的处理 PC 端与移动端的样式调整,

字体大小会变大,适合小屏设备阅读,多端简单地适配操作非常简单。

但依旧有着问题,比如专注于小屏设备的话误差很大,专注于超大屏的话还缺些火候。

em 方案

本方案算是优化的一类,可以稍稍弥补上述所说的大小屏问题。

虽然有着  device-width 文字得到了放大,

但 320px 小屏中的 12px 与 414px 小屏中的 12px 视觉上还是有较大差异的。

那么,用 em 去跟随这些细小的适配粒度,再放大一次呢。

代码语言:html复制
html { font-size: 10px; }
@media screen and (min-width: 321px) and (max-width: 375px) {
  html { font-size: 11px; }
}
@media screen and (min-width: 376px) and (max-width: 414px) {
  html { font-size: 12px; }
}
@media screen and (min-width: 415px) and (max-width: 639px) {
  html { font-size: 15px; }
}
@media screen and (min-width: 640px) and (max-width: 719px) {
  html { font-size: 20px; }
}
@media screen and (min-width: 720px) and (max-width: 749px) {
  html { font-size: 22.5px; }
}
@media screen and (min-width: 750px) and (max-width: 799px) {
  html { font-size: 23.5px; }
}

说实话,设定字体大小、边距间隙、定宽定高、动画位移,需要用到 px 的场景并不太多,

前两者甚至可以统一公共类来完成,所以随着 em 缩放一些,能够比较粗浅轻易的适配更小的粒度。

还带来了一个蛮有意思的效果,在只有 px 的时候,宽度变化想要高度也变化是困难的,

而宽度随 em 变化时,如果高度也写成 em 那就很妙了。

但这也有点小问题,就是 em 中的 em 其实是翻倍,这计算量可就哦豁了。

rem 方案

如果 em 会面临嵌套后多倍计算的话,直接用 rem 不就好了吗。

再进一步,em 方案中根节点的字体大小能否直接不用 @media  而用 js 来实现,

这也便造就了 lib-flexible 等插件的出现。

而 px2rem 或 postcss-pxtorem 等工具也让开发不用侧重于写 rem 而是写 px 了。

主要代码

代码语言:js复制
function flexable(remRatio = 75) {
  function setRem() {
    var winW = docEl.getBoundingClientRect().width;
    $style.innerText = 'html{font-size:'   (docEl.style.fontSize = winW / remRatio   'px')   ' !important;}';
  }
  var win = window,
    doc = document,
    docEl = doc.documentElement,
    $style = doc.createElement('style');
  doc.head.appendChild($style);
  setRem();
  win.addEventListener('resize', setRem, !1);
}

flexable(7.5); // 7.5rem = 100vw

postcss-px-to-viewport

代码语言:js复制
module.exports = {
  plugins: {
    autoprefixer: {},
    'postcss-px-to-viewport': {
      unitToConvert: 'px',
      viewportWidth: 10000,
      unitPrecision: 5,
      propList: ['*'],
      viewportUnit: 'rem',
      fontViewportUnit: 'rem',
      selectorBlackList: ['.ignore'],
      minPixelValue: 1,
      mediaQuery: false,
      replace: true,
      exclude: [],
      landscape: false,
      landscapeUnit: 'rem',
      landscapeWidth: 568,
    },
  },
};

改动 viewport

https://foreverz133.github.io/demos/works/lib-flexible/js/lib-flexible.js

众所周知,小数和单数的尺寸数值其实并不精准,甚至 1px 就能造成 float 布局的错位,

而 rem 方案中转化为实际 px 其实相当多情况都是小数,所以会更注重毛细线效果的结果。

而  initial-scale 一定程度上可以稍稍减小误差的概率。

也能让高清屏得到  initial-scale 放大,显得更清晰细致(不包括图片)。

代码语言:js复制
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
  // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
  if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
    dpr = 3;
  } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
    dpr = 2;
  } else {
    dpr = 1;
  }
} else {
  // 其他设备下,仍旧使用1倍的方案
  dpr = 1;
}
scale = 1 / dpr;
metaEl.setAttribute(
  'content',
  'initial-scale='   scale   ', maximum-scale='   scale   ', minimum-scale='   scale   ', user-scalable=no'
);

body 的 font-size

在很多插件中,body 的 font-size 会被设置为 12 * dpr 的大小。

而如果将其设为 12rem 的话将出现一种很优秀的效果。

就是 Ctrl 加号 去缩放屏幕时,并不会改变视图。

vw 方案

然而当开始使用 rem 后你会发现一个问题, @media  不再那么有效了,

那么我想用  @media(min-height: 414px)  或 @media(min-height: 414rem)  去调整些什么都是不可行的。

vw 方案则比较好地能部分解决这个问题,毕竟它并没有改变什么比例基准。

而 initial-scale 也可以靠  @media(min-device-pixel-ratio)  来搞搞。

可以说 vw 方案其实要比 rem 方案更应该被推崇,至少大漠也这么认为。

但是吧,rem 方案 和 vw 方案,在非全屏宽布局中其实都不太 OK。

代码语言:html复制
.container {
  width: 1280px;
  margin-left: auto;
  margin-right: auto;
}

pt 方案

以上方案,都用到了 viewport 的  device-width 来进行屏幕宽度的响应,而 pt 方案则不然。

代码语言:html复制
<meta name="viewport" content="user-scalable=no" />
代码语言:css复制
@function px($px, $designWidth: 750) {
  @return (735 / $designWidth) * $px * 1pt;
}

它有着 rem 方案类似的效果,但不需要修改根节点字体大小。

比如:此处的 px(375, 750) 相当于 50vw。

不过,此方案在屏宽大于 980px 后就没用了,因此只适用于手机端。

以前有试用过三个月,没有出现过纰漏,感觉也是个非常有效的方案。

具体原理不详,原文来自于 移动端 HTML 响应式布局之神奇的 pt。

其实这和流行 viewport 前的原始形态很相似,也是字体大小会随屏幕缩放,

但有个比例尺后,就和设计稿尺寸对应上了,妙哉妙哉。

固定视图 方案

代码语言:html复制
<meta name="viewport" content="width=750,user-scalable=no" />

此方案就很骚了,直接改 viewport 其他都按 px 来。

不搞什么自动间隙,什么左右靠齐,就是固定宽,开发起来贼舒服。

以前试用了半年多,用于移动端也完全没问题,PC 端有极少设备不能用。

百分比定位

其实这是最常见的响应式方案了,只是并不处理文字而已。

所以仅有图片等元素的很多活动 H5 就直接用百分比绝对定位来实现自适应了。

scale 缩放居中

以上方案都是根据屏宽来产生响应的,那么有没有办法以容器宽度来响应的呢。

很遗憾,要么 iframe 要么 transform 的 scale 来实现了。

比如一个游戏界面,只要固定的宽高不超出屏幕,居中就完事了。

代码语言:js复制
function initWindowSize(designWidth = 750, designHeight = 1334) {
  var winW = window.innerWidth;
  var winH = window.innerHeight;
  var $body = $('.container');
  var ww, hh;
  if (winW / winH < designWidth / designHeight) {
    ww = winW;
    hh = (designWidth / designHeight) * ww;
  } else {
    hh = winH;
    ww = (designWidth / designHeight) * hh;
  }

  var scale = ww / designWidth;
  $body.css('transform', 'scale('   scale   ')');
}

而且此方案特别适合横屏应用,是改造量最少的方案。

腾讯技术创作特训营s9其他文章

「学习NestJS的第一个接口(一)」

「学习NestJS开发小程序后台(一)」

「学习NestJS开发小程序后台(二)检测图片敏感内容」

0 人点赞