阅读 231

CSS进阶 - 移动端响应式布局技巧

1. 设备像素、设备独立像素、CSS像素、PPI、devicePixelRatio

1.1 设备像素(物理像素 / 像素分辨率)

  • 显示器的最小物理单位(对于一个显示器来说是固定)
  • 以手机屏幕为例,iPhone像素分辨率为1125x2436,是指屏幕横向能显示1125个物理像素点,纵向能显示2436个物理像素点
  • 通常说的4K显示屏指的是4096x2160
1.2 设备独立像素(dips)
  • 比如我们说的“电脑屏幕在2560x1600分辨率下不适合玩游戏,我们把它调成1440x900”,这里的分辨率指的就是设备独立像素
  • 可在控制台通过window.screen.width/window.screen.height查看
  • 平时我们所说的iPhone X的逻辑分辨率375x812指的就是设备独立像素
  • 一个设备独立像素可能包含多个物理像素,包含的越多,显示越清晰

1.3 CSS像素

  • 在页面不缩放的情况下,1px的CSS像素 === 1设备独立像素
  • 页面放大200%时,页面的设备独立像素依旧不变,放大的是CSS像素。但是此时CSS像素与设备独立像素的关系变化了,1px === 4独立像素(宽x2,高x2)

1.4 PPI

  • 指每英寸的物理像素数
  • 以尺寸为5.8英寸(屏幕对角线长度)、分辨率为1125x2436的iPhone X为例:
  • ppi = Math.sqrt(11251125 + 24362436) / 5.8,值为463ppi

1.5 devicePixelRatio

  • 像素比window.devicePixelRatio
  • devicePixelRatio指的是物理像素和设备独立像素的比,即1独立像素由多少物理像素渲染
  • dpr(device.pixel ratio):设备像素比,设备像素/设备独立像素,代表设备独立像素到设备像素的转换关系,在JS中可以通过window.devicePixelRatio获取
  • window.devicePixelRatio = 物理像素 / 设备独立像素
  • iPhone X的devicePixelRatio是3

1.6 高清屏图片失真

  • 一些像素比较低的图片,在普通显示屏上可以显示,但在高清屏上会出现模糊的现象
  • 原因是:假如一张图片,设置宽高是100px,在不同屏幕上,呈现的都是100个设备独立像素的图片,但是对于高清屏来说,100个设备独立像素所需要的物理像素比普通屏多得多
  • 1个设备独立像素所含的物理像素越多,显示越清晰;假如普通屏100个设备独立像素需要1W个物理像素点,高清屏得3W个。但是图片本身包含的像素点可能远远达不到3W,这个时候,图片就会拉伸自己的像素点,所以看起来就显得模糊
  • 解决办法:高清屏上图片的宽高设小一点,这样所需的物理像素就不用那么多了,屏幕显示图片所需的物理像素越接近图片,图片越清晰

1.7 矢量图永不失真

  • 因为矢量图不是一个个像素点显示的,而是通过给定的坐标数据进行绘制的,所以不会失真

2. layout viewport和visual viewport

  • layout viewport(布局视口)
  • visual viewport(视觉视口)和物理像素
  • ideal viewport(理想视口)和dip(设备独立像素)

3. viewport缩放适配

  • 屏幕的尺寸:window.screen.width // 设备独立像素
  • 浏览器窗口尺寸:window.innerWidth、window.innerHeight // CSS像素

innerWidth/innerHeight不包括滚动条的宽度/高度,精确计算用document.documentElement.clientWidthdocument.documentElement.clientHeight

<!-- meta:vp tab --> 
<meta id="viewport" name="viewport" content="width=device-width; init
ial-scale=1.0;maximum-scale=1.0; user-scalable=no;">
复制代码

移动前端中常说的viewport(视口)就是浏览器显示页面内容的屏幕区域:

  • width:控制viewport的大小,可以指定一个值,比如600,或者特殊的值,比如device-width为设备的宽度(单位是缩放为100%的CSS像素)
  • height:和width相对应,指定高度
  • initial-scale:初始缩放比例,也就是当页面第一次load的时候缩放比例
  • maximum-scale:允许用户缩放到最大比例
  • minimum-scale:允许用户缩放到最小比例
  • user-scalabel:用户是否可以手动缩放

