像图片一样布局

来源:互联网 发布:ps怎么修改淘宝主图 编辑:程序博客网 时间:2024/04/30 13:39

转载地址:https://github.com/xiangpaopao/blog/issues/9


移动端经常会有这样的展示页面,页面中有一些独立的元素,并且伴随各种交互效果、转场动画。

img img

针对页面布局的话,大概有这样的需求:

  • 不滚动页面,所有元素均在一屏之类展示
  • 像图片那样缩放元素---宽度改变时高度按比例变化
  • 背景图需要把浏览器窗口撑满
  • 往往项目是独立的,需要快速上线,开发周期短

这种形式页面在正常的文档流中布局显然不太合适,比较传统的做法是这样:

  • 布局以绝对定位为主
  • 用百分比配合px控制宽高、位置
  • 背景图用background-size:cover撑满
  • 用css媒体查询来适应多种屏幕
  • css搞不定的请js帮忙

布局一个单屏展示页

比如这样一个640*960的设计稿,分背景和按钮两层,要求背景全屏(可以不显示全)按钮定位在精确的位置上。

img

传统做法

一般会把背景图用background-size:cover显示在一个宽高撑满屏幕的容器上以适应各种屏幕, 这个按钮怎么定位呢,一般是会这样做吧position:absolute;bottom:18%;

模拟一下iPhone5微信中的显示
img

iPhone4微信中的显示
img

可以看到iPhone4中按钮错位,原因是当屏幕尺寸改变时,背景图与按钮的尺寸与位置会遵循不同的规则变化。这个例子中的效果貌似还能接受,可有些场景对定位的要求可能比这更高。

解决这个问题一般会用媒体查询针对屏幕做适配吧

@media screen and (max-height: 500px) {  .btn{    bottom:12%;  }}

Demo 在这里 http://jsbin.com/zugape/edit

如果页面中元素多、定位要求精确,这种做法是比较暴力的。下面是支付宝十年晒单页面中针对不同尺寸屏幕做的适配

/* <=640 */@media screen and (min-width: 319px) and (max-width: 321px) {    ...}/* 720 */@media screen and (min-width: 359px) and (max-width: 361px) {    ...}/* 1024*768, 2056*1536 */@media screen and (min-width: 383px) and (max-width: 385px) {    ...}/* 800 */@media screen and (min-width: 399px) and (max-width: 401px) {    ...}/* 1080 */@media screen and (min-width: 539px) and (max-width: 541px) {    ...}/* 1200 */@media screen and (min-width: 599px) and (max-width: 601px) {    ...}/* 1440 */@media screen and (min-width: 719px) and (max-width: 721px) {    ...}/* 1600 */@media screen and (min-width: 799px) and (max-width: 801px) {    ...}/* for small screen */@media screen and (max-height: 500px) {    ...}/* for iPhone6 Plus */@media only screen and (device-width: 414px) and (-webkit-min-device-pixel-ratio: 3),only screen and (device-width: 375px) and (-webkit-min-device-pixel-ratio: 3){    ...}

总结下这种方式的缺点:

  • 要把设计稿中的PX在大脑中换算成%
  • 百分比控制宽高是相对于父元素,计算繁琐
  • 用媒体查询针对各种尺寸的屏幕做兼容工作繁琐

图片的自适应规则

一张图片如果给他设置<img src="pic" style="max-width: 100%;max-height:100%” />的话,无论视口大小,他都会显示在视口里面,如图
img img

类似的还有图片作为背景显示时的background-size属性。
background-size: contain:缩放图像的最大值,其宽度和高度都能放入内容区域
img

background-size: cover:缩放图像的最小值,其宽度和高度都能放入内容区域
img

当你改变图片的宽度或高度时,图片的另一边会自动按比例缩放,如果div有这种能力多好啊!

vw、vh--为移动而生

vw、vh是CSS3中出现的新的长度单位,vw 相对于视窗的宽度,视窗宽度是100vw;vh 相对于视窗的高度,视窗高度是100vh。
其中视窗指的是浏览器实际显示区域,即window.innerWidth/window.innerHeight的大小。
如 想一个元素的宽是视口宽的一半,只需设置width:50vw

与百分比的异同

乍一看好像和百分比类似,并没发现多少优势,在进行一些尝试之后我总结了一下他们的异同

百分比vw、vh相对父级元素相对视口横向/纵向相对父级横向/纵向vw/vh相对视口宽/高(即写vh就是相对视口高、写vw就是相对视口宽,不必横向与横向纵向与纵向对应)对字体大小无效对字体大小有效

Tips:其实margin-top/bottom以百分比为单位时他的参照对象并不是父元素的height而是width。详情阅读 doyoe margin系列文章

这些特性可以实现一些之前用CSS难以解决的问题。

相对视口100%高度

由于百分比高度是相对父级的,之前如果想让文档流中的某容器相对视口高度100%,只用css的话得从html>body>element一层层下来都设置height:100%,而现在只需给元素设置height:100vh
height 100% Demo http://jsbin.com/risegu/edit

响应式文字 && 像图片一样布局

先上Demo
百分比方式 http://jsbin.com/vemudo/edit
vw方式 http://jsbin.com/huwido/edit 
这两个Demo建议把浏览器模拟成移动设备的样子,拉伸浏览器窗口宽度观察效果。

img img

