rem布局(苏宁移动端页面为例)

540 阅读13分钟

笔记来源:拉勾教育 - 大前端就业集训营

文章内容:学习过程中的笔记、感悟、和经验

rem布局(苏宁移动端页面为例)

rem(root em)单位

rem是相对单位,类似于em,em参考的是父元素字体大小,rem参考的是html根元素字体大小

**优点:**一个页面只有一个html根元素,参考元素是唯一的,可以实现整体控制

媒体查询(@media)

判断屏幕宽度,CSS3新增语法,类似于触发条件,如果满足会应用其中的样式,否则不执行

  • 可以针对不同媒体类型定义不同的样式
  • 可以针对不同屏幕大小设置不同样式
  • 重置浏览器大小过程中,页面会根据浏览器的宽度和高度重新渲染页面
  • 目前移动端设备都可以使用媒体查询

语法规范

  • 必须使用@mesia开头
  • mediatype - 媒体类型
  • and、not、only - 关键字
  • nedia featyre - 媒体特性
@media mediatype and|not|only (media featyre){ css样式 }

mediatype - 媒体类型

将不同设备终端划分为不同的类型,称为媒体类型

解释说明
all用于所有设备
print用于打印机和打印预览
screen用于电脑屏幕,平板电脑,智能手机等(最常用)

关键字

关键字将媒体类型或多个媒体特性连接到一起做为媒体查询的条件。

  • and:可以将多个媒体特性连接到一起,相当于“且”的意思。
  • not:排除某个媒体类型,相当于“非”的意思,可以省略。
  • or:可以测试多个媒体查询的条件,只要有一个条件成立,就执行, “或”的意思。
  • only:指定某个特定的媒体类型,可以省略。

媒体特性

每种不同的媒体类型具有不同的特性,根据不同的媒体类型的媒体特性设置不同的样式风格

最常用的三个媒体特性:

解释说明
width定义输出设备中页面可见区域的宽度
min-width定义输出设备中页面最小可见区域宽度
max-width定义输出设备中页面最大可见区域宽度

案例

  • 按照从大到小的或者从小到大的思路
  • 注意我们有最大值max-width和最小值min- width都是包含等于的
  • 当屏幕小于540像素,背景颜色变为蓝色(x<= 539)
  • 当屏幕大于等于540像素并且小于等于969像素的时候背景颜色为绿色( 540=< x <= 969)
  • 当屏幕大于等于970像素的时候,背景颜色为红色( x>= 970)
  • 注意:

为了防止混乱,媒体查询我们要按照从小到大或者从大到小的顺序来写,但是我们]最喜欢的还是从小到大来写, 这样代码更简洁

需求:

  • 当屏幕小于540像素,背景颜色变为蓝色(x<= 539)
  • 当屏幕大于等于540像素并且小于等于969像素的时候背景颜色为绿色( 540=< x <= 969)
  • 当屏幕大于等于970像素的时候,背景颜色为红色( x>= 970)
/* 宽度小于等于539时 */
@media screen and (max-width: 539px) {
    body {
        background: #0000ff;
    }
}
/* 宽度大于等于540、小于等于969时 */
/* 下面这个是上面一行的简易写法,原理是当宽度大于970时会层叠掉绿色的属性 */
/* @media screen and (min-width: 540px)  and (max-width: 969px) { */
@media screen and (min-width: 540px) {
    body {
        background: #00ff00;
    }
}
/* 宽度大于等于970时 */
@media screen and (min-width: 970px) {
    body {
        background: #ff0000;
    }
}

媒体查询+rem实现元素大小动态变化

使用媒体查询修改html根元素得字号,其他元素使用rem单位就可以随着html变化而变化

案例

需求:让文字字号、背景和高度随着宽度变化而变化

<style>
    /* 默认html字号 */
    html {
        font-size: 20px;
    }
    /* 宽度大于等于640时,修改html字号 */
    @media screen and (min-width: 640px) {
        html {
            font-size: 30px;
        }
    }
    * {
        margin: 0;
        padding: 0;
        }
    div {
        width: 100%;
        height: 3rem;
        background: #0f0;
        text-align: center;
        line-height: 3rem;
    }
