移动端
特点
移动端下的屏幕存在以下特点:
-
屏幕相比较于PC端要小
-
浏览器不像PC端,随时各种调整大小
原因
移动端由于屏幕整体比PC端小,而且也不能出现拖动浏览器来调整大小的情况,所以在移动端上的布局是流式布局最多,其中有些小分支,如固定小版心。
案例
代码
普通的图片和容器,写单位的时候换成 百分比 或者 flex即可。
对于页面中的某些元素,如字体大小,可以使用 淘宝 flexibile + rem
的解决方案
一、普通的流式布局
<!DOCTYPE html> <head> body { ul { li { <body> </html> |
效果
二、淘宝flexible + rem
flexible 和flex布局没关系 老婆和老婆饼 也没有关系
这个解决方案是可以和以上的流式布局搭配使用的,rem的作用是主要是针对字体实现 跟随屏幕变化而变化
- rem css单位,相对长度,它的值等于根标签的字体大小
- 淘宝flexible
是手淘团队出的一个处理移动端rem设置的js库
把根标签的字体大小改成了 当前屏幕的十分之一大小
根标签的字体大小发生改变了,使用了rem单位的元素或者字体大小也跟着改变
手机淘宝的flexible方案,特点:
1.仅针对iphone生成动态viewport,因为目前iphone的dpr只有1,2,3三种,android的dpr很有多种,不具有一致性;
2.字体大小不用rem做缩放处理,仍然使用px单位,设置不同dpr下对应的字体大小;
3.宽度利用rem等比缩放;
4.允许强制定义dpr;
使用时页面头部需要引入flexible.js.
流程
flexible代码
<!DOCTYPE html> (function flexible(window, document) { var docEl = document.documentElement; // 设备像素比
var dpr = window.devicePixelRatio || 1; // 设置body元素字体大小:监听DOM内容是否加载完毕,完毕后给body设置字体大小 function setBodyFontSize() { if (document.body) { document.body.style.fontSize = 12 * dpr + "px"; } else { document.addEventListener("DOMContentLoaded", setBodyFontSize); } } setBodyFontSize(); // 更改根元素字体大小:设置根元素字体大小为屏幕的十分之一
function setRemUnit() { var rem = docEl.clientWidth / 10; docEl.style.fontSize = rem + "px"; } setRemUnit(); // 监听屏幕大小:监听屏幕大小的变化,有变化调用更改根元素字体大小函数
window.addEventListener("resize", setRemUnit); window.addEventListener("pageshow", function (e) { if (e.persisted) { setRemUnit(); } }); if (dpr >= 2) { var fakeBody = document.createElement("body"); var testElement = document.createElement("div"); testElement.style.border = ".5px solid transparent"; fakeBody.appendChild(testElement); docEl.appendChild(fakeBody); if (testElement.offsetHeight === 1) { docEl.classList.add("hairlines"); } docEl.removeChild(fakeBody); })(window, document); </script> <body> </div> setFont();
</html> |
flexible效果
综合flexible 和 rem
根据以上的特点
-
flexible
把 根标签字体大小改为 屏幕的十分之一 -
rem
可以根据根标签的字体大小改变而发生改变
得出以下解决方案
-
假定设计稿的宽度 是
640px
-
根标签的字体大小为
64px
也就是1 rem = 64px
=>1px=1/64rem
-
原设计稿中的div大小为100px,字体大小为100px
-
将px单位修改为 rem单位
div{ |
5. 将设计稿的宽度也抽象出去
div{ |
完整代码
<!DOCTYPE html> (function flexible(window, document) { var docEl = document.documentElement; // 设备像素比
var dpr = window.devicePixelRatio || 1; // 设置body元素字体大小:监听DOM内容是否加载完毕,完毕后给body设置字体大小 function setBodyFontSize() { if (document.body) { document.body.style.fontSize = 12 * dpr + "px"; } else { document.addEventListener("DOMContentLoaded", setBodyFontSize); } } setBodyFontSize(); // 更改根元素字体大小:设置根元素字体大小为屏幕的十分之一
function setRemUnit() { var rem = docEl.clientWidth / 10; docEl.style.fontSize = rem + "px"; } setRemUnit(); // 监听屏幕大小:监听屏幕大小的变化,有变化调用更改根元素字体大小函数
window.addEventListener("resize", setRemUnit); window.addEventListener("pageshow", function (e) { if (e.persisted) { setRemUnit(); } }); if (dpr >= 2) { var fakeBody = document.createElement("body"); var testElement = document.createElement("div"); testElement.style.border = ".5px solid transparent"; fakeBody.appendChild(testElement); docEl.appendChild(fakeBody); if (testElement.offsetHeight === 1) { docEl.classList.add("hairlines"); } docEl.removeChild(fakeBody); })(window, document); </script> div {
calc(100rem / 64);
height: calc(100rem / 64);
font-size: calc(100rem / 64);
background-color: aqua;
}
</style> <body> </div> setFont();
</html> |
最终效果
三、小版心
小板心的做法其实也是流式布局中的一种,只不过对最外层容器加了一个最大宽度的设置如
main{ |
参考
四、vw 和 vh
在移动端中,还存在以下单位,也很好用,可以很方便解决问题。
以上单位 在移动端中,或者在小程序中都支持。
设计稿为 375px
,存在一个大小为100px
的div
,字体大小也为100px
。
-
375px = 100 vw
那么1 px = 100vw / 375
-
因此
100px = 100vw * 100 / 375
;
代码
main { |
详细介绍
老版常规做法
方案一:Meida Queries媒体查询
meida queries
主要是通过查询设备的宽度来执行不同的 css
代码,最终达到界面的配置。核心语法是:
@media screen and (max- 600px) { /*当屏幕尺寸小于600px时,应用下面的CSS样式*/ |
需要添加meta设置
<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 :表示宽度是设备屏幕的宽度
initial-scale=1.0:表示初始的缩放比例
minimum-scale=1.0:表示最小的缩放比例
maximum-scale=1.0:表示最大的缩放比例
user-scalable=no:表示用户是否可以调整缩放比例
这个标签可以保证在移动端设备中,页面的宽度与屏幕宽度相同。
方案二:px + viewport缩放
以最小的Iphone4/5的宽度(320px)为基准,还原视觉稿。
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0 /> |
然后对不同屏幕分辨率的手机进行简单粗暴的等比例缩放设置。 例如:iphone8(375px)initial-scale = 375 / 320 = 1.18
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.18 /> |
initial-scale越来越大,页面内容也就被拉伸也越厉害,导致页面内容会变得模糊,这个方法已经被摒弃了。
高度定死,宽度自适应,元素都采用px
做单位。
随着屏幕宽度变化,页面也会跟着变化,效果就和PC页面的流体布局差不多,在哪个宽度需要调整的时候使用响应式布局调调就行(比如网易新闻),这样就实现了『适配』
方案三:响应式布局
响应式的概念分为两大类
-
一种是后端响应式
-
一种是前端响应式
后端响应式
后台服务器根据前端浏览器的User-Agent
来判断来源请求是PC端还是移动端,然后服务器动态返回PC端页面或者移动端页面。nginx中很容易就出现该功能。京东,天猫,淘宝也是这样子的。
前端响应式
主要是指通过媒体查询来实现。
前端写好一套代码 html + css + javascript
,就可以冬天的根据屏幕的宽度来改变页面的样式
这种做法体验不是最好,但是却是最小的代码实现了 兼容pc端和移动端。一般是对页面要求不高或者小企业使用。
由于还要兼容到pc端,所以一般做响应式页面 不会用太高级的h5 css3 的技术。
新做法
方案四:rem + viewport缩放
需要添加meta设置
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> |
换句话说,当我们指定一个元素的font-size为2rem
的时候,也就说这个元素的字体大小为根元素<html>
字体大小的两倍,如果html
的font-size为12px
,那么这个2rem
的元素font-size就是24px
。同理当该元素为3rem
时,那么其实际
font-size就是36px
。
h1 { font-size: 2rem; } /* 2 × 12px = 24px */ p { font-size: 1.5rem;} /* 1.5 × 12px = 18px */ div { 20rem;} /* 20 * 12px = 240px*/ |
看到这里你应该就会发现,只要我们根据不同屏幕设定好根元素<html>
的font-size,其他已经使用了rem单位的元素就会自适应显示相应的尺寸了。
rem计算
我们使用rem单位事先需要做的一件事情就是设置根元素<html>
的font-size,通常有两种做法
方法一:JS计算
通过JavaScript读取屏幕宽度,然后根据宽度计算出对应的尺寸并设置根元素的font-size。
const oHtml = document.getElementsByTagName('html')[0] const width = oHtml.clientWidth; // 320px的屏幕基准像素为12px oHtml.style.fontSize = 12 * (width / 320) + "px"; |
这样iphone8(375px)下html
的font-size 就是14.0625px,iphone8p下font-size就是15.525px。
如果在iphone8(375px)下设置元素font-size为 1.7066rem, 效果跟设置其font-size为 24px 是一样的(24 / 14.0625 = 1.7066)。
使用JS来获取屏幕宽度的好处在于可以100%适配所有的机型宽度,因为其<html>
元素的基准尺寸是直接算出来的。既然是JS代码,为了避免造成因为动态设置<html>
元素的font-size而造成页面抖动,一般这部分代码我们放在header
底部去加载,并内联到html文档里面。
实战
将根元素的font-size扩大100倍,使用px的时候,根据设计图除以100得到想要的px
!new function() {
var a = this;
a.width = 750,
a.fontSize = 100,
a.widthProportion = function() {
var b = (document.body && document.body.clientWidth || document.getElementsByTagName("html")[0].offsetWidth) / a.width;
return b > 1 ? 1 : b
},
a.changePage = function() {
document.getElementsByTagName("html")[0].setAttribute("style", "font-size:" + a.widthProportion() * a.fontSize + "px !important")
},
a.changePage(),
window.addEventListener("resize",
function() {
a.changePage()
},
!1)
};
|
方法二:媒体查询
既然只是为了根据屏幕宽度来设置<html>
元素的字体大小,那我们完全也可以通过css3媒体查询来完成这部分工作。
html { font-size: 14.0625px; } } @media screen and (min- 360px){ html { font-size: 13.5px; } } @media screen and (min- 320px){ html { font-size: 12px; } } html { font-size: 16px; } |
rem存在的问题
rem作为一种简单粗暴解决不同屏幕下视图的区别的一种方案,它可以解决本文出现的问题以及绝大多数移动端适配屏幕尺寸的问题。但是既然它并不是一个完美的解决方案,那就有其局限性所在。
大屏智能机时代确实几乎完全替代了我十年前纸质化阅读的习惯。从2011年至今,手上的手机屏幕宽度一直在提升,但是使用的看小说软件的显示字号几乎是不变的。使用rem会在一定程度上打破用户的文字内容阅读习惯,特别是在大篇
幅的内容时。
iOS与Android平台的适配方式背后隐藏的设计哲学是这样的:阅读文字时,可读性较好的文字字号行距等绝对尺寸数值组合与文字所在媒介的绝对尺寸关系不大。(可以这样简单理解:A4大小的报纸和A3大小甚至更大的报纸,舒适的阅
读字号绝对尺寸是一样的,因为他们都需要拿在手里阅读,在手机也是上同理);在看图片视频时,图片、视频的比例应该是固定的,不应该出现拉伸变形的情况。而rem用在字号时,使字号在不同屏幕上的绝对尺寸不一致,违背了设计
哲学。
方案五:vw + vh
参考
阿里巴巴TXD移动端适配总结(viewport讲的不错)