总结5种自适应方式
特别说明:在开始这一切之前,请开发移动界面的工程师们在头部加上下面这条meta:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
复制代码
一、百分比
.test{
width: 20%
}
复制代码
-
优点
- 代码简单
-
缺点
- 需要计算,很不方便
二、media query
- 实现思路
@media screen and (min-width: 320px) and (max-width: 650px) { .class { float: left; }}
@media screen and (min-width: 650px) and (max-width: 980px) { .class { float: right; }}
@media screen and (min-width: 980px) and (max-width: 1240px) { .class { float: clear; }}
@media screen and (device-width: 640px) { html { font-size: 12px; } }
@media screen and (device-width: 750px) { html { font-size: 16px; } }
@media screen and (device-width: 1240px) { html { font-size: 20px; } }
复制代码
-
优点
- 仅需要写css代码
-
缺点
-
灵活性不够,取每个设备的精确值需要自己去计算,所以只能取范围值
-
考虑设备屏幕众多,分辨率也参差不齐,把每一种机型的css代码写出来是不太可能的
-
只能选择几个主流设备呈现完美适配
-
断层式的切换变化
-
代码量大
-
三、vh/vw
- 视口的解释
在桌面端,视口指的是在桌面端,指的是浏览器的可视区域;而在移动端较为复杂,它涉及到三个视口:分别是 Layout Viewport(布局视口)、 Visual Viewport(视觉视口)、Ideal Viewport。 而视口单位中的“视口”,在桌面端,毫无疑问指的就是浏览器的可视区域;但是在移动端,它指的则是三个 Viewport 中的 Layout Viewport 。
- 视口单位主要包括以下4个:
- vw : 1vw 等于视口宽度的1%
- vh : 1vh 等于视口高度的1%
- vmin : 选取 vw 和 vh 中最小的那个
- vmax : 选取 vw 和 vh 中最大的那个
- 视口和%单位的区别:
视口单位区别于%单位,视口单位是依赖于视口的尺寸,根据视口尺寸的百分比来定义的;
%单位则是依赖于元素的祖先元素。
单位度量,视口宽度为100vw,高度为100vh(左侧为竖屏情况,右侧为横屏情况)
例如,在桌面端浏览器视口尺寸为650px,那么 1vw = 650 * 1% = 6.5px(这是理论推算的出,如果浏览器不支持0.5px,那么实际渲染结果可能是7px)。
方法1:仅使用vw作为CSS单位
- 在仅使用 vw 单位作为唯一应用的一种 CSS 单位的这种做法下,我们遵守:把设计稿的尺寸转换为vw单位
//iPhone 6尺寸作为设计稿基准
$vm_base: 375;
@function vw($px) {
@return ($px / 375) * 100vw;
}
复制代码
- 无论是文本还是布局高宽、间距等都使用 vw 作为 CSS 单位
.test {
padding: vm(15) vm(10) vm(10);
font-size: vm(10);
}
复制代码
- 物理像素线(也就是普通屏幕下 1px ,高清屏幕下 0.5px 的情况)采用 transform 属性 scale 实现。
.test {
position: relative;
&::after {
// 实现1物理像素的下边框线
content: '';
position: absolute;
z-index: 1;
pointer-events: none;
background-color: #ddd;
height: 1px;
left: 0;
right: 0;
top: 0;
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
-webkit-transform: scaleY(0.5);
-webkit-transform-origin: 50% 0%;
}
}
...
}
复制代码
- 对于需要保持高宽比的图,用 padding-top 实现
.test {
position: relative;
padding-top: percentage(100/700); // 使用padding-top
height: 0; //这个不能省
overflow: hidden;
img {
width: 100%;
height: auto;
position: absolute;
left: 0;
top: 0;
}
}
复制代码
疑问插播:
- 当margin-top、padding-top的值是百分比时,分别是如何计算的?
不管是margin-top/margin-bottom还是margin-left/margin-right(padding一样),百分数是相对最近父级块级元素的width计算
- 为什么margin-top/margin-bottom的百分数也是相对于width而不是height呢?
CSS权威指南中的解释:
正常流中的大多数元素都会足够高以包含其后代元素(包括外边距),如果一个元素的上下外边距时父元素的height的百分数,就可能导致一个无限循环,父元素的height会增加,以适应后代元素上下外边距的增加,而相应的,上下外边距因为父元素height的增加也会增加,这样就无限循环。
- 一般使用padding-top:(percentage)实现响应式背景图片,实现的基本原理?
实现的基本原理:利用百分比,保持元素的宽高比的技巧
比如一张图片的宽度是1024px,高度为316px;那么现在的 padding-top = (高度 / 宽度 )* 100% = (316 / 1024)* 100% = 30.85%;
<div class="wrap">
<div class="inner"></div>
</div>
.wrap{
max-width: 1024px;
}
.inner {
padding-top:30.85%; /* 316 / 1024 */
background: url("http://images2015.cnblogs.com/blog/561794/201603/561794-20160310002800647-50077395.jpg") no-repeat;
background-size:cover;
background-position:center; //IE8及以下不支持background-size:cover属性,为了兼容IE下面的浏览器
}
复制代码
方法一实现的页面虽然看起来适配得很好,但是你会发现由于它是利用视口单位实现的布局,依赖于视口大小而自动缩放,无论视口过大还是过小,它也随着视口过大或者过小,失去了最大最小宽度的限制,所以考虑结合rem来实现。
方法2:搭配vw和rem,布局更优化
- 给根元素大小设置随着视口变化而变化的 vw 单位,这样就可以实现动态改变其大小。
- 限制根元素字体大小的最大最小值,配合 body 加上最大宽度和最小宽度
// rem 单位换算:定为 75px 只是方便运算,750px-75px、640-64px、1080px-108px,如此类推
$vm_fontsize: 75; // iPhone 6尺寸的根元素大小基准值
@function rem($px) {
@return ($px / $vm_fontsize ) * 1rem;
}
// 根元素大小使用 vw 单位
$vm_design: 750;
html {
font-size: ($vm_fontsize / ($vm_design / 2)) * 100vw;
// 同时,通过Media Queries 限制根元素最大最小值
@media screen and (max-width: 320px) {
font-size: 64px;
}
@media screen and (min-width: 540px) {
font-size: 108px;
}
}
// body 也增加最大最小宽度限制,避免默认100%宽度的 block 元素跟随 body 而过大过小
body {
max-width: 540px;
min-width: 320px;
}
复制代码
相对于法一,个人比较推崇法二,有以下两点原因: 第一,法二相对来说用户视觉体验更好,增加了最大最小宽度的限制; 第二,更重要是,如果选择主流的rem弹性布局方式作为项目开发的适配页面方法,那么法二更适合于后期项目从 rem 单位过渡到 vw 单位。只需要通过改变根元素大小的计算方式,你就可以不需要其他任何的处理,就无缝过渡到另一种CSS单位,更何况vw单位的使用必然会成为一种更好适配方式,目前它只是碍于兼容性的支持而得不到广泛的应用。
方法3:搭配vw和vh
一屏的时候可以同时使用vw和vh作为css单位设置文本、布局高宽、间距、
-
优点
- 体验好,纯css
-
缺点
- 兼容性不好 (在移动端 iOS 8 以上以及 Android 4.4 以上获得支持,在微信 x5 内核中得到支持)
四、rem
rem属性指的是相对于根元素设置某个元素的字体大小。它同时也可以用作为设置高度等一系列可以用px来标注的单位。
- 实现思路
假设我们UI设计的标准是iphone5s,iphone5系列的屏幕分辨率是640。为了统一规范,我们将iphone5 分辨率下的根元素font-size设置为100px;
html {
font-size: 100px;
}
复制代码
那么以此为基准,可以计算出一个比例值6.4。我们可以得知其他手机分辨率的设备下根元素字体大小,需要考虑到如果是移动设备,屏幕会有一个上下限制,可以控制分辨率在某个范围内,超过了该范围,我们就不再增加根元素的字体大小:
var deviceWidth = document.documentElement.clientWidth > 1300 ? 1300 : document.documentElement.clientWidth;
document.documentElement.style.fontSize = (deviceWidth / 6.4) + 'px';
考虑到,如果转屏
window.onresize = _.debounce(function() { var deviceWidth = document.documentElement.clientWidth > 1300 ? 1300 : document.documentElement.clientWidth;
document.documentElement.style.fontSize = (deviceWidth / 6.4) + 'px';}, 50);
复制代码
在head中,我们将以上代码加入,动态地改变根节点的font-size值。
如果是320分辨率设备,1px的边框会被压缩成0.5px,可以为不同的设备设置不同的meta
所以最终代码为
<meta name="viewport" content="width=device-width,user-scalable=no,maximum-scale=1" />
<script type="text/javascript">
(function() {
// deicePixelRatio :设备像素
var scale = 1 / devicePixelRatio;
//设置meta 压缩界面, 模拟设备的高分辨率 (淘宝和网易新闻的手机web端就是采用的是这种方式)
document.querySelector('meta[name="viewport"]').setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
//为提高性能,增加节流函数
var reSize = _.debounce(function() {
var deviceWidth = document.documentElement.clientWidth > 1300 ? 1300 : document.documentElement.clientWidth;
//按照640像素下字体为100px的标准来,得到一个字体缩放比例值 6.4
document.documentElement.style.fontSize = (deviceWidth / 6.4) + 'px';
}, 50);
window.onresize = reSize;
})();
</script>
<style type="text/css">
html {
height: 100%;
width: 100%;
overflow: hidden;
font-size: 16px;
}
复制代码
-
优点
- 不需要在不同的屏幕下调整样式 (不额外增加css代码)
-
缺点
- 改html中script参数容易影响全局
- 需要内嵌一段脚本去动态计算根元素大小,使得css和js耦合在一起
五、弹性布局flexbox
容器几个重要属性:
flex-direction
flex-wrap
flex-flow
justify-content
align-items
align-content
复制代码
项目的属性:
order
flex-grow
flex-shrink
flex-basis
flex
align-self
复制代码
注:
order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。
flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。
flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。
详细请看布局教程
-
优点:
- 界面所有的元素大小和高度都会根据不同分辨率和屏幕宽度的设备来调整元素、字体、图片、高度等属性的值。简单来说就是在不同的屏幕下,你看到的字体和元素高宽度的大小是不一样的。
尽管以上多种适配方式,但是如果屏幕跨度太大,可能不仅仅是改变样式,而需要重新设计页面布局。工作中根据场景选取相应方式。
总结
在此总结几个关键的点:
5种自适应方式:
- 百分比
- vm/vh
- flexbox
- media
- rem
物理像素线(普通屏幕下 1px ,高清屏幕下 0.5px 的情况)解决办法:
- 可采用 transform 属性 scale 实现
- rem方式中可设置meta
document.querySelector('meta[name="viewport"]').setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
复制代码
不管是margin-top/margin-bottom还是margin-left/margin-right(padding一样),百分数是相对最近父级块级元素的width计算。
一般使用padding-top:(percentage)实现响应式背景图片。
当控制在1屏时候,可以结合使用vw和vh作为CSS单位
参考