CSS布局在前端开发中像呼吸同样——再日常不过的事。好比同事A在尝到了Flexbox布局的甜头以后,任何布局都会以display:flex
打头阵,同事B由于项目得支持IE10,像避开毒蛇同样的避开Flexbox布局方法。你会发现我可能有点嗤笑这样的行为,我曾经也是这样的一员,我想为这个问题——当遇到css布局,你在考虑什么? 整理一个完整的解决方案。javascript
你在考虑什么:从什么样的HTML结构出发可以帮助到css布局?你的布局方法武器库都有什么,在具体场景下,选择什么合适的布局方法?须要作支持旧浏览器吗?Flexbox、Grid这些布局的方法弄潮儿在旧浏览器中的最佳实践是?等等等等。css
本文将介绍个人"答案",欢迎胖友们补充、更正。html
Normal flow(不知什么中文翻译妥帖,仍是扔了英文...)指的是若是没有改变css布局代码,网页中标签的默认表现方式。好比demo-normal-flow:块级标签p
挨个从上往下,而内联标签span
表现得像段落中的文本。前端
当咱们建立、自定义一个布局,实际上是调整标签在Normal flow中的位置,或是直接从Normal flow移除,咱们最最原始的材料就是Normal flow。若是使用语义化标签(semantic markup),从一个结构良好的HTML文档开始是颇有帮助的:java
HTML5新加了些帮助结构化的标签,html-document-structured 这篇文章能够参考,这里作一个overview:git
header
:body
、main
标签的直接子标签,位置在页面头部,内容可能为logo、标语、搜索提示、导航栏;nav
:导航栏包在nav
标签内,可能出如今头部、侧边栏、底部等等,这里有个demo-mdn-nav,神奇的地方在于设置nav
标签的display:inline-block
,是做用在li
标签上的;main
:body
标签的直接子标签,主内容区域;aside
:侧边栏;article
:通常出如今main
标签内,article
标签内能够有section
、footer
等标签,是比较独立的内容,好比像博客网站主页的一个文章简介;section
:section
和div
很相似,若是使用div
标签是为了对内容作样式控制,或者为了便于javascript获取作其余操做,那么使用div
就是你的答案,其余状况就用section
;address
:提供联系信息,放在article
标签内提供文章做者信息,放在main
、body
、footer
内提供网站信息;footer
:通常在HTML结构底部,补充网站信息,若是放在article
内补充文章信息; Normal flow是CSS布局的起点,更好的选择是语义化标签(semantic markup)做为CSS布局的起点。github
css布局方法有不少,如Flexbox、Grid、Float等等等等,在使用以前得把握两个中心思想:web
接下来主要以讲demo的形式介绍各个布局方法的使用场景,对于布局方法自身如何使用不会过多说明。浏览器
Flexbox是Flexible Box Layout的简称,Flexbox既能够用于整个页面的布局,也能够用于局部部件的布局。Flexbox存在些浏览器兼容性的问题,在旧浏览器中的实践会在以后说明。接下来几个场景是创建在浏览器支持Flexbox的前提下。服务器
Flexbox全称Flexible Box Layout中的Flexible(灵活性),是它的立命之本。Flexbox的第一个使用场景也呼之欲出——Flexing sizing of flex items,也就是盒子尺寸的高度灵活性:
section
标签是Flex容器,article
标签是Flex item,其中前面两个article
标签flex:1 200px
,最后一个article
标签flex:2 200px
。具体表现为,若是不能提供3个Flex item都是200px
宽度的空间,则它们仨宽度一致,若是能提供,剩余空间按照1:1:2分配;footer
标签高度固定,section
标签由于flex:1
而占据余下全部空间。在水平方向,也能够是侧边栏宽度固定,主要内容占据余下全部空间;Flexbox提供像align-items
、justify-content
这样的属性去调整flex items在主轴(main axis)、副轴(cross axis)的位置。好比最多见的考试题,水平垂直居中某个元素,demo-flexbox-alignment ;再好比justify-content:space-around
做用于导航条的样式,demo-flexbox-alignment-justify-content。
通常来讲,标签出现顺序由源代码中出现顺序决定,Flexbox为Flex items提供了order
属性,提供从css角度调整Flex items在页面中出现的顺序的能力。
若是为Flex item设置主轴方向(main axis)的margin
值为auto
,好比主轴是横向的,设置margin-left:auto
,这个Flex item会占据往左这个方向的剩余空间:demo-flex-flex-item-margin:auto。
Grid布局,和Flexbox设计为在一个方向布局不一样,它帮助咱们更加容易地从两个方向上布局元素。我更加推荐Grid布局应用于整个页面,由于它很是清爽、优雅。它一样存在浏览器兼容问题,且比Flexbox更要重,在旧浏览器中的实践会在以后说明。接下来几个场景是创建在浏览器支持Grid的前提下。
为何说它优雅呢?看几个demo就知道了。
demo-grid-layout、demo-grid-layout-grid-template-areas:两个demo都实现了最基本的一个页面状况,一个头部、一个侧边栏、一个主要内容区域、一个底部,前者是Grid布局最常规的使用,后者使用了grid-template-areas
属性;
另外在Grid布局以前,有一些库在作模拟Grid System的工做,将一个页面分红6列或者12列,标签按列去占据页面。Grid布局方法彻底有这样一个能力,使用12列布局的Grid重写前面两个demo实现的效果:demo-grid "framework";
若是能使用Grid布局整个页面,我是强烈推荐的,它的思惟切入点再也不是一维,而是二维,这是一场变革。
Floats布局方法既能够针对整个页面,也能够针对局部部件,虽然设计之初并非为了布局整个页面。我是把Floats做为没法使用Grid、Flexbox时候的第一选择。像前面提到的作Grid System的css库,它其实也是将其中的每个item设置为了float:left
,而后计算占据宽度的百分比以模拟Grid System。
另外,"floated item"(设置float:left
或float:right
)会从Normal flow中移除。来看看具体应用的demo吧。
“文字环绕图片”是Floats设计的初衷:demo-float-avatar image
demo-float-a fun drop-cap effect
"Floated item"的高度是不包括在容器标签内,若是高度超出容器标签,会出现显示上的错误,这是Floats应用于页面布局最多见的一个问题:demo-float-floated items overflow the wrapper
解决方案有三种:
::after
清除浮动,或者在容器标签内加一个空的div
元素清除浮动也能够解决问题;overflow
属性创建一个BFC,可是当心overflow:hidden
、overflow:auto
可能增长了你不须要的显示效果;display:flow-root
创建一个BFC,并且不会像overflow
增长不须要的显示效果,可是得考虑浏览器支不支持这个属性;在许多年之前,web开发者使用table
标签作整个页面的布局,将页面内容放入table
的行和列中,这种方法的问题在于不灵活,并且语义错误(对于屏幕阅读器的用户很不友好)。之因此放入table
标签能布局,是由于存在描述table layout的一些列css属性,它们是和table
这些标签是绑定的。而直接使用这些css属性,用于不是table
这些元素布局,这种方法被称为是 "using CSS tables" :demo-using css tables;
"using css tables" 被称做是一种遗留方法(legacy method),用于整个页面布局,适用于不支持Flexbox和Grid的浏览器,可是我这里的最佳替补仍是Floats。
Positioning的定位和前面四种不太同样,它通常不用于建立整个页面布局,而是管理和微调标签,作一个局部位置的调整。要注意若是已经设置如下几个position
属性值的标签,层级是高于Normal flow,层级可经过z-index
属性调整。
position:relative
相对定位,作位置调整demo-positioning-relative-left/right:这个例子不是很深动形象,可是demo糙理不糙,确实是经过设置left
、top
等属性值去移动位置。
posision:absolute
绝对定位,作任何可弹出、可拖拽UI部件MDN上放了这样一个使用场景说明:
popup information boxes and control menus; rollover panels; UI features that can be dragged and dropped anywhere on the page; and so on...
postion:fixed
固定定位demo-position-fixed:固定表头,表头位置始终定于页面顶部,不随滚动条滚动而滚动。
固然可用于任何须要固定于页面某个位置的UI部件。
position:sticky
粘性定位这里有个很经典的例子: demo-sticky-a scrolling index page where different headings stick to the top of the page as they reach it ;可是在使用时得考虑浏览器兼容问题,兼容性目前堪忧。
Multicol是Multi-columns layout的简称,它提供了一种在列中布置内容的方法,相似于文本在报纸中的流动方式,使得阅读更加友好,不用上下滚动。Multicol的定位是这一种特殊的内容展现布局。
demo-multi-column layout:经过在container
块级元素上设置column-count
或者column-width
属性开启Multicol:
最初吸引我作这个话题的缘由,是目前公司项目得支持IE十、IE11,现状是项目中的布局方法没有Grid、鲜有Flexbox,就比较心痒痒,想搞搞明白到底能不能在支持IE十、IE11的状况使用这两种潮流的布局方法。因此在旧浏览器中的实践重点考虑的是IE十、IE11两位。
浏览器对Flexbox的支持仍是挺不错的,IE10支持2012版语法,IE11支持的语法和现代浏览器一毛同样。在IE10和IE11中使用Flexbox存在一些已知的问题,在caniuse-flexbox有说明,同时还有一个Flexbugs是一个问题的列表以及解决措施。
因此这里的最佳实践分两步:
另外贴两篇Postcss扫盲文章:Some things you may think about PostCSS... and you might be wrong、It's Time for Everyone to Learn About PostCSSWhat It Really Is; What It Really Does
浏览器对Grid的支持较Flexbox要差不少,IE十、IE11支持的是旧版本的规范,是带有-ms-
前缀,但即便使用autoprefixer补上了前缀,相同属性名相同属性值在页面中的表现也可能不一致。这样我是不推荐Flexbox实践中的方法,而是使用Feature Queries。
Feature Queries是使用css的@supports
,@supports
用于检测浏览器是否支持参数中的属性属性值,若是支持则渲染花括号中的css代码,相似于:
@supports (display: grid) {
// code that will only run if CSS Grid is supported by the browser
}
复制代码
这里有个细节点,IE十、IE11是不支持@supports
规则,因此压根不会进入这个条件判断,花括号中的css代码是不会渲染的,这与咱们考虑的逻辑:支持@supports
规则、不支持display:grid
是不一样的,可是最后的结果是同样的。
以一个例子讲述一下整个流程:demo-creating fallbacks in CSS
.wrapper{
overflow:auto;
}
.item {
float:left;
width:33.3%;
}
复制代码
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
复制代码
由于旧浏览器不支持Grid布局,Grid相关属性旧浏览器都没法解释。在支持的浏览器中使得item由floated item转为grid item,这样的覆盖行为由css规定,更多覆盖状况见Fallback method。另外一部分是直接放入对旧浏览器是有影响的,要作Feature queries:
@supports (display: grid) {
.item {
width: auto;
}
}
复制代码
覆盖原有的width:33.3%
。
没错,这里的实践得写两套样式。因此有人提出问题,写一套支持全部浏览器的不就得了,干吗非得用Grid?这是个很实际的问题,毕竟写两套,再加测试调试,会增长必定工做量。有几个场景建议使用Grid:
尤为是支持IE十、IE11的项目,测试是很重要的一个环节,最佳的测试仍是在各个浏览器中打开。但这里存在获取浏览器的问题,例如win10系统上仅有IE11,而不能使用IE10等。有些公司有本身的服务器,有各类浏览器可供测试;若是没有的话,能够考虑下载虚拟机:download the Virtual Machines offered by Microsoft ,或者使用像 BrowserStack 访问远程的虚拟机。
从开发者角度,整个工做流程应该是这样子:
CSS Grid Layout and Progressive Enhancement
Using CSS Grid: Supporting Browsers Without Grid
Some things you may think about PostCSS... and you might be wrong
It's Time for Everyone to Learn About PostCSSWhat It Really Is; What It Really Does