可以看到当浏览器宽度改变时,百分比Demo中只有元素的宽度发生了变化,而统一使用vw做单位的Demo中文字的大小、元素的高度与宽度均按缩放比例发生了变化,这正是我们想要的“像图片一样布局”的效果。

vmin 与 vmax

还有vw、vh延生出来的单位vmin、vmax。
vmin:关于视口高度和宽度两者的最小值
vmax:关于视口高度和宽度两者的最大值

我觉得这是一组神奇的单位,但是暂时对这个使用场景的理解有限,能想到的场景是一个正方形,height:100vmin;width:100vmin时,得到的是这个视口中能显示满的一个最大正方形(http://jsbin.com/baheko);height:100vmax;width:100vmax时得到的是能把这个视口全部显示满的最小正方形(http://jsbin.com/tamasi)。

然后在codepen上找到这样一个demo,他让16:9的视频窗口在视口中自适应http://codepen.io/CreativeJuiz/pen/KzkgL

其他适用场景有待发掘

vw、vh的问题

vw vh 在桌面端浏览器兼容性已经是比较好了,不过在移动端貌似还需要等待,国产安卓浏览器的话UC到现在都不支持真不让人省心。
img

另外对张鑫旭的视区相关单位vw, vh..简介以及可实际应用场景 中他的结论:vw vh只适用于非定位元素;vh高度值的内部元素不支持百分比%高度 有些疑问,我在测试中并未发现这样的情况,这篇文章写于2012年,不知道是不是这样的情况只发生在当时的浏览器。Demo http://jsbin.com/dineka/edit

rem方案

回头来看我们的布局,vw vh的方案因为兼容性问题只能放弃,重新分析下我们的需求:
其实我们需要那么一个全局的相对单位...
我们可以通过修改这个单位来控制整个布局...
我们可以通过判断屏幕的比例来缩放整个页面以展示全部内容...

然后想到类似手机淘宝的动态rem的方案:所有布局元素单位使用rem,由于rem是相对于根元素的,所以不同屏幕按一定规则控制的font-size 即可兼容各屏幕。

var root = document.getElementsByTagName('html')[0],    NATIVE_W = 640;function updateSize() {    var w = window.innerWidth;    var cw = w / (NATIVE_W / 100);      root.style.fontSize = cw + 'px';}window.onload = updateSize;window.onresize = updateSize;

这样的页面一般会有设计稿的,我们需要设置rem和设计稿中px的转换比例。
1rem = 1px 这样固然方便,但是有些浏览器有最小字体的限制。
所以我想让 1rem = 100px。
我们的设计稿一般为640 x 960,这个尺寸是针对iPhone4,设备像素比是2,那么我们实际需要html的font-size为50px。
这样的话假如设计稿中一个元素尺寸为240px x 200px,
那么这个元素需要在屏宽为320px的设备上显示的尺寸是120px x 100px,而我们需要他在布局时设置的宽高是2.4rem x 2rem。
设计稿宽640px 也就是整个页面应为 6.4rem。 所以对应不同宽度的设备时用window.innerWidth(视口宽) / 6.4 得到的就是对应此设备的font-size。
布局时,把设计稿上的尺寸除以100然后把px单位换成rem。

怎么解决比较短的屏幕显示不完全的情况呢,可以先判断一下视口的比例,当视口高宽比低于设计稿宽高比时,缩小html节点的font-size这样就能把内容显示全了

var root = document.getElementsByTagName('html')[0],    NATIVE_W = 640,    NATIVE_H = 960;function htmlSize() {    var cw = 50,        w = window.innerWidth,        h = window.innerHeight;      if ((w / h) > (NATIVE_W / NATIVE_H)) {        cw = h / (NATIVE_H / 100);    } else {        cw = w / (NATIVE_W / 100);    }    root.style.fontSize = cw + 'px';}window.onload = htmlSize;window.onresize = htmlSize;

Demo http://jsbin.com/rupole/edit
可以试下缩小、拉大窗口布局也会像图片那样相应变化,并且无论窗口是什么样的尺寸,元素都会出现在比较合理的位置,当然,一些特殊情况仍然要用媒体查询来适配。

然后在布局时,其实只要把这段js放在页面中,就rem当成px来用就行了,不需要多考虑啥,这个方案的优点就是构建页面成本低,跨屏显示效果也能满意。

calc

另外有些元素我们想他垂直方向上针对中心定位而不是顶部或底部,比如想让一个小球居中之前大概是这样:

#cir{  width:200px;  height:200px;  border-radius:100px;  background:#888;  position:absolute;  left:50%;  top:50%;  margin-left:-100px;  margin-top:-100px;}

其实CSS3中有这样一个表达式:calc()(CSS里居然有这玩意,我第一次看到时怀疑是不是SASS或LESS里的),他可以给元素的border、margin、pading、font-size和width等属性动态计算值,例如:top:calc(50% - 1rem),这在这种展示页面的布局中是相当有用的,上面的css可以改写成:

#cir{  width:200px;  height:200px;  border-radius:100px;  background:#888;  position:absolute;  left:calc(50% - 100px);  top:calc(50% - 100px);}

Demo http://jsbin.com/gasato/edit

关于更多calc的介绍建议阅读大漠的这篇博文 http://www.w3cplus.com/css3/how-to-use-css3-calc-function.html

遗憾的是这玩意在桌面端浏览器中支持的已经比较好了,不过在移动端的表现令人堪忧,安卓原生浏览器从4.4开始支持,而最新版的安卓UC仍然不支持。

img


0 0