移动端web开发布局,包括流式布局、flex布局、@media(媒体查询)+rem+less、flexible.js+rem,以及一些移动端开发的常用知识和技巧
移动WEB开发布局导读
现状
pc端的浏览器比较杂,兼容性不好,移动端的兼容性好,主要只需处理webkit内核的浏览器即可
移动端调试方法
谷歌浏览器(chrome devtools)
视口
布局视口
视觉视口
理想视口
需要借助meta视口标签来显示理想视口
meta视口标签
解释一下这个视口标签中content属性中的一些值:
-
width=device-width (最重要的一句话)
表示我的宽度是设备的宽度,设备有多宽,布局的宽度就有多宽
-
user-scalable=no / yes (或者写0 / 1)
表示不允许 / 允许用户手动去缩放
-
initial-scale=1.0
表示初始化的缩放比例就是我原先设计的那个比例,如果是2.0就是缩放为原先的两倍
-
maximum-scale
表示最大缩放比例
-
minimum-scale
表示最小缩放比例
加上这一行的效果:原先如果变成手机端字会很小,现在能够按正常大小显示
二倍图
物理像素&物理像素比
物理像素:就是我们说的分辨率 iPhone8的物理像素是 750
物理像素比:物理像素:开发像素,iPhone8的物理像素比:2.0
实际中分辨二倍图:
带一个@2x的就是二倍图
实验:
我们发现300px竟然占了宽度750像素的iPhone8的一大半
我们再将div宽度改到375像素:
div刚好占满整个屏幕,说明在iPhone8这里,1px就是2像素
换句话说在iPhone8,像素比是2
那么为什么会出现开发像素和物理像素不一一对应的情况呢,很久以前确实是一一对应的,但是显示的字很糊,后来有了一种叫视网膜屏幕的技术,它将更多的像素压入屏幕,使得字更加清晰,如下:
二倍图做法
实验:
多倍图
背景图缩放 background-size
background-size属性规定背景图片的尺寸
实验:
多倍图切图cutterman
移动端开发选择
移动端技术解决方案
移动端CSS初始化 normalize.css
实验:
移动端去掉特殊样式
例子1:
移动端的时候我们点击a标签背景色会高亮:
我们可以把它去掉:
例子2:
移动端按钮的外观效果:
我们可以把他去掉:
去掉之后移动端按钮外观效果:
这样我们就把原先土土的样式去掉了,之后可以进一步修改成我们自己喜欢的样式
例子3:
移动端长按出现右键菜单栏
我们可以把它去掉:
去掉之后就不会出现菜单栏了
移动端常见布局
移动端技术选型
流式布局
为了让盒子不能过大也不能过小以免内容显示不对,我们还需要指定max_width和min_width(防止过度拉伸或者缩放导致的页面bug)
实验:
流式布局案例
具体代码见代码库
注意点:
由于采用的是流式布局,所以里面的小盒子也要采用百分比的方式
-
这一块通过缩放我们会发现左右两边是不会随着缩放而缩放的,但是中间这一块会随着缩放而缩放,那我们的想法是这样的:
左右两边的宽度固定死,中间的不指定宽度默认就是父亲的宽度,但是我们又希望左右两边的能显示出来,那我们就给中间的加一个左右的margin给他撑开就好了
-
伪元素是行内元素,因此指定伪元素宽高之前需要先将其转成块级元素
-
比方说jd-icon有一个伪元素jd-icon::after,那jd-icon::after的父亲就是jd-icon
-
不一定一定要子绝父相,子绝父绝也行,但优先选择子绝父相
-
指定某一个元素的margin的时候周围的元素的位置也一起变化了,这种情况多半是与父级元素发生了嵌套外边距塌陷,具体的解决方法去看css基础,里面有总结
-
为了使文字和图片垂直居中而设置line-height的时候图片并没有居中,那是因为图片默认和文字的基线对齐,此时只需要设置图片的vertical-align: middle即可(css基础班讲过)
-
明明没有设置margin或padding,但是图片之间却有空隙,如下:
解决方法(css基础班讲过):1、给图片设置display:block(因为块级元素不会有vertical-align,因此就不会有基线,从而消除bug);2、给图片设置vertical-align:top|bottom|middle
-
如果行内元素有变成块级元素的需求但是他已经加了一个浮动的话那就没必要再给他变成块级元素了(css基础班讲过)
-
最后可以加上移动端去掉特殊样式的代码
二倍精灵图的等比缩放
精灵图的等比缩放
精灵图如果需要等比缩放的话应该先缩放,再测量宽、高和位置
缩放精灵图:
缩放之后再测量:
最后写代码的时候不要忘了写上background-size对整张精灵图做一个缩放:
DPG与webp
flex布局
实验:
原先我们想要给span设定宽高需要先转成块级元素,现在不用了:
我们像上面这样写,发现span并没有宽度(这个时候没有宽度是正常的)
然后我们给div设置flex布局:
现在span就有宽度了:
我们还可以加justify-content属性:
效果:
而且他是可以自适应伸缩的
还可以再加上flex属性:
效果:
平均分成三等分了,而且也是自适应伸缩的
flex布局原理
- 任何一个容易都可以用flex布局
- float不再需要了,自然清除浮动的clear就不再需要了
- 原先只能水平居中,不能垂直居中,现在的flex是可以垂直居中的
flex布局父项常见属性
- flex-direction:
- justify-content
- flex-wrap
- align-content
- align-items
- flex-flow
flex-direction
设置主轴方向
实验:
-
row
基本代码(还没有加flex):
效果:
写了flex-direction: row跟没写一样,因为默认就是row
-
row-reverse
效果:
-
column
效果:
-
column-reverse
这个就不展示了,效果可以想象
justify-content
注意这个属性是跟着主轴来走的,跟副轴一点关系都没有,所以在使用这个属性之前一定要先确定好主轴是哪个
实验:
基础代码(还没写flex):
-
flex-start(默认)
-
flex-end
-
center
-
space-around
-
space-bewteen(★)
上述主轴是x轴的,主轴换成y轴也是同理
flex-wrap
思考:flex子元素一行内排不下是否会换行
答案是不会:
-
nowrap(默认)
-
wrap
align-items
我们希望实现既在主轴居中又在副轴居中的效果,如下:
实验:
基础代码(还没写flex):
水平居中:
-
center
垂直居中:
-
flex-start
-
flex-end
不说了,自行想象
-
stretch
注意,要把子盒子的高度去掉,否则没效果,因为子盒子已经有高度的话就没法拉伸了,去掉子盒子高度之后的效果如上图
将主轴变成y轴之后的效果跟主轴为x轴时同理
align-content
需要注意的是,align-items是单行的,也就是说如果我们想实现下图效果是不可行的:
因为align-items不像justify-content有一个space-around属性,可以平均分配主轴上的剩余空间,所以在有多行的时候他是做不到在副轴上平分剩余空间的。
要想做出这种效果,我们需要借助align-content属性
注意,align-content适用于多行(发生换行)的情况,在单行下是没有效果的
还是像上面那样准备好基础代码(没有写flex)
然后我们给他设置换行:
-
flex-start
-
flex-end
不多说,自行想像
-
center
-
space-between
-
space-around
-
stretch
自行想象
注意,当设置y轴为主轴的时候,align-content依然只对多列有效,如果只有单列,就用align-items
align-items和align-content的区别
flex-flow
原先:
现在:
flex布局子项常见属性
- flex
- align-self
- order
flex
这里注意两点:
1、是从剩余空间中分配;
2、flex是用来表示在剩余空间中该元素占多少份数的
实验:
- 需求:一行中有三个元素,左右两个贴紧左右两侧,中间的独占所有剩余空间并且伸缩自适应
效果:
-
需求:一行内三个盒子,将一行均分成三等份,每个盒子各占一份
只需要给每一个span指定flex为1
注意:不要给他们写宽度,因为flex是分配剩余空间的,如果都不写宽度,那么他们的宽度默认就是0,对于父盒子来讲剩余空间就是父盒子的宽度
效果:
-
需求:在上一题的基础上,我们希望其中某一个盒子比其他两个盒子要大
其实就是相当于把一块蛋糕分成4分,其中一个吃2份,另外两个吃1份
只需在上一题的基础上给某一个span的flex设置为2即可,代码如上
align-self
实验:
原本我们是操作一行中的所有盒子:
效果:
现在我们希望只有第三个盒子被操作:
只需给第三个盒子写align-self属性即可:
order
实验:
需求:我们希望在上一题的基础上将2号盒子移动到1号盒子前面,类似于z-index(注意,只是用法类似,order和z-index是不一样的),order值越小就越靠前,且order值默认为0
现在我们给第二个盒子设置order为-1,由于第一个盒子的order为0,因此第二个盒子会跑到第一个盒子的前面
效果:
flex布局案例
注意:
-
position:fixed,也就是固定的盒子应该要有宽度,而且固定定位的盒子与父亲没有关系,他以屏幕为准,所以宽度直接写100%是不合适的,这样这个盒子将会占满整个屏幕,因此我们还需要给他加上max-width和min-width两个属性
此时我们会发现宽度什么的都没问题,但是盒子靠左对齐,没有居中,这个时候由于已经写了固定定位,我们再给他加margin:0 auto是没用的,应该用left属性来调整
解决方法:
-
京东的做法是直接不写left:
这样会自动居中
-
另一种方法是借助transform:translateX(-50%)和left:50%,表示先定义距离左边缘50%距离,再向左移动自身宽度50%,达到正好居中的效果
如果我们想要兼容的话就在transform前面加上-webkit-,如下:
而且按照传统的写法都是先写-webkit-transform后写transform,如上图
-
-
加了绝对定位或浮动的盒子就直接有大小了,不需要再转成块级元素;加了绝对定位的盒子margin就失效了,需要使用top和left这种的属性来控制位置
-
当我们希望文字垂直居中的时候我们会使用line-height等于盒子的高度,但是要注意的是如果我们使用了css3的盒子模型,那他会把border之类的都算进去,导致我们使line-height等于盒子高度的时候整体文字会显得比较偏下,所以这时候我们不应该让line-height直接等于盒子的高度,而应该让他等于盒子内容的高度,因此我们应该先减去上下border的宽度。比方说整个盒子高度20px,上下border宽度各占1px,这个时候就应该设置line-height为20 - 1 - 1 = 18px,这样文字才能真正垂直居中
-
ul有默认的margin值和padding值,需要自定义ul的话最好把他们先去掉(置为0)
-
一个元素既可以设置flex属性又可以设置display: flex,这两个是不冲突的
-
flex及可以这么写:flex: 1,也可以这么写:flex: 20%,换言之,flex属性可以写百分比
-
属性选择器技巧:
我们想要给一些盒子设定公共属性,又想要给某些盒子设置特殊属性,可以通过命名一个具有公共前缀的class,如下:
这一块的布局思路:分成三行, 每一行分成三列,第一列独占两行,后面两列再分上下两行
还有一种叫径向渐变:
实验:
线性渐变:
打开后发现没效果,那是因为没有加-webkit-私有前缀(可能是兼容性不太好)
注意:背景渐变必须添加浏览器私有前缀
还可以设置为对角线的渐变:
rem适配布局
em
这个单位以前讲过,他是相对于父盒子的字体大小来说的,比方说父亲的字体大小是:font-size: 12px,那儿子的宽高可以这么设置:width: 10em; height: 5em,表示儿子的宽度是:10 * 12 = 120px,高度是:5 * 12 = 60px
实验:
rem
em是相对于父亲的字体大小来说的,而rem是相对于html的字体大小来说的,所以被称为rem(root em)
实验:
给html指定字体大小:
给p元素指定width和height:
再来一个div:
可见不管怎么伸缩,两个盒子都是同比例的,要修改大小只需要修改html的字体大小即可
媒体查询(@media)
mediatype
关键字
媒体类型
实验:
上述3号 540~970的代码还可以简写成:
这是利用了css中样式的层叠,后面的样式会覆盖前面的样式,也类似于数学的集合,分析:
注意点:
引入资源
解决了多年以来的问题:既然我们使用rem和媒体查询做到了样式动态变化,那如果变化特别大呢?比方说pc版的和手机版的两个页面那看起来是完全不一样啊,其实这里就用到了媒体查询的引入资源功能
实验:
对于以上需求,我们需要准备两套css:
然后引入css:
当宽度大于640的时候下面的css就把上面的给覆盖掉了
媒体查询+rem实现元素动态大小变化
案例:
基础代码(没写媒体查询):
注意这里写上了rem的代码,包括line-height也使用rem
写上媒体查询代码:
less
参考:https://less.bootcss.com/(less官网)
场景:
- 有很多盒子的style都是一个颜色,如果我们需要修改只能一个一个地去改
- 使用rem的时候首先我们会给html指定字体大小,然后会给子盒子指定rem,这个时候就需要计算了,比方说我们需要一个82px宽度的盒子,而html的字体大小是12px,那么他的宽度应该设置为 82 / 12 rem,由于css没有计算功能,这样会非常不方便
less介绍
less变量
实验:
less编译
注意,less需要编译成css才能使用,可以借助vscode中less插件来实现,安装这个插件之后每当我们ctrl+s保存less文件之后都会生成一个对应的css文件,如下:
less嵌套
less的嵌套相比于css的嵌套会简便很多:
还是上面这个布局:
现在用less写:
注意 交集|伪类|伪元素选择器 的写法:
我们像给a写一个hover效果,但是如果我们这么写:
生成的css:
中间带了一个空格,说明他已经不再是a的hover了
那这种情况该怎么写呢?
我们只需要在前面补一个 & 符号即可:
生成的css:
再试一个伪元素的写法:
生成的css:
less运算
实验:
直接加减乘除数字就行了,不需要带单位
上述代码生成的css:
注意::
比方说我们要使用rem,那么已经定义好了html的字体大小为50px,这个时候img的宽度就应该这么设置(第一个数添加单位rem):
结果(该结果就是我们希望的结果):
那如果第一个数不加单位呢(由于@baseFont已经有px单位了,所以最终算出来的结果的单位就是px):
结果(不是我们所希望的结果):
神奇的是,除了上述的运算之外,less还能做颜色的运算(比方说#444 - #222),如下:
还能加括号运算:
重要结论:
- 运算符左右两侧必须敲一个空格隔开
- 两个数参与运算,如果只有一个数有单位,那结果就以这个单位为准
- 两数参与运算,如果两个数都有单位且单位不一样,最后的结果以第一个数的单位为准
less其他语法
关于less,其实还有很多其他语法和函数,比方说混合(Mixins)、转义(Escaping)、函数(Functions)、命名空间和访问符、映射(Maps)、作用域(Scope)、导入(Importing)等,具体使用请参考:https://less.bootcss.com/(less官网)
sass
比less功能更强大一些
参考:https://www.sass.hk/(sass官网)
scss
scss是sass的一个升级版本,完全兼容sass之前的功能,又有了些新增功能,且语法形式上也有些许不同
参考:https://blog.csdn.net/baozhuona/article/details/78570683(sass与scss的区别)
rem适配方案
适配方案1(less+媒体查询+rem)
技巧:可以把屏幕划都分成15等份,比方说750px的屏幕,划分成15份,每一份50px,这个时候html的字体大小就为50px,如果换成320px的屏幕,那也是除以15,每一份21.33px,那么320px的屏幕下html的字体大小就是21.33px,这样两个设备的元素宽高都可以写一样数值的rem,而且显示的比例是一样的,如下:
实验:
划分的份数这里默认是15份,当然你也可以是20份,25份,这个由我们自己来定(主要是控制最后算出来的rem不要是0.000001rem或者1000000rem这样的就行了,说实话划分的目的就是让这个rem的数字好看点,像上面这个15份最后算出来的rem大多数都是在0.1-10之间的)
总结rem开发适配方案的操作顺序:
适配方案2(flexible.js+rem)(更加高效)
flexible.js内部默认将设备屏幕划分成10等分。使用flexible.js相当于给我们省去了@media媒体查询这一块,所以在这里我们是不需要使用媒体查询的
在flexible.js内部我们可以知道他具体将设备切割成了多少份:
rem布局案例(使用上述适配方案1)
技巧:
-
我们默认是将屏幕划分成15份的,所以可以给这个15一个变量来存储,这样到时候如果我们想改成20,那直接改这个变量就行了
-
手机里面的像素跟媒体查询里面的像素是一一对应的
比方说上如的375像素,那么媒体查询里面的宽度的像素就是375px
-
注意,这里说的像素跟手机的物理像素是没有关系的,而是跟css像素是有关系的
-
由于在pc端浏览器打开的时候会显得太大,所以我们一般会在文件最开头写一个写死的html字体大小:
注意它是一定要写到最上面的,这是因为代码的层叠性,下面的会覆盖上面的
上面的样式是写在common.less里面的,跟我们要写的主页的样式没有什么关系,所以现在我们还需要建立一个写主页样式的less文件
但是呢,新建的less文件还是需要使用到common.less文件中的内容的,这个时候就可以使用less的导入语法@import 将文件导入(注意,这里的文件可以是less也可以是css)
同时,这个时候在html里面我们也不需要再导入common.less文件了,因为common.less文件已经被引入进index.less里面了,所以html直接导入index.css即可
下面可以正式开始写样式了(直接写到index.less就行了):
注意:
-
这里line-height设置为1.5,意思是当前元素和当前元素的子元素的行高都设置为字体大小的1.5倍;如果line-height设置为150%,意思是当前元素的行高设置为字体大小的1.5倍而当前元素的子元素的行高都要等于当前元素字体大小的1.5倍,如下:
-
这里没有指定max-width,而是直接把width写死写满为15rem。这其实是两种思路,我们既可以像以前那样写max-width来限定最大宽度,也可以直接写width为15rem,因为前面已经做好了rem适配(common.less),我们知道用了rem之后不管屏幕被拉到多宽,他的最大宽度也会被限定死
注意,宽度用rem,由于前面分了15份,所以满宽度就是15rem
注意,这里的rem都是量出来的,比方说上图的height,首先量出来高是66px,然后去除以html的字体大小,也就是这里的@baseFont(这里我们定的就是50),最后最最重要也是最容易出错的地方就是单位,应该写上rem而不是px,因为最后算出来的数值的单位就是rem,这个地方极易出错
注意上图,我们使用的是最普通的布局(没有用flex这些的),我们希望img在a内水平居中对齐,由于img属于行内元素,所以在使用margin: 0 auto之前,必须要将他转成块级元素,否则margin: 0 auto语句将失去居中对齐效果
rem布局案例(使用上述适配方案2)
注意,上图的width: 15rem是不对的,因为划分成了10等份,所以如果宽度为750px,那每一份的宽度就是75px,所以满宽度应该是:750 / 75 = 10rem,所以应该设置宽度为10rem
我们惊喜的发现,flexible.js自动帮我们设定好了html的字体大小:
这里屏幕宽度1366px,上面我们也了解了flexible.js是将屏幕划分成10等份的,因此他自动给我们设定了html的字体大小为136.6px
再看看iPhone678的:
也是划分了10等份
注意:
之前我们使用适配方案1(less+@media+rem)的时候,我们只给body指定了最小宽度(min-width),最大宽度并没有指定,而是直接写了width:15rem(满宽度),那是因为那个时候我们指定默认的html字体大小就是50px,那么1rem就是50px,所以15rem就是750px,就已经是满宽度了,因此这个时候指不指定max-width都是一样的,就算指定了也就是指定max-width: 750px,这跟直接写width: 15rem没什么区别
但是!如果我们使用flexible.js的话,由于他是根据当前的屏幕给我们平均分成了10等份,所以他是并没有固定死默认的html字体大小的,因此如果这个时候我们不指定max-width,他默认的最大宽度就是当前屏幕的宽度,会出现如下情况:
上图的123顶着左边缘,这与我们希望的最大宽度为750px是不相符的
所以使用flexible.js的情况下必须指定max-width:
cssrem(自动将px转成rem的vs插件)
注意,这个插件默认的html文字大小是 cssroot 是16px,如上图,这里如果我们写上16px,他会自动给我们转成1rem,但是这里有一个问题,我们自己的适配方案中由于是10等份,1rem应该是75px,所以这里我们需要手动修改这个插件的比例:
注意,不是在这改,是在左边的这个编辑按钮改
改完重启之后就符合我们的要求了:
之后我们给某个元素指定width:10rem(满宽度),但是会有一个问题:
这个元素直接占满了整个屏幕的宽度,不用说,这个还是flexible.js的特性:以当前屏幕宽度来划分10等份,所以这里我们写10rem就又等于是占满了整个屏幕的宽度,那么怎么修改呢?如下:
原先方案1的时候我们就是在那一堆@media上面写了一个默认的html字体大小,那么这里的解决方案也是一样的,我们利用媒体查询将最大html字体大小控制在75px(因为是分成10份,所以每一份就是:750 / 10 = 75px),但是由于级别不够,我们的这个样式还是会被flexible插件覆盖掉,因此在后面加一个!important
现在终于正常了:
而且flexible有一个优势就是比起原先的直接手动写@media,他的随屏幕宽度变化而变化的程度是比较柔和的,简言之就是比较好看