</style>

<div>购物车</div>

引入资源

当样式比较繁多的时候,我们可以针对不同的媒体使用不同stylesheets (样式表)

原理就是直接在<link>中判断设备的尺寸,然后引用不同的css文件。 语法规范

<link rel= "stylesheet" media=" mediatype andnotlonly (media feature)" href=" mystylesheet.css">

示例

/* 在屏幕宽度大于等于400px时引入styleA.css文件 */
<link rel="stylesheet" href="styleA.css" media="screen and (min-width: 400px)">

建议:从小尺寸到大尺寸引入

less基础

css弊端

CSS是一门非程序式语言,没有变量、函数、SCOPE (作用域)等概念

  • CSS需要书写大量看似没有逻辑的代码,CSS 冗余度是比较高的。
  • 不方便维护及扩展,不利于复用。
  • CSS没有很好的计算能力
  • 非前端开发工程师来讲,往往会因为缺少CSS编写经验而很难写出组织良好且易于维护的CSS代码项目。

less简介和安装

  • Less (Leaner Style Sheets的缩写)是一门CSS扩展语言,也成为CSS预处理器。
  • 做为CSS的一种形式的扩展,它并没有减少CSS的功能,而是在现有的CSS语法上,为CSS加入程序式语言的特性。
  • 它在CSS的语法基础之上,引入了变量,Mixin (混入),运算以及函数等功能,大大简化CSS的编写
  • 降低了CSS的维护成本,就像它的名称所说的那样,Less 可以让我们用更少的代码做更多的事情。

Less中文网址: lesscss.cn/

常见的CSS预处理器: Sass、 Less、 Stylus

Less是一JCSS预处理语言,它扩展了CSS的动态特性。

安装

  • 安装nodejs,可选择最新的版本,网址: https://nodejs org/en/download/
  • 检查是否安装成功,使用cmd命令(win10 是window +r打开运行输入cmd)输入 ” node -v "查看版本即可
  • 基于node.js在线安装Less,使用cmd命令”npm install -g less”即可
  • 检查是否安装成功,使用cmd命令『 lessc -V』 查看版本即可

less使用

首先创建一个.less文件,在里面书写less语句

less变量

变量是指没有固定的值,可以动态改变的。因为我们CSS中的- -些颜色和数值等经常使用。

书写方法:@变量名:值;

变量命名规范
  • 必须有@为前缀
  • 不能包含特殊字符
  • 不能以数字开头
  • 大小写敏感

例如@color: pink;

使用规范

直接在样式里面引入

/* 创建变量 */
@color: pink;
body {
  /* 直接使用 */
  background: @color;
}

less编译

本质上,Less 包含一套自定义的语法及一个解析器,用户根据这些语法定义自己的样式规则,这些规则最终会通过解析器,编译生成对应的CSS文件。所以,我们需要把我们的.less文件,编译生成为.css 文件,这样我们的html页面才能使用。

推荐方法(nodejs) :在当前文件夹,使用cmd命令“lessc style.less > style.css”

更推荐方法:VScode安装easy less插件,重启后每当保存less文件会自动生成一个同名的css文件,然后在html文件中引入css即可

less嵌套

类似于html结构嵌套,可以直接书写选择器嵌套,使逻辑更加清晰

后代选择器:

#header .logo {
  wudth: 100px
}

在less中的写法

#header {
  /* 选中#header后代.logo */
  .logo {
    width: 100px;
  }
}

交集|伪类|伪元素选择器

使用&符号代表前一层选择器

/* 伪类选择器 */
a {
  &:hover {
    color: red;
  } 
}

/* 伪元素选择器 */
a {
  &::after {
    content: "";
  } 
}

/* 交集选择器 */
a {
  &.div {
    color: red;
  } 
}

less运算

任何数字、颜色、或者变量都可以参与运算。less提供加减乘除四则运算

200rem / 50px      结果输出4rem
#999 - #333     结果输出#666