4. 媒体查询@media

语法:@media 媒体类型 逻辑操作符 (媒体属性) {样式代码}

4.1 逻辑操作符

  • and:操作符用来把多个媒体属性组合起来,合并到同一条媒体查询中。只有当每个属性都为真时,这条查询的结果才为真;@media all and (min-width: 700px) and (orientation: lanscape) {...}
  • not:操作符用来对一条媒体查询的结构进行取反;@media not all and (monochrome) {...}
  • only:操作符表示仅在媒体查询匹配成功时应用指定样式,可以通过它让选中的样式在老式浏览器中不被应用;@media only screen and (max-width: 1000px) {...}

4.2 媒体属性

  • width | min-width | max-width
  • height | min-height | max-height
  • device-width | min-device-width | max-device-width
  • device-height | min-device-height | max-device-height
  • aspect-ratio | min-aspect-ratio | max-aspect-ratio
  • device-aspect-ratio | min-device-aspect-ratio | max-device-aspect-ratio
  • color | min-color | max-color
  • color-index | min-color-index | max-color-index
  • monochrome | min-monochrome | max-monochrome
  • resolution | min-resolution | max-resolution
  • scan | grid

4.3 横竖屏

  • @media (orientation: portrait) {竖屏}
  • @media (orientation: landscape) {横屏}

5. vw弹性适配

  • vw1vw等于视口宽度的1%
  • vh1vh等于视口高度的1%
  • vmin:选取vwvh中最小的那个
  • vmax:选取vwvh中最大的那个
  • 视口单位区别于%单位,视口单位是依赖于视口的尺寸,根据视口尺寸的百分比来定义的;而%单位则是依赖于元素的祖先元素

6. 动态rem适配

  • 相对长度单位,相对于根元素(HTML元素)font-size计算值的倍数
  • 根元素HTML默认的font-size16px
  • 为了方便计算,我们一般给父元素的font-size设置为100px
  • 移动端适配rem && vw计算工具:www.jq22.com/demo/jquery…
  // 针对750的设计稿
  function refreshRem() {
      var desW = 750,
          winW = document.documentElement.clientWidth,
          ratio = winW / desW;
      document.documentElement.style.fontSize = ratio * 100 + 'px';
  }
  refreshRem();
  window.addEventListener('resize', refreshRem);
复制代码

7. 弹性flex适配

Flex是Flexible Box的缩写,意为“弹性布局”,用来为盒装模型提供最大的灵活性。

7.1 flex布局的基本概念

采用Flex布局的元素,称为Flex容器(flex container),简称“容器”。它的所有子元素自动称为容器成员,称为Flex项目(flex item),简称“项目”。

容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end。

7.2 容器的属性

  • flex-direction
  • flex-wrap
  • flex-flow
  • justify-content
  • align-items
  • align-content
7.2.1 flex-direction

设置主轴的方向

  • row:主轴的方向是水平,从左到右
  • column:主轴的方向是垂直的,从上到下
  • row-reverse:主轴的方向是水平,从右到左
  • column-reverse:主轴的方向是垂直的,从下到上

7.2.2 flex-wrap
  • wrap:换行
  • nowrap:不换行(默认)
  • wrap-reverse:换行,不过第一行在最下面

7.2.3 flex-flow

flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap

7.2.4 justify-content

属性定义了项目在主轴上的对齐方式

justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly

7.2.5 align-items

align-items属性定义项目在交叉轴上如何对齐

align-items:flex-start | flex-end | center | baseline | stretch

stretch(默认值):如果项目未设置高度或者设为auto,将占满整个容器的高度。

7.2.6 align-content

align-content属性定义了多根轴线的对齐方式,如果项目只有一根轴线,该属性不起作用(也就是说项目得换行)

align-contentflex-start | flex-end | center | space-between | space-around | stretch

