knowledge

响应式相关

目录

  1. WAP端适配总结
  2. 响应式页面解决方案
  3. 基本概念、术语
  4. px转rem方案
  5. 响应式设计
  6. 不同PPI的设备使用不同分辨率的图片
  7. 放大模式下的适配(取消系统放大方案)

WAP端适配总结

  1. 一份支持响应式页面的PSD设计稿、或多份具体响应式细节的PSD设计稿(少见)。
  2. 宽屏:按比例放大项、或增加项数量。
  3. <meta>的viewport值方案:理想视口方案、或1/DPR缩放方案。
  4. 响应式设计三大要素:媒体查询、流式布局、弹性图片。
  5. 不同PPI使用不同分辨率图片
  6. font-size阶梯取值方案(位图字体):CSS媒体查询额外设置方案、或JS设置html的data-dpr统一控制方案。
  7. 半像素处理
  8. rem+@media方案
  9. 雪碧图使用百分比background-position
  10. 使用rem导致的CSS小数、百分比的四舍五入问题处理
  11. 自适应宽度布局flex优雅解决布局、自适应问题)。
  12. 是否横竖屏切换显示(特殊单屏应用,如:游戏)。

响应式页面解决方案

适配布局(与设计师协作思路)

  1. 使用vm(或vh

    参考:大漠:再聊移动端页面的适配

    1. 设置为理想视口:

      <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">

    2. vw(或vhvminvmax)设置html的font-size

       :root {
         --psd: 设计稿宽度px;  /* 无单位 */
         --rfz: 缩小倍数;      /* 无单位。可以设置为100:方便计算、也因为PC浏览器通常都有最小字体限制 */
       }
       html {
         /* 单位:vw */
         font-size: 具体vw;                                /* 兼容性 */
         font-size: calc(100vw / 设计稿宽度px * 缩小倍数);  /* 兼容性 */
         font-size: calc(100vw / var(--psd) * var(--rfz));
       }
      
      1. 若原本是PC页面而增加的WAP适配,就在html外添加媒体查询。
      2. 若要限制最大宽度(或高度)的页面,可以媒体查询限定html的font-size具体px >要限制最小宽度(或高度)同理,改变`min-`为`max-`、改变`最大`为`最小`。 ```css /* 在上面的基础上增加媒体查询限制最大宽度 */ @media (min-width: 最大宽度px) { html { /* 单位:px(不能换算成rem) */ font-size: 具体px; /* 兼容性 */ font-size: calc(最大宽度px / 设计稿宽度px * 缩小倍数); /* 兼容性 */ font-size: calc(最大宽度px / var(--psd) * var(--rfz)); } } /* 或 */ @media (min-height: 最大高度px) { html { /* 单位:px(不能换算成rem) */ font-size: 具体px; /* 兼容性 */ font-size: calc(最大宽度px / 设计稿宽度px * 缩小倍数); /* 兼容性 */ font-size: calc(最大高度px / var(--psd) * var(--rfz)); } } ```
    3. 元素用设计稿的px除以缩小倍数(--rfz),单位用rem(手动计算或px转rem方案)。

      原理思路:把设计稿转化为宽度的百分比(vw)显示在移动端上。 - 针对1080px的设计稿,初始设定:`--psd: 1080; --rfz: 100;`: 300px的设计稿距离计算如下 1. 1080px设计稿中300px占用:`300px / 1080px ≈ 0.278`; 2. 300px的设计稿距离写成CSS为:`300 / var(--rfz) + rem => 300 / 100 + rem = 3rem`; `3rem => 3 * html的font-size => 3 * calc(100vw / var(--psd) * var(--rfz)) => 3 * 100vw / 1080 * 100 ≈ 27.8vw`; 3. `27.8vw === 设计稿宽度的0.278`,从而设计稿对应了响应式页面。
  2. 已过时的方案 1. [flexible方案](https://github.com/amfe/lib-flexible) >类似的还有:[hotcss](https://github.com/imochen/hotcss)。 1. 用JS动态设置`的viewport`缩放比为`1/DPR`,解决0.5px问题。 >缩放比例`1/DPR`原因:在这个缩放比例下,**CSS中的1px设备独立像素**等于**屏幕的1px物理像素**。事实上取消了px作为设备独立像素的含义,变成物理像素的值。能够画出1px物理像素的内容。 2. 用JS根据**不同布局视口宽度**动态设置**html的font-size值**,把要做成响应式的内容转换为rem单位。 把视觉稿分成100份来看待(为了以后兼容vh,vw单位)。每一份被称为一个单位a,1rem单位认定为10a。拿750px宽度的视觉稿举例:`750px = 100a => 75px = 10a = 1rem => 1rem = 75px`,因此当设计稿宽度为750px时,量取的长度要除以75并加上rem单位。 3. 用JS在``上动态设置**data-dpr**,对额外需要根据DPR变化而改变的内容设置样式(如:字体)。 ```scss @mixin font-size($font-size) { font-size: $font-size; [data-dpr="2"] & { font-size: $font-size * 2; } [data-dpr="3"] & { font-size: $font-size * 3; } } ``` >因为字体很多都是点阵字体或位图字体,通常有16px、24px的清晰字号,其他字号大小是位图缩放的结果,有损美观。 - 不需要设置~~媒体查询改变html的font-size值~~。 2. **媒体查询**设置**不同布局视口宽度**下**html的font-size值**,把要做成响应式的内容转换为rem单位 1. 设置为理想视口: ``。 >若改变布局视口(放大),则只需媒体查询内容添加更大布局视口下html的font-size值。 2. 切图取值用**设计稿的px带入下面方法而生成的rem值**。 ```scss /* 用Sass预处理语言换算px -> rem */ @function rem($px, $base-font-size: 20px) { @if unitless($px) { @return rem($px + 0px); } @if unit($px) != "px" { @error "rem()的参数单位必须是px或不带单位"; } // $base-font-size:切图时设计稿宽度对应的媒体查询中html的font-size @return $px / $base-font-size + rem; } ``` 3. 媒体查询仅设置[不同布局视口宽度下html的的font-size值](https://github.com/realgeoffrey/knowledge/blob/master/网站前端/初始化模板/@media设置html的font-size.md)。 >0.5px问题用[WAP端半像素](https://github.com/realgeoffrey/knowledge/blob/master/网站前端/HTML+CSS学习笔记/实现具体业务.md#wap端半像素)处理,或直接设置为1px。 </details>

当Android系统的样式出现问题又找不到原因时,有可能是系统字体大小被修改过。

基本概念、术语

  1. 视口(viewport)

    网站外层的容器,控制网站的最高块状容器:<html>

    1. PC端的viewport就是浏览器窗口的宽度高度,严格等于浏览器的窗口。

      PC端无视<meta>的viewport设置。

    2. WAP端的viewport太窄,为了能更好为CSS布局服务,所以提供了两个viewport

      1. 可视视口(visual viewport):

        浏览器的窗口,可以放大缩小、滚动页面来改变可见部分。

        1. 通过<meta name="viewport" content="initial-scale=缩放值, user-scalable=是否缩放, minimum-scale=缩放值, maximum-scale=缩放值">控制缩放。

          视觉上,可视视口永远是浏览器大小,但宽度值等于逻辑像素宽度。

          可视视口宽度(屏幕范围内CSS像素堆积的总宽度) = 浏览器宽度 / 现在的缩放值

        2. JS获取:window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight

          随页面缩放而改变。

      2. 布局视口(layout viewport):

        网站外层容器的固定大小,决定<html>宽度。不同浏览器默认大小不同,980px左右;不能小于可视视口。

        1. 通过<meta name="viewport" content="width=布局视口初始宽度值, initial-scale=缩放值">设置并缩放成为最终布局视口宽度。

          布局视口宽度 = 初始宽度值 / 初始缩放值 > 可视视口宽度 : 初始宽度值 / 初始缩放值 ? 可视视口宽度

        2. JS获取:document.documentElement.clientWidth || document.body.clientWidth

          随写入的viewport的宽度值 / 初始缩放值改变而改变。

        3. CSS媒体查询判断:@media (min-width: 宽度px) and (max-width: 宽度px)

          随写入的viewport的宽度值 / 初始缩放值改变而改变。

      概念理解 想象下layout viewport是一张大的不能改变大小和角度的图片。现在你有个更小的框来观看这张大图片,这个框被不透明的材料包围,因此你只能看到大图片的一部分。你通过这个框看到的大图片的部分被称为visual viewport。你能拿着这个框站得离大图片远点(用户的缩小页面功能),以一次性看到这个大图片的更多区域;或你能站得近点(用户的放大页面功能),以看到更少区域。你能改变这个框,但这张大图片的大小和形状都不会改变。
      • 理想视口(ideal viewport):<meta name="viewport" content="width=device-width,initial-scale=1.0">

        1. 可视视口,初始不缩放。
        2. 布局视口,设置为屏幕宽度。
  2. 像素(pixel)

    像素是数字图像的最小组成单元,它不是一个物理尺寸,但和物理尺寸存在一个可变的换算关系(物理尺寸之间的换算是固定的),也是分辨率的单位。

    1. CSS像素(前端用的px

      viewport的像素。浏览器内部对逻辑像素进行再处理的结果(调整逻辑像素的缩放来达到适应设备的一个中间层)。

      width=device-width:让viewport的宽度等于逻辑像素的总宽度。

    2. 设备独立像素(Device-Independent Pixels,DIPs),密度无关像素(Density-Independent Pixels,DIPs)

      逻辑像素,一种度量单位。由程序使用的虚拟像素,然后由相关系统转换为物理像素呈现。

      iOS用pt(point),Android用dp(density-independent pixel),前端用px

    3. 物理像素(physical pixels),设备像素(device pixels)

      1. 对物理显示设备而言,是固定的。反映显示设备内部led灯的数量,由操作系统控制来发光填色值。
      2. 对系统层面而言,是系统解析后提供给应用展示的。所以改变屏幕分辨率后,应用面对的物理像素也改变了。

    e.g. iPhone 13 Mini的渲染像素是1125x2436,对应的逻辑像素是375x812@3x(css或js获取的像素也是这个逻辑像素值),但是它的物理像素是1080x2340(特殊,设计成渲染分辨率和物理分辨率不一致)。

  3. 比例

    1. DPR(Device Pixel Ratio,设备像素比)、dppx(dots per pixel,每物理像素包含的逻辑像素数量)、dpi(dots per inch,每英寸包含逻辑像素数量)

      DPR = 物理像素 / 设备独立像素1DPR = 1dppx = 96dpi

      1. JS获取:window.devicePixelRatio
      2. CSS媒体查询:@media (min或max-resolution: 整数dppx)@media (min或max-resolution: 整数dpi)
      1. 改变浏览器缩放,会改变DPR。
      2. 对于固定的逻辑像素,当系统分辨率改变时(导致物理像素变化),DPR不变。
    2. PPI(Pixels Per Inch,每英寸物理像素,物理像素密度)

      PPI = Math.sqrt(物理像素宽的平方 + 物理像素高的平方) / 屏幕对角线长度的英寸

      表示每英寸所拥有的物理像素数目。

  4. 主屏分辨率

    物理像素(或系统提供的、被当做物理像素的值)的宽x高。

px转rem方案

rem:相对于根元素的字体大小的单位。rem单位转换为具体px值:rem乘于html的font-size像素

  1. SCSS在.scss文件进行

     @function rem($px, $base-font-size: 20px) {
         @if unitless($px) {
             @return rem($px + 0px);
         }
         @if unit($px) != "px" {
             @error "rem()的参数单位必须是px或不带单位";
         }
    
         // $base-font-size:切图时设计稿宽度对应的媒体查询中html的font-size 或 --rfz+px
         @return $px / $base-font-size + rem;
     }
     a {
         width: rem(20);
     }
    
     /*
     a {
         width: 1rem;
     }
     */
    
  2. px2rem(或px2rem-postcss)在.css文件进行

     /* px2rem设置:remUnit: 20,baseDpr: 1 */
     a {
         width: 20px;
         height: 40px;   /*px*/
         padding: 60px;  /*no*/
         margin: 80PX;
     }
    
     /*
     a {
         width: 1rem;
         padding: 60px;
         margin: 80PX;
     }
     [data-dpr="1"] a {
         height: 40px;
     }
     [data-dpr="2"] a {
         height: 80px;
     }
     [data-dpr="3"] a {
         height: 120px;
     }
     */
    

响应式设计

  1. 媒体查询方式
    1. CSS属性:

      @media (min-width: 360px) and (max-width: 640px) {...}

    2. HTML标签:

      <link rel="stylesheet" type="text/css" media="(min-width: 360px) and (max-width: 640px)" href="...">

  2. 响应式设计三大要素
    1. 媒体查询
    2. 流式布局:节点用百分比remflexgrid布局

      使用自适应结构,如:自适应宽度布局

    3. 弹性图片:img {max-width: 100%;}

不同PPI的设备使用不同分辨率的图片

  1. @1、@2、@3不同分辨率的图片放大倍数是1倍、2倍、3倍
  2. 若图片是雪碧图

    1. 则其间距也要是和放大倍数一致,@1、@2、@3分别间距是2px、4px、6px
    2. 则其background-size设置为最低分辨率整个雪碧图的高宽)、background-position设置为最低分辨率时的值。单位用pxrem百分比都可以。
  1. 媒体查询

     @mixin image($url) {
         background-image: url($url + "@1.png");
    
         @media (min-resolution: 2dppx) {
             background-image: url($url + "@2.png");
         }
    
         @media (min-resolution: 3dppx) {
             background-image: url($url + "@3.png");
         }
     }
    
     .img {
         @include image("去除后缀的图片地址");
     }
    
  2. <img>的一些属性:srcsetsizesbackground-image的值:image-set()
  3. SVG(矢量图)代替位图使用

放大模式下的适配(取消系统放大方案)

iOS、Android可以在系统设置中修改字体大小视图大小/显示大小,会导致H5页面的样式数值发生变化(PC版的缩放同理)。

解决方案:利用 html的font-size + 元素的font-size用rem单位、元素的其他样式属性数值不要用 rem 单位(e.g. 用vwpx、等) 的响应式方案,并根据系统放大/缩小的倍数,对html的font-size进行逆向处理:

  1. 先设置某节点font-size值,再获取该节点真实font-size值,他们的倍数就是系统放大/缩小的倍数,需要逆向处理这个倍数;
  2. 获得前面的倍数,若放大/缩小多少,则html的font-size等效缩小/放大多少;

    e.g. 一开始设置50px;计算得到100px,得知放大了2倍,这时再最终设置为25px。节点的1rem=1rem x 25px x 2倍=50px,与一开始1rem=50px的期望相同。

  3. 节点的font-size数值用rem,其他样式属性数值不要用 rem(可以用vw的响应式方案);

    因为其他样式属性数值,用rem时,某些机型跟随系统变化,某些机型又不跟随,但是用vwpx等其他单位时还未发现会跟随变化。

  4. 规避系统通过其他方式放大/缩小页面的手段(e.g. iOS会通过text-size-adjust同步系统放大/缩小)。
实现 ```html 节点的font-size数值都用rem作为单位,节点的其他样式属性数值不要用rem,可规避系统导致的放大/缩小(就是使系统导致的变化失效) ``` [CodePen demo](https://codepen.io/realgeoffrey/pen/YzLbvRo)

非纯前端解决方案:让客户端打开WebView时就禁止变化字体大小视图大小/显示大小。e.g. WebView初始化时客户端设置textZoom: 100