likes
comments
collection
share

你没事吧?没事就来看看这篇响应式方案

作者站长头像
站长
· 阅读数 62

涅槃计划CSS篇

前言

hi大家好,我是小鱼,今天讨论的是前端响应式方案。这也是很多面试官喜欢问的一个问题,题型考察范围比较广,区分度比较大,一题就把你看得透透的,特别是移动端的更不可避免。所以,卷起来吧。

响应式

一提到响应式就会有很多概念,概念 == 术语,专业,高深,冷酷,无情。响应就是有响有应,这是一件双箭头的事情(我喜欢你,你也喜欢我)注意:前提是合适。那换做是屏幕也是同理,根据屏幕大小,显示合适的内容。我们先给它一个定义

同一个页面在不同的屏幕尺寸的一个终端设备上有一个不同的布局表现,简单来说可以适配多端,同时让用户在多个设备上都有一个很好的页面源体验。

可能有些小伙伴会认为响应式布局是CSS3之后才有的一个概念,响应式就是flex或者媒体查询,其实不是这样,像早期的一些流排版,可能会结合一些min-widthmin-height和百分比,一定程度上可以实现响应式布局。或者大家熟悉的REMEMVW/VH还有多栏布局,图片的话有图片集srcset......等等

在讨论方案之前我们先回顾一些常用的单位

单位

px

px(pixel),表示像素,所谓像素就是呈现在我们显示器上的一个个小点,每个像素点都是大小等同的,所以像素为计量单位被分在了绝对长度单位中。像素分为两种类型:css像素和物理像素。

  1. CSS像素(CSS pixels): 又称为逻辑像素,是为web开发者创造的,在CSS和javascript中使用的一个抽象的层
  2. 设备像素(device independent pixels): 设备屏幕的物理像素,任何设备的物理像素的数量都是固定的

每一个CSS声明和几乎所有的javascript属性都使用CSS像素,因此实际上从来用不上设备像素 ,唯一的例外是screen.width/height,这也是为什么给不同分辨率的屏幕上设置一样的字体大小呈现出来的却不一样

rem/em

em的字体大小是相对于最近的被设定过字体大小的祖先元素

rem是CSS3新增的一个相对单位(root em,根em),rem为元素设定字体大小时相对的只是根元素html,默认情况下,html元素的font-size为16px。这个单位可谓集相对大小和绝对大小的优点于一身,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。

vw/vh

vw/vh也是一个相对单位(类似于remem)

vw:viewport width 视口宽度单位,1vw = 1/100视口宽度

vh:viewport height 视口高度单位,1vh = 1/100视口高度

注意:和百分比是有区别的,百分比是相对于父元素来说的,而vw和vh总是针对于视口来说的。实际开发中用vw最多,因为vh是相对视口高度计算尺寸的,一般我们都是相对的视口宽,而且使用vh需要考虑全面屏,视口高度尺寸会偏大。

实现方案


媒体查询

刚刚介绍px的时候说到,我们所用到的1px(css像素)所表示的物理像素在不同终端设备上的大小是不同的,那我们要解决这样的问题,BiuBiuBiu ---- 媒体查询(Media Query)闪亮登场,是CSS3的新语法。

  • 使用@media查询,可以针对不同的媒体类型定义不同的样式
  • @media可以针对不同的屏幕尺寸设置不同的样式
  • 当你重置浏览器大小的过程中,页面也会根据浏览器的宽度和高度重新渲染页面
  • 目前针对很多苹果手机、Android手机,平板等设备都用得到媒体查询

那我们就可以针对不同的屏幕大小定义不同的样式,来达到适配的效果。

栗子↓

// 设置max-width 是指定义输出设备中页面最大可见区域宽度,当宽度小于某个像素时,会执行里面的样式

@media screen and (max-width: 1334px){
    .container{
      width: 600px;
    }
}

@media screen and (max-width: 960px){
    .container{
      width: 400px;
    }
}

@media screen and (max-width: 750px){
    .container{
      width: 200px;
    }
}

外链式

min-width:最小值,大于或者等于该值加载css max-width:最大值,小于或者等于该值时加载css 或者一些多个端口:xx < 视口 < xx

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- 通用的样式写在最前面 -->
    <link rel="stylesheet" href="./css/common.css">
    <!-- 针对不同的视口,选择不同的样式 -->
    <link rel="stylesheet" href="./css/large.css" media="screen and (min-width:1200px)">
    <!-- 为了避免更改了顺序,导致临界点发生改变,通常错开1px -->
    <link rel="stylesheet" href="./css/small.css" media="screen and (max-width:1201px)">
    <!-- 各个视口相似的样式要提取出来,防止书写多次 -->
    <title>Document</title>
</head>
<body>
    <!-- 在视口>1200的时候显示红色字体,绿色背景 -->
    <!-- 在视口<1200的时候显示蓝色字体,粉色背景 -->
    <div class="box">你好</div>
</body>
</html>

缺点:如果项目适配多端情况比较多,改变浏览器大小时需要改变的样式就很多,这么多的样式管理起来就很繁琐。

百分比

百分比大家都很熟悉了,widthheight属性的百分比依照与父属性的宽高,设置百分比可以让浏览器中的元素随着浏览器的大小而变化,这样也可以实现响应式,简单写个栗子吧。

.box {
    width: 100%;
    height: 500px;
    background-color: rgb(243, 151, 45);
    display: flex;
    justify-content: space-around;
    align-items: center;
}
.item {
    width: 20%;
    height: 150px;
    background-color: rgb(211, 56, 56);
}

你没事吧?没事就来看看这篇响应式方案