7.3 项目的属性

以下6个属性设置在项目上:

  • order
  • flex-grow
  • flex-shrink
  • flex-basis
  • flex
  • align-self
7.3.1 order

属性定义项目的排列顺序,数值越小,排列越靠前,默认为0

7.3.2 flex-grow
  • flex-grow属性定义项目的放大比例,默认为0。即如果存在剩余空间,也不放大。
  • 如果所有项目的flex-grow属性都为1,那么它们将等分剩余空间。
  • 如果一个项目得flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。
.item {
	flex-grow: <number>; /** default 0 */
}
复制代码

7.3.3 flex-shrink
  • flex-shrink属性定义了项目得缩小比例,默认为1,即如果空间不足,该项目将缩小
  • 如果所有项目的flex-shrink属性都为1,当空间不足时,豆浆等比例缩小
  • 如果一个项目的flex-shrink属性为0,其他项目都为1,当空间不足时,前者不缩小
  • 负值对该属性无效
.item {
	flex-shrink: <number>; /** default 1 */
}
复制代码

7.3.4 flex-basis

flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目得本来大小。它可以设为跟width或者height属性一样的值(比如350px),则项目将占据固定空间

.item {
	flex-basis: <length> | auto; /** default auto */
}
复制代码
7.3.5 flex
  • flex属性是flex-growflex-shrinkflex-basis的简写,默认值为0 1 auto。后两个属性可选
  • flex: 0 1 auto; 默认值
  • flex: none; 代表的意思是等同于 flex: 0 0 auto;
  • flex: auto; 代表的意思是 flex: 1 1 auto;
  • flex: number; 当flex取值为一个非负数字,则该数字为flex-grow的值,flex-shrink的值为1,flex-basis的值为0%
7.3.6 align-self

align-self属性允许单个项目可以和其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch

