页面布局的方式总是随着技术的更新和创意的涌现不断的更新换代.从最开始的 固定布局「Fixed」到因为宽屏设备和移动互联网的普及产生的响应式和自适应,再到「Mobile First」的设计理念,前端们在可用性和适配性上做的贡献越来越多
页面布局是 CSS 的一个重点应用
网页布局类型
常见的布局方式大致有以下几种:
固定布局 【Fixed】
流式布局 【Fluid】
rem 布局 【Rem】
弹性布局 【Flexbox】
响应式布局 【Responsive】
1. 固定布局 [px]
顾名思义,页面上的所有元素的尺寸一律使用 px,pt 这种固定单位编写,在 <head> 里把
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
然后根据设计稿的宽高设定实现稿即可.
这种方式简单易上手,缺点显而易见,不能根据不同的屏幕做出不同的表现.例如直接设定主体宽度,然后居中展示,两边留白.宽屏两边留白多,窄屏两边留白少.
移动端使用固定布局
在 viewport meta 标签上设置
content = "width = 320"
, 页面的各个元素也采用 px 作为单位.通过用 JS 动态修改标签的 initial-scale 使得页面等比例缩放, 从而刚好占满整个屏幕.这种方案类似弹性布局的 rem.
在 viewport meta 标签上设置
content = "width = 640,user - scalable = no"
,页面的各个元素采用 px 作为单位.由于手机浏览器的宽度小于 640px(逻辑像素)(iphone plus 系列为 414px),所以浏览器 viewport 会自动缩放至全屏大小.经典案例: 荔枝 FM, 人人都是播客 的移动站
优势:
开发简单: 缩放交给浏览器,开发人员不需要自己操心,完全按照视觉稿切图
还原精准: 绝对等比例缩放,可以精准的还原原始视觉效果(会有清晰度的失真)
测试方便: 可以在 pc 端实现大部分的测试工作,即开发人员自己就能完成测试的大部分工作,手机端只要修改一些细节.
劣势:
像素丢失: 对于一些分辨率较低的手机,可能设备像素还未达到 viewport 指定的宽度,此时可能出现边框丢失等问题.现代手机基本不会发生这种情况.
缩放失效: 早期 android 手机不能根据 meta 中的 width 来进行缩放,需要配合 initial-scale.这种完全依赖浏览器的方式也难免可能发生异常.
文本折行: 会发生在缩放失效的机型中.
2. 流式布局 [%]
网页中主要使用百分比(%)来划分区域,往往配合 max-*,min-* 等属性控制尺寸流动范围以免过大或者过小影响阅读,让不同分辨率屏幕尽可能实现自适应.
例如,设置网页主题宽度为 80%,min-width 为 960;图片也做类似处理(例如
width:100%; max-width:图片原始尺寸,防止拉伸
).这种开发方式在早期的 web 开发时用来对应不同的 PC 屏幕(那时不会相差太大),现在也常用在移动端开发上.
缺点:
宽度使用百分比定义,但高度和文字大小都是用 px 来固定,所以在大屏幕手机下的显示效果有些元素(例如 width=100%)会被拉伸的很长,但是高度,文字大小还是和原来一样(即有些元素无法变得流式,显得很不协调).
3. rem 布局
REM,即 font size of the root element,使用 rem 单位进行相对布局,通过根元素进行适配,它好比是一个中介,通过它计算出页面真正要展示的大小, 达到自适应效果.(有时需要配合媒体查询),常用于移动端开发.
rem 避免了根据 px 布局在高分辨率下几乎无法辨认的缺点,又相对 % 百分比更加灵活,同时可以支持浏览器的字体大小调整和缩放等的正常显示.一般编写时需要对 UI 稿做转换,也有编辑器可以安装单位转换插件.例如 ATOM 的 px2rem 插件
实现 rem 的核心,就是针对并监听不同尺寸的手机屏幕计算出相应的比例,以下代码通常写在 app.js(第一个加载的 js 文件) 最上方:
解释一下:
// rem布局的核心代码. 此例默认UI稿按 1080 * 1920 提供
(function(win, doc) {
var docEl = doc.documentElement,
resizeEvt = 'oritationchange' in window ? 'oritationchange': 'resize',
recalc = function() {
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
if (clientWidth < 640) {
docEl.style.fontSize = 100 * (clientWidth / 1080) + 'px';
} else {
docEl.style.fontSize = 100 * (clientWidth / 1920) + 'px';
}
if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DomContentLoaded', recalc, false);
})(window, document)
当浏览器将我们的项目下载完成时,开始解析 DOM 树,触发
doc.addEventListener('DomContentLoaded', recalc, false)
,执行 recalc 方法,计算出当时条件下的适配比 rem,执行页面渲染.当用户手机屏幕发生横竖屏翻转时,BOM 捕捉到事件变化, 触发
win.addEventListener(resizeEvt, recalc, false)
执行 recalc 方法,重新计算新的适配比 rem,页面响应变化.
if (clientWidth < 640)
监控并区分用户手机屏幕是处在横竖屏什么状态下,640px 是手机屏幕的最大安全宽度,超过 640 就认为是横屏状态.
至于缩放比是要设置 100,10 还是 24(移动端常用大小),你开心就好. 总之,计算规则就是 【 1px * 缩放比 == 1rem 】
这种布局方式编写简单,适配能力强,容易理解,易于维护.
# 但 rem 也不是万能的,比如:
用户修改字体大小,强行改变手机逻辑像素表现形式,rem 布局不能感知这种状态,会出现元素偏移的现象
当用户切换横竖屏需要展示不同效果时,rem 无法实现.
解决办法:问题 1 可以配合 css 位置属性 或局部使用其他的的布局方式(如以下将要介绍的 flex 布局)调整恢复;问题 2 可以使用媒体查询 或通过 js 动态修改样式.
4. 弹性布局 [flex]
flex 布局是 W3C 在 2009 年提出的方案. 传统的布局方式,基于盒模型,依赖于 display + position + float 等属性,他们对于特殊布局非常不方便,比如垂直居中.而 flex 可以为盒模型提供最大的灵活性.
任何一个容器都可以指定为 flex 布局,包括行内布局.如果是 webkit 内核,必须加 - webkit- 前缀
注意:设置为 Flex 布局以后,子元素的 float,clear 和 vertical-align 属性将会失效.
<div class="box">
<span class="item"></span>
</div>
.box {
-webkit-display: flex;
display: flex
}
span {
display: inline-flex;
}
# flex 基本概念: '容器' - '项目' - '轴'
flex 布局结构示意图
轴【axis】: 水平的主轴 main axis 的起始位置为 main start ,结束的位置为 main end; 垂直的交叉轴 cross axis 的起始位置为 cross start,结束位置为 cross end;
容器【flex container】和 项目【flex item】: 项目在容器内部,默认沿着主轴排列,单个项目占据主轴为 main size, 占据交叉轴为 cross size;容器可以简单理解为父元素,项目可以简单理解为子元素
项目其实可以理解为 子容器,对于 flex,核心点只有两个:容器 和 轴
# 为容器增加属性 -【父元素】
1. flex-direction (元素排列方向),可选值:(默认) 水平,水平右到左,垂直,垂直下到上
.box { flex-direction: row | row-reserve| column | column-reserve }
2. flex-wrap (元素的换行方式),可选值:(默认) 不换行,往下换行,往上换行(第一行在下方)
.box { flex-wrap: nowrap | wrap | wrap-reserve }
3. flex-flow (以上两者的简写),默认为: 水平 || 不换行
4. justify-content (主轴对齐方式),可选值:(默认) 左对齐,右对齐,居中,充满两边靠边,充满两边留边
.box { flex-flow: flex-direction || flex-wrap }
// 例
.box { flex-flow: row nowrap; }
.box { justinfy-content: flex-start | flex-end | center | space-between | space-around }
5. align-items (交叉轴对齐方式),可选值:上对齐,下对齐,中部对齐,(默认) 拉伸至上下占满,首行文字的基线对齐
.box { align-items: flex-start | flex-end | center | stretch | baseline }
6. align-content (多根轴线的对齐方式) 可选值:上对齐,下对其,中部对齐,(默认) 均匀拉伸至上下占满,充满上下中部均分,充满上下两边留空中部均分
1. order (项目的排列顺序),可选值: 数值(越小越靠前,相同按文档流顺序展示)
.box { align-content: flex-start | flex-end | center | stretch | space-between | space-around }
# 为项目增加属性 -【子元素】
,item { order: <integer>; } /* default 0 */
2. flex-grow (项目的放大比例),可选值:数值(0 表示按原大小展示;都定义为 1 表示所有项目均分可用空间;定义某个为 2 其余都为 1,则 2 的占用 1 的两倍然后所有项目占满空间)
.item { flex-grow: <number>; } /* default 0 */
3. flex-shrink (项目的缩小比例),可选值:数值(0 表示按原大小展示;都定义为 1 表示空间不足时等比缩小;定义某个为 0 其余都为 1,空间不够时 0 的不缩小,其余按等比缩小.负值无效)
.item { flex-shrink: <number>; } /* default 1 */
4. flex-basic (项目占用主轴空间), 可选值:(根据 flex-direction 定义的主轴 (水平或垂直) 来定义项目本来的大小,跟 width/height 一样;如果设定跟 width 和 height 一样的值,则项目将占据固定空间)
.item { flex-basic: <length> | auto; } /* default auto */
5. flex (前三者的简写【推荐】),可选值:auto (1 1 auto) ,none (0 0 auto),自定义值 (n, n, length);auto 表示空间大了自动放大,空间小了自动缩小;none 表示无论空间如何,大小固定不变.推荐优先使用 auto 或 none
flex
/* default 0 1 auto ; 空间大了保持不变,小了自动缩小*/
.item { flex: auto | none | [<'flex-grow'> <'flex-shrink'>? || <'flex-basic'>] }
5. align-self (某项目和其他项目不一样的对齐方式,覆盖 align-item),可选值:auto(继承父元素 align-items),上对齐,下对齐,中部对齐,首行文字基线对拉伸;要区分 align-items 是设置在容器上的属性,align-self 是设置在项目上的属性.
flex 属性树
/* default auto */
.item { align-self: auto | flex-start | flex-end | center | baseline | stretch; }
# flex 总结
5. 响应式布局 [media query]
响应式布局的设计思路和其他布局思路大同小异,都是为了同一套代码适配不同媒体设备.因为由于越来越多的移动设备加入到互联网大军中,移动端将不能再被忽视,移动终端的分辨率和 pc 端有较大差异,为了让用户的体验更好,代码就需要兼容不同的屏幕.
主要分两类: RWD 响应式 和 AWD 自适应,
RWD = (Responsive Web Design):media query + 流体布局 + 自适应图片 / 视频资源
AWD = (Adaptive Web Design):media query + js 操作 dom + 在服务端操作 dom
这里主要介绍响应式:
很粗糙的解释,步骤大致是:
编写非响应式代码(适配主要屏幕的设备代码,遵循 Mobile First)
加工成响应式代码 (增加媒体查询语句)
响应式细节处理,代码自测
完成响应式开发
# 实现响应式布局设计具体步骤
1. 布局及设置 meta 标签
主要是为了让代码适应移动端的屏幕.解释一下,viewport 是指需要加载 meta 标签时读取的名字为'视口',其中,width 等于设备的宽度 device-width,是为了告诉浏览器,将布局视口的宽度设置为设备理想的宽度,initial-scale=1(缩放比例) 保证加载的时候,要获取设备的宽度,同时要保持原始大小,便于媒体查询.user-scalable=no 指定不允许用户缩放屏幕.
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="HandheldFriendly" content="true">
2. 通过媒体查询来设置响应式样式
media query 是响应式布局的核心,他们够和浏览器进行沟通,告诉浏览器页面改如何呈现,假如要适配一个大小为 414 逻辑像素的屏幕 (iphone6 plus),应该这么写:
我喜欢设置范围,也可以设置具体值:(max-width: 414px)
然后我们将该片段放置在样式文件的尾部,以保证覆盖非响应代码的样式.再如:假如我们要兼容 iPad 和 iphone,应该这么设置:
@media screen and (max-width < 500) {
.my_class {
font-size: 24px;
color: #3d77e0;
}
}
3. 字体设置 - 推荐 rem
@media screen and (min-width>768px) and (max-width<1024px) { } // ipad
@media screen and (min-width>320px) and (max-width<767px) { } // iphone
在 css3 之前,大部分开发人员使用的都还是 px,但 px 是绝对单位,并不能响应随着屏幕变化而变化的父容器,css3 引入了 rem,完美解决此问题.注意不要忘记响应变化时重置根元素的大小.
其实这里就是使用的rem布局的知识,不理解的建议回头看看rem布局.
html { font-size: 24px; }
@media ( min-width>640px ) { html {font-size: 28px} body { font-size: 1.2rem } }
@media ( min-width>767px ) { html {font-size: 32px} body { font-size: 1.2rem } }
@media ( min-width>960px ) { html {font-size: 36px} body { font-size: 1.2rem } }
4. 需要注意的点
(1):宽度不能固定,可以使用百分比,即流体(fluid grids)
(2):图片处理
body { width: 100%; }
.content { width: 50%; }
html 中的图片,为了最大化让图片保持原始效果,可以如下这么设置:
这么设计是为了:当图片小于给定空间时按原始尺寸显示,当超出时就缩小至容器大小.
.wrap img {
width: auto;
max - width: 100 % ;
height: auto;
}
除了 img 标签的图片外我们经常会遇到背景图片,比如 logo 做背景,可以这么设置:
background-size 是 css3 新增的属性,用来设置背景图片的大小,有两个可选值,表示 width 和 height,如果只指定一个,另一个则为 auto.设置 100% 100% 使图片总是充满元素容器,这有可能使得图片变形.另外
.box {
background: url('icon/logo.png') no - repeat;
background - size: 100 % 100 % ; // css3
}
background - size: cove;
表示等比扩充比例用来填满元素,这有可能使得图片内容显示不全,但不会被拉伸或挤压.
background - size: contain;
表示等比缩小比例来适应元素的尺寸,则有可能使得元素容器部分区域空白.
还可以使用::before 和::after 伪元素 + content 属性来动态显示一些内容.
6. 最后 但同样重要
自习对比几种布局方式可以发现,各大布局并不独立,反而相辅相成,互相渗透,想单独用某种布局来实现一个产品很难,我们也没必要这么做.
目前采用最多的是 rem 布局 + 响应式布局的 media query,基本能实现较为复杂的页面效果,当然还有一些效果如垂直居中,也能引入弹性布局 flex 来实现;容器,图片,背景图片设置,流式布局的效果相对好一些;如果没有特殊需求,尽量还是少用绝对布局,坑太多不好维护.
总之,遵循一个原则,结合具体需求,那种适配性高些,哪种后期维护容易些,就使用哪种.
# 最后的最后,但不重要
我的下一篇文章: 《布局的具体设计与实现》,如果觉得我写的还不错的朋友,可以关注我,我们一起成长.
来源: http://www.jianshu.com/p/d25ae141109a