响应式
什么是响应式页面呢?
顾名思义响应式页面就是能做出响应的页面,它的页面效果不是定死的,会随着用户的改变而改变。
如何着手响应式有以下几个思考的方向
- 找一份设计图
- 使用Media Query
- 隐藏元素
- 添加meta viewport
- 明白手机端交互方式的区别
Media Query
是什么
Media query 翻译过来就是媒介查询,媒介就是我们查看这个网页的设备。
媒介查询源于CSS3,它可以根据用户的设备所具有的某些特征,来提供不同的样式用于显示。
用法
引用方式
它的引用方式一共有两种
- <link>元素中媒介查询
- 样式表中媒介查询
<!-- link元素中的CSS媒体查询 -->
<link rel="stylesheet" media="(max-width: 800px)" href="example.css" />
<!-- 样式表中的CSS媒体查询 -->
<style>
@media (max-width: 600px) {
body{
background: red;
}
}
</style>
在link中使用媒介查询后,即使不满足样式条件,这个样式文件依然会被下载。
条件判断
媒介查询的条件判断的逻辑操作符只有and
, only
, not
三种,多个判断条件用()
包裹后操作符隔开。
//当媒介最大宽度为800px且是横屏时里面的样式生效
@media (max-width: 800px) and (orientation: landscape){
......
}
Mobile First
目前web前端开发项目类型可以分为两种方式,Mobile First 和 Desktop First。Mobile First就是优先开发移动端后开发PC端,后者反之。
不同的Fist中我们Media Query针对的也不同,Mobile First中,因为我们以移动端为主,所以我们的Media Query应该是针对PC的条件去控制,Desktop Fist则针对移动端设置条件样式。
这里就用到了一开始所说隐藏
meta viewport
现在,你已经写好了你的响应式网页,那么已经可以了吗?
别急,你离完成仅剩最后一步。
由于历史的原因,我们的手机在访问网页时,不管你是响应式网页还是非响应式,浏览器都会将你的宽度改为980px。
这是历史遗留的问题,因为最早的智能手机为了完整的显示一个网页,直接将PC上的网页缩放塞进手机浏览器中,经过调研,发现大部分的网页都是980px左右,所以当我们用手机访问网页时宽度都会被缩放到980px。
我们只需要加上这样一行代码就可以解决问题
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
width=device-width
设置页面宽度为设备宽度。
user-scalable=no
不允许用户缩放
initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0
最大最小默认缩放比例都为1。
这样我们的响应式网页才完全生效了。
移动端特点
- 没有hover
- 有touch
- 没有滚动条
- 没有IE
- 没有resize
因为移动端是没有hover事件的所以当我们在需要兼容移动端的页面中应该尽量少用hover事件。
移动端一般很少监听click事件,都是以touch事件为主,JS没有滑动事件,但是可以通过touch事件模拟
没有IE意味着我们可以为所欲为放飞自我,使用最新的CSS和HTML。
为什么需要响应式?
当我们需要给不同的设备显示不同网页(样式)时,为什么不可以一开始就写好多个网页再由后端负责根据用户设备来跳转呢?
我们写响应式需要思考非常多的问题,在一个页面里html css需要考虑很多判断逻辑,这些多出来代码以及设计的时间可能已经能够写一个新的网页,那为什么不一开始就写两个网页就好了呢?
确实,现在大部分互联公司现在几乎都不会去使用响应式页面。
- 博客园:响应式
- 百度:非响应式
- 谷歌:非响应式
- 淘宝:非响应式
- 头条:非响应式
- 知乎:非响应式
国内大型公司可以说基本上都是非响应式网页,只有那些交互性较弱比如个人blog,小型企业站点以展示内容为主的网站还会应用响应式设计。
动态REM自适应
在了解rem之前需要先知道
- 浏览器的默认font-size是16px
- Font-size最优先用户在浏览器中设置的大小,chrome默认最小12px。
什么是rem?
rem是众多number单位中的其中一个,它的值为根元素font-size的值。
<style>
body{font-size: 40px;}
p{font-size: 2rem;}
</style>
<body>
<p>hello</p>
word
<div>!!</div>
</body>
因为给body
标签设置了40px,所以body
里面的内容应该都是40px。但是由于p
在后面优先设置了2rem,浏览器的默认font-size为16px,也就是html
标签的font-size就是16px,所以现在的hello是32px。
也就是说rem的根元素的值指的就是html
的font-size的值。
rem有什么用?
上面扯了那么多介绍rem,那肯定是有用的。
别急,让我细细道来。
我们是希望在所有的手机上看到的页面都是一个样子的,页面内每个元素在固定的位置。但是按照常规方法,一个样式能做到让所有手机完美(90%)还原设计稿的样子吗?
答曰:可以,用media写响应式,针对不同的设备宽度,展现不同的样式。
好的,那让我们打开开发者工具模拟手机看看。
- iPhone X : 375 x 812
- iPhone 6/7/8 Plus : 414 x 736
- iPhone 6/7/8 : 375 x 667
- iPhone 5/SE : 320 x 568
- Galaxy S5 : 360 x 640
- Pixel 2 : 411 x 731
看到这些你还想用media吗?你要写多少个media?光是一个iPhone就可以搞死你更别说还有一堆的国产机等着你适配。
那怎么办呢,有没有办法可以让一个CSS适应“所有”的手机呢?
办法肯定有,那就是自适应,我们不需要知道用户的手机的长宽是多少,我们让网页自己匹配用户的手机长宽就好了啊。
自适应布局
自适应布局有下面两种常规方法
- 百分比布局:宽度百分比。
- 缩放布局:按比例设置网页宽高。
这两个布局一个百分一个比例看上去意思是一样,其实不然。百分比布局中的宽度样式不是一个具体的值,而缩放是在已知宽度的情况下定死的值。
/*device-width = 320*/
body{
width: 50% /*160px*/
}
body{
width: 160px /*160px*/
}
如果我们的目的是在手机上展现body占据屏幕一半的效果的话,上面两种写法在宽度为320px的手机上效果是一样的,都是将body的宽度设置为手机的一半长。
现在只是在宽度为320px的手机上展现了1/2的效果,那么当我们的手机是宽度300px的时候呢?
/*device-width = 300*/
body{
width: 50% /*150px*/
}
body{
width: 150px /*150px*/
}
如果是百分比布局是不是不需要改动,而按比例布局需要改动。
那么百分比布局能解决问题吗?
不行,百分比布局有个缺陷,高度是未知的,因为高度没有办法百分比,如果定死了高度那么就没有办法与宽度适应了。一旦我们的页面一复杂,未知的高度会带来更多的问题。
总的来说我们的页面需要靠宽度适配,再用这个宽度来决定自身的高度以达到宽高都成比例,在不同的手机上都可以按同样的比例展现。
那有什么方法可以准确获取手机的宽度吗?
这时我们的英雄登场了,rem。
上面说到rem是根元素font-size的值,那么我们只需要将根元素html
的font-size为手机的宽度,这时不就可以通过rem来设置有比例的宽高样式了吗。
rem怎么用?
var width=document.documentElement.clientWidth;
document.write(`<style>html{font-size:${width / 10}px}</style>`)
JS代码就两行,将rem设置为手机宽度的的10%,虽然设置width / 100可以完全模拟vw(自适应不用vw是因为vw兼容性太差了),但是当em为1%时,一但宽度小于120px时,font-size就会小于12px,低于chrome默认的最小font-size就会出现bug,所以我们设置rem为10%。
还需要注意的是虽然width和height是用rem使用,但是不代表别的大小也需要用rem(如果字体的font-size也用rem,那当宽度很小时,字会小的看不清),我们应该搭配别的单位以获得更美观的效果。
使用SCSS自动转换px
为了减少我们计算量,我们可以直接使用scss写一个function帮我们解决转换的问题。
@function px( $px ){
@return $px/$designWidth*10 + rem;
}
$designWidth : 640。
.box{
background: grey;
width: px(256);
height: px(128);
margin: px(32) px(32);
float: left;
}