百分比只能做一些简单的响应式,如果全部使用百分比单位来实现响应式布局,有很明显的缺陷:

  1. 计算量来说比较复杂,我们刚刚只写了几个简单的元素,如果页面比较丰富呢?全部按照设计图换算成百分比在成本上来说太高了。

  2. css中的子元素中的百分比(%)到底是谁的百分比?widthheight相对于父元素的widthheighttopbottom相对于直接非static定位(默认定位)的父元素的高度,leftright相对于直接非static定位(默认定位的)父元素的宽度,而marginpadding不管垂直还是水平方向都相对比父元素的宽度、border-radius则是相对于元素自身等等,这么多的条条框框,会造成我们使用百分比单位容易使布局问题变得复杂、混乱。我找到了我给大家列出来

  • padding百分比是相对于参照元素的宽度而言;
  • margin百分比是相对于参照元素的宽度而言;
  • width百分比是相对于参照元素的宽度而言;
  • leftright百分比是相对于参照元素的宽度而言;
  • height百分比是相对于参照元素的高度而言;
  • topbottom百分比是相对于参照元素的高度而言;
  • line-height百分比是相当于元素自身文字大小而言;
  • background-size百分比是相当于元素自身的宽高而言;
  • border-radius百分比是相当于元素自身的宽高而言;
  • transform百分比是相当于元素自身的宽高而言;
  • background-position百分比和其它的百分比单位表现都不一样,具体可以用以下公式计算:
positionX = (容器的宽度-图片的宽度) * percentX; 
positionY = (容器的高度-图片的高度) * percentY;

rem

rem这个单位刚刚已经介绍过了,简单、灵活。它是相对于根元素html的font-size来决定大小的,根元素的font-size相当于提供了一个基准,当页面的size发生变化时,只需要改变font-size的值,那么以rem为固定单位的元素的大小也会发生响应的变化。

计算rem

不知道大家有没有写过移动端的项目,在做移动端各种尺寸屏幕的适配时,用的最多的就是rem方案。我们都写过这样的代码,来设置根字体大小。比如把我们的html的font-size设置成1px,这样1rem就等于1px,因为我们标注稿750px,是基于二倍屏的,1个css单位等于2个实际单位,所以我们的font-size设置为0.5px,这样我们设置尺寸时,rem和标注稿的px,就是1比1映射的。当然这里所有的大小都是相对于标注稿尺寸来说的,如果是其他屏幕的尺寸,html的font-size肯定要相应的变大或者变小。

// 基准大小
const baseSize = 16
// 设置 rem 函数
function setRem() {
  // 当前页面宽度相对于 750 宽的缩放比例,可根据自己需要修改。
  const scale = document.documentElement.clientWidth / 750
  // 设置页面根节点字体大小
  document.documentElement.style.fontSize = baseSize * Math.min(scale, 2) + 'px'
}
// 初始化
setRem()
// 改变窗口大小时重新设置 rem
window.onresize = function() {
  setRem()
}

转换rem

实际开发的时候,还是需要我们去计算对应的rem值去开发。

postcss-pxtorem

是一个用JavaScript工具和插件转换CSS代码的工具。

1. 安装 postcss-pxtorem

$ npm install postcss-pxtorem -D

2. 配置Postcss

项目下新建postcss.config.js文件

module.exports = {
  plugins: {
    'postcss-pxtorem': {
       //根元素字体大小
       rootValue: 16,
       //匹配CSS中的属性,* 代表启用所有属性
       propList: ['*'],
       //转换成rem后保留的小数点位数
       unitPrecision: 5//小于12px的样式不被替换成rem
       minPixelValue: 12,
       //忽略一些文件,不进行转换,比如我想忽略 依赖的UI框架
       exclude: ['node_modules']
     }
  }
}

配置好了在开发就可以直接使用px,设计图给多少就写多少,是不是很nice!!!

这里肯定有很多小伙伴会提到字体的问题,用户群体有老年人,有大写字号或者超大,设计师不希望字体自适应。这种就需要你自己去对不同的字号做一些比值,涉及到一些缩放比例,这个比例定好之后,可以转换成大写的PX,通过mixin或者可以通过一些特殊的类对比需不需要scale。大家可以根据自己的场景去实现。

淘宝的flexible.js

flexible.js用来处理移动端各种设备兼容和尺寸众多的问题。 “了解一个框架的实现原理比用一个框架更有意思”,推荐文章---→ 手写flexible.js的原理实现

vw/vh

上面已经介绍过了,忘了的再上去看一遍,加深印象哈哈哈哈哈。使用vw/vh布局,可以实现视口宽度不同,网页元素宽高等比缩放效果,比rem的优势在于,在代码中直接写vw/vh就能实现移动适配效果,不用引入js文件,比rem更简单,但有兼容问题,ie9-11不支持vmin和vmax,opera浏览器整体不支持vw单位。

vw/vh是相对单位,vw相对视口的宽度,vh相对视口的高度。 1vw = 1/100的视口宽度,1vh = 1/100的视口高度。 比如iphone6/7/8的视口宽是375,换算成vw就是3.75。.

除了vw和vh外,还有vmin和vmax两个相关的单位

  • vmin:vw和vh中的较小值
  • vmax:vw和vh中的较大值

但实际开发中用vw最多,因为vh是相对视口高度计算尺寸的,一般我们都是相对的视口宽,而且使用vh需要考虑全面屏,视口高度尺寸会偏大。

// 比如对于iphone6/7 375*667的分辨率 1px = (1/375)*100 vw
$vm_base: 375;
@function vw($px) {
  @return ($px / 375) * 100vw;
}

.box {
  width: vw(150);
  height: vw(50);
}

end

响应式布局就是通过检测视口的宽度,通过一系列方式来让页面适配起来。这些方式各有利弊,大家根据自己的需要来选择。

你没事吧?没事就来看看这篇响应式方案

转载自:https://juejin.cn/post/7195000946173640741
评论
请登录