.item {
	align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
复制代码

8. 移动端1px问题的多种解决方法

CSS像素为1px高的直线,对应的物理像素是不同的,可能是2个物理像素或者3个物理像素,而设计师想要的1个物理像素的直线,而设计师要的实际1px的边框就是下面这种情况:

对于CSS而言,可以认为是border: 0.5px;,这是多倍屏下能显示的最小单位。然而,并不是所有手机浏览器都能识别border: 0.5px,有的系统里,0.5px会被当成为0px处理,那么如何1px细线问题呢?

8.1 使用border-image实现

准备一张符合要求的边框图片,样式设置如下:

.border-bottom-1px {
  border-width: 0 0 1px 0;
  -webkit-border-image: url(linenew.png) 0 0 2 0 stretch;
  border-image: url(linenew.png) 0 0 2 0 stretch;
}
复制代码

上文是把border设置在边框的底部,所以使用的图片是2px高,上部的1px颜色为透明,下部的1px使用视觉规定的border的颜色。

优点:可以设置单条、多条边框;

缺点:更换颜色和样式麻烦,需要更换图片;

8.2 使用background-image实现

background-imageborder-image的方法一样,你要先准备一张符合你要求的图片。然后将边框模拟在背景上。

.background-image-1px {
  background: url(../img/line.png) repeat-x left bottom;
  -webkit-background-size: 100% 1px;
  background-size: 100% 1px;
}
复制代码

优缺点与border-image一样;

8.3 多背景渐变实现

background-image方案类似,只是将图片替换为css3渐变。设置1px的渐变背景,50%有颜色,50%透明。

.background-gradient-1px {
  background:
    linear-gradient(#000, #000 100%, transparent 100%) left / 1px 100% no-repeat,
    linear-gradient(#000, #000 100%, transparent 100%) right / 1px 100% no-repeat,
    linear-gradient(#000,#000 100%, transparent 100%) top / 100% 1px no-repeat,
    linear-gradient(#000,#000 100%, transparent 100%) bottom / 100% 1px no-repeat
}
/* 或者 */
.background-gradient-1px{
  background:
    -webkit-gradient(linear, left top, right bottom, color-stop(0, transparent), color-stop(0, #000), to(#000)) left / 1px 100% no-repeat,
    -webkit-gradient(linear, left top, right bottom, color-stop(0, transparent), color-stop(0, #000), to(#000)) right / 1px 100% no-repeat,
    -webkit-gradient(linear, left top, right bottom, color-stop(0, transparent), color-stop(0, #000), to(#000)) top / 100% 1px no-repeat,
    -webkit-gradient(linear, left top, right bottom, color-stop(0, transparent), color-stop(0, #000), to(#000)) bottom / 100% 1px no-repeat
}
复制代码

优点:可以实现单条、多条边框;边框的颜色随意设置;

缺点:增加代码量,圆角没法实现,兼容性问题;

8.4 使用box-shadow模拟边框

利用对阴影处理的方式实现0.5px的效果

.box-shadow-1px {
  box-shadow: inset 0px -1px 1px -1px #c8c7cc;
}
复制代码

优点:代码少,兼容性好;

缺点:边框有阴影,颜色变浅;

8.5 伪元素+transform

构建1个伪元素, border1px, 再以transform缩放到50%

把原先元素的 border 去掉,然后利用 :before 或者 :after 重做 border ,并将 transformscale 缩小一半,原先的元素相对定位,新做的 border 绝对定位。

// 单条border样式设置
.scale-1px{
  position: relative;
  border:none;
}
.scale-1px:after{
  content: '';
  position: absolute;
  bottom: 0;
  background: #000;
  width: 100%;
  height: 1px;
  -webkit-transform: scaleY(0.5);
  transform: scaleY(0.5);
  -webkit-transform-origin: 0 0;
  transform-origin: 0 0;
}
复制代码
// 四条boder样式设置
.scale-1px{
  position: relative;
  margin-bottom: 20px;
  border:none;
}
.scale-1px:after{
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  border: 1px solid #000;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  width: 200%;
  height: 200%;
  -webkit-transform: scale(0.5);
  transform: scale(0.5);
  -webkit-transform-origin: left top;
  transform-origin: left top;
}
复制代码

优点:可以满足所有场景,且修改灵活;

缺点:对于已使用伪类的元素(例如clearfix)要多层嵌套;

8.6 viewport + rem 实现

同时通过设置对应viewportrem基准值,这种方式就可以像以前一样轻松愉快的写1px了。

devicePixelRatio = 2 时,输出viewport

<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
复制代码

devicePixelRatio = 3 时,输出viewport

<meta name="viewport" content="initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no">
复制代码

优点:所有场景都能满足,一套代码可以兼容基本所有布局;

缺点:老项目修改代价太大,只适用于新项目;

9. 图片模糊问题的多种解决方法

在不同的设备像素比下,加载不同分辨率的图片,即加载多倍图片。

9.1 media查询

使用media查询判断不同的设备像素比来显示不同精度的图片:

.avatar{
    background-image: url(conardLi_1x.png);
}        
@media only screen and (-webkit-min-device-pixel-ratio:2){
     .avatar{
          background-image: url(conardLi_2x.png);
      }
}        
@media only screen and (-webkit-min-device-pixel-ratio:3){
     .avatar{
          background-image: url(conardLi_3x.png);
     }
}
复制代码

此方案只适用于背景图

9.2 image-set

.avatar {
    background-image: -webkit-image-set( "conardLi_1x.png" 1x, "conardLi_2x.png" 2x);
}
复制代码

此方案只适用于背景图

9.3 srcset

使用img标签的srcset属性,浏览器会自动根据像素密度匹配最佳显示图片:

<img src="conardLi_1x.png"  srcset=" conardLi_2x.png 2x, conardLi_3x.png 3x">
复制代码

9.4 JavaScript拼接图片URL

使用window.devicePixelRatio获取设备像素比,遍历所有图片,替换图片地址:

const dpr = window.devicePixelRatio;

const images =  document.querySelectorAll('img');

images.forEach((img)=>{
  img.src.replace(".", ‘@${dpr}x.’); 
})
复制代码
文章分类
前端
文章标签