注意事项

  • 参与运算的两个数字如果只有一个单位,则继承单位
  • 如果都有单位,取第一个数字的单位
  • less运算符左右必须有空格

rem适配方案

让页面不能进行等比例适配的元素可以根据宽度等比例适配

使用媒体查询判断宽度,根据宽度设置rem基础字号,元素使用rem单位设置宽高等属性

rem实际开发适配方案

  1. 按照设计稿与设备宽度的比例,动态计算并设置html根标签的font- size大小; (媒体查询)
  2. CSS中,设计稿元素的宽、高、相对位置等取值,按照同等比例换算为rem为单位的值

rem适配方案的使用(市场主流)

  • 方案1:less + 媒体查询 + rem
  • 方案2:淘宝flexible.js + rem (推荐

方案1

常见设计稿尺寸
设备常见宽度
iphone 4/5640px
iphone 6/7/8750px
Android常见320px. 480px、 540px、 600px、 720px、 768px、 800px、 1080px 目前市场主流设备尺寸按照1080px设计

一般情况下,我们以一套或两套效果图适应大部分的屏幕,放弃极端屏或对其优雅降级,牺牲一些效果,现在基本以750为准。

具体实施
  1. 假设设计稿为750px
  2. 人为假设把屏幕分为15等分(也可以是其他数字)
  3. 每一份html字体大小就是50px
  4. 那么适配比如320px的设备时,字体大小就是320px/15 = 21.33px
  5. 用我们的页面大小除以不同的html字号大小,就可以得到想要的rem数值
比如我们以750px为标准设计稿:
  • 一个100* 100像素的页面元素在750屏幕下,就是100 / 50转换为rem是2rem *2 rem比例是1比1
  • 320屏幕下,html 字体大小为21.33则2rem = 42.66px此时宽和高都是42.66但是宽和高的比例还是1比1 但是已经能实现不同屏幕下页面元素盒子等比例缩放的效果
元素大小取值方法
  • 最后的公式:页面元素的rem值=页面元素值(px)/(屏幕宽度/划分的份数)
  • 屏幕宽度/划分的份数就是 html font-size的大
  • 或者:页面元素的rem值=页面元素值(p)/ html font-ize字体大小

苏宁首页案例(m.suning.com)

技术选型

  • 方案:我们采取单独制作移动页面方案
  • 技术:布局采取rem适配布局(less+rem+媒体查询)
  • 设计图:本设计图采用750p×设计尺寸

准备工作

  1. 搭建文件结构(html + css文件夹 + images文件夹)
  2. html文件设置视口、引入初始化css
  3. 设置公共样式的common.less文件并引入common.css文件
    • 新建common.less设置好最常见的屏幕尺寸,利用媒体查询设置不同的html字体大小,因为 除了首页其他页面也需要。
    • 苏宁网站首页的开发尺寸有320px、360px、 375px、 384px、 400px、 414px、 424px、480px、540px、 720px、 750px等。
    • 划分的份数我们定为15等份。
    • 因为我们pc端也可以打开我们苏宁移动端首页,我们默认html字体大小为50px,注意这句话写到最上面。
  4. 新建index.less文件,并在里面引入common.less文件(@import "common")在index.html中引入index.css文件

body样式

//body样式
body {
    min-width: 320px;
    width: 15rem;
    margin: 0 auto;
    line-height: 1.5;
    font-family: Arial, Helvetica, STHeiTi, sans-serif;
    background: #f2f2f2;
}

top-banner区域

BxnbMF.png

结构分析:

整体大盒子里面包裹两个a标签,第一个a标签包裹整个图片区域,另一个放置左边的关闭按钮

<!-- top-botter部分 -->
<div class="top-banner">
    <a href="javastricp:;">
        <img src="./images/top_banner.jpg" alt="">
    </a>
    <a href="javastricp:;"></a>
</div>
<!-- top-botter部分结束 -->
// top-banner区域
.top-banner {
    position: relative;
    width: 15rem;
    height: 2rem;
    //背景图
    & a:nth-child(1) {
        display: block;
        width: 100%;
        height: 100%;
        & img {
            display: block;
            height: 100%;
            width: 100%;
        }
    }
    //关闭按钮
    & a:nth-child(2) {
        position: absolute;
        top: 0.5rem;
        left: 0.1rem;
        width: 1rem;
        height: 1rem;
        background: url(../images/close.png) no-repeat center center;
        background-size: 0.6rem auto;
    }
}

header区域

Bxfwef.png

结构分析

总体分我上下两层,上面从左到右为三个元素,可以使用flex布局,下面盒子实际上也有三个元素,最上面覆盖了一个a标签点击跳转到其他页面,下面有一个小图标和一个form标签,form标签内部有一个input

<!-- header部分 -->
<div class="header">
    <!-- 上部 -->
    <div class="header-top">
        <a href="javastricp:;"><img src="./images/classify.png" alt=""></a>
        <a href="javastricp:;"><img src="./images/ad.gif" alt=""></a>
        <a href="javastricp:;"><img src="./images/login.png" alt=""></a>
    </div>
    <!-- 下部 -->
    <div class="header-bottom">
        <i></i>
        <form action="header-bottom-from">
            <input type="seach" placeholder="400元北京消费补贴">
        </form>
        <a href="javastricp:;"></a>
    </div>
</div>
<!-- header部分结束 -->
// header区域
.header {
    width: 15rem;
    height: 3.6rem;
    background: #ffdb47;
    .header-top {
        display: flex;
        justify-content: space-between;
        align-items: center;
        width: 15rem;
        height: 1.76rem;
        padding: 0 0.68rem;
        box-sizing: border-box;
        & a:nth-child(1) {
            width: 0.72rem;
            height: 1.2rem;
            img {
                width: 100%;
            }
        }
        & a:nth-child(2) {
            width: 9rem;
            height: 1.1rem;
            img {
                width: 100%;
            }
        }
        & a:nth-child(3) {
            width: 0.72rem;
            height: 1.2rem;
            img {
                width: 100%;
            }
        }
    }
    .header-bottom {
        position: relative;
        width: 15rem;
        height: 1.84rem;
        padding: 0 0.48rem;
        box-sizing: border-box;
        a {
            position: absolute;
            left: 0.48rem;
            top: 0;
            display: block;
            width: 14.04rem;
            height: 1.76rem;
        }
        i {
            position: absolute;
            left: 0.84rem;
            top: 0.52rem;
            width: 0.72rem;
            height: 0.72rem;
            background: url(../images/search_btn.png) no-repeat 0 0;
            background-size: 0.72rem auto;
        }
        form {
            display: flex;
            align-items: center;
            width: 14.04rem;
            height: 1.76rem; 
            input {
                width: 14.4rem;
                height: 1.28rem;
                border: 0;
                padding: 0.06rem 0.4rem 0 1.3rem;
                box-sizing: border-box;
                border-radius: 0.62rem;
                background: #fff;
                font-size: 0.56rem;
                line-height: 1.28rem;
            }
        }
    }
}

banner区域

BxL1G6.png

结构分析:整体结构一个大个子包裹一套轮播图,需要设置背景,注意轮播图使用三位置法

<!-- banner区域 -->
<div class="banner">
    <!-- 图片列表 -->
    <ul>
        <li class="now"><img src="./images/banner.jpg" alt=""></li>
        <li><img src="./images/banner.jpg" alt=""></li>
        <li><img src="./images/banner.jpg" alt=""></li>
        <li><img src="./images/banner.jpg" alt=""></li>
        <li><img src="./images/banner.jpg" alt=""></li>
        <li><img src="./images/banner.jpg" alt=""></li>
    </ul>
    小指示灯
    <ol>
        <li class="now"></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
    </ol>
</div>
<!-- banner区域结束 -->
// banner区域
.banner {
    position: relative;
    width: 15rem;
    height: 5.2rem;
    background: url(../images/banner_bg.png) no-repeat 0 0;
    background-size: 15rem auto;
    ul {
        position: relative;
        width: 14.04rem;
        height: 5.2rem;
        margin: 0 auto;
        border-radius: 0.48rem;
        background: #cccccc;
        overflow: hidden;
        li {
            position: absolute;
            top: 0;
            left: 100%;
            width: 100%;
            height: 100%;
            &.now {
                left: 0;
            }
            img {
                display: block;
                width: 100%;
                height: 100%;
            }
        }
    }
    ol {
        display: flex;
        justify-content: space-between;
        position: absolute;
        left: 50%;
        bottom: 0.2rem;
        width: 2rem;
        height: 0.2rem;
        margin-left: -1rem;
        li {
            width: 0.2rem;
            height: 0.2rem;
            border-radius: 50%;
            background: rgba(255, 255, 255, 0.5);
            &.now {
                background: rgba(255, 255, 255, 1);
            }
        }
    }
}

nav区域

BxxzrT.png

结构分析:

大盒子包裹10个小盒子,每个盒子里面可以使用flex布局或者其他昂时都可以

<!-- nav部分 -->
<div class="nav">
    <ul>
        <li>
            <img src="./images/nav_01.png" alt="">
            <p>苏宁秒杀</p>
        </li>
        <li>
            <img src="./images/nav_01.png" alt="">
            <p>苏宁秒杀</p>
        </li>
        <li>
            <img src="./images/nav_01.png" alt="">
            <p>苏宁秒杀</p>
        </li>
        <li>
            <img src="./images/nav_01.png" alt="">
            <p>苏宁秒杀</p>
        </li>
        <li>
            <img src="./images/nav_01.png" alt="">
            <p>苏宁秒杀</p>
        </li>
        <li>
            <img src="./images/nav_01.png" alt="">
            <p>苏宁秒杀</p>
        </li>
        <li>
            <img src="./images/nav_01.png" alt="">
            <p>苏宁秒杀</p>
        </li>
        <li>
            <img src="./images/nav_01.png" alt="">
            <p>苏宁秒杀</p>
        </li>
        <li>
            <img src="./images/nav_01.png" alt="">
            <p>苏宁秒杀</p>
        </li>
        <li>
            <img src="./images/nav_01.png" alt="">
            <p>苏宁秒杀</p>
        </li>
    </ul>
</div>
<!-- nav部分结束 -->
//nav区域
.nav {
    width: 15rem;
    ul {
        width: 100%;
        overflow: hidden;
        li {
            float: left;
            width: 3rem;
            height: 2.84rem;
            text-align: center;
            img {
                display: block;
                width: 1.68rem;
                height: 1.68rem;
                margin: 0.48rem 0.66rem 0;
            }
            p {
                margin: 0.1rem 0 0.44rem;
                font-size: 0.44rem;
                line-height: 0.56rem;
                color: #666;
            }
        }
    }
}

方案2 (flexible.js + rem)

  • 手机淘宝团队出的简洁高效移动端适配库
  • 我们再也不需要在写不同屏幕的媒体查询,因为里面js做了处理
  • 它的原理是把当前设备划分为10等份,但是不同设备下,比例还是一致的。
  • 我们要做的,就是确定好我们当前设备的html文字大小就可以了
  • 比如当前设计稿是750px,那么我们只需要把 html文字大小设置为75px(750px / 10)就可以 里面页面元素rem值:页面元素的px 值/ 75剩余的,让flexible.js来去算

github地址: github.com/amfe/lib-fl…

引入js文件

<!-- 引入flexible.js文件 -->
<scricp src="js/flexible.js"></script>

更改flexible.js最大像素值

引入flexible.js文件

新建css文件,利用媒体查询将超过750px的屏幕字号设置为75px

@media screen and (min-width: 750px) {
  html {
    /* 使用!important关键字强制设置文字字号 */
    font-size: 75px !important;
  }
}

vscode插件cssrem

使用flexible.js制作苏宁首页案例的时候方法是相同的,可以不实用less(当然也可以使用),可以使vscode插件cssrem,这个插件会在你输入px值的时候提供选项自动转换成rem数值

注意:vscode有一个默认的rem字号,可能不是我们想要的,这时可以更改默认的rem字号(在设置里面直接搜索rem即可),然后重启vscode就可以使用flexible.js制作了