当遇到css布局,你在考虑什么?

​ CSS布局在前端开发中像呼吸同样——再日常不过的事。好比同事A在尝到了Flexbox布局的甜头以后,任何布局都会以display:flex打头阵,同事B由于项目得支持IE10,像避开毒蛇同样的避开Flexbox布局方法。你会发现我可能有点嗤笑这样的行为,我曾经也是这样的一员,我想为这个问题——当遇到css布局,你在考虑什么? 整理一个完整的解决方案。javascript

​ 你在考虑什么:从什么样的HTML结构出发可以帮助到css布局?你的布局方法武器库都有什么,在具体场景下,选择什么合适的布局方法?须要作支持旧浏览器吗?Flexbox、Grid这些布局的方法弄潮儿在旧浏览器中的最佳实践是?等等等等。css

​ 本文将介绍个人"答案",欢迎胖友们补充、更正。html

Normal flow:css布局的起点

​ Normal flow(不知什么中文翻译妥帖,仍是扔了英文...)指的是若是没有改变css布局代码,网页中标签的默认表现方式。好比demo-normal-flow:块级标签p挨个从上往下,而内联标签span表现得像段落中的文本。前端

​ 当咱们建立、自定义一个布局,实际上是调整标签在Normal flow中的位置,或是直接从Normal flow移除,咱们最最原始的材料就是Normal flow。若是使用语义化标签(semantic markup),从一个结构良好的HTML文档开始是颇有帮助的:java

  1. 语义化标签确保**内容可读,**即便是很是受限制的浏览器、像屏幕阅读器这样的设备也如此;
  2. 以此为起点去布局文档,是合做友好的,而不是破坏性的、改动很大的,由于大多数标签仍是在Normal flow中;

HTML5新加了些帮助结构化的标签,html-document-structured 这篇文章能够参考,这里作一个overview:git

  • headerbodymain标签的直接子标签,位置在页面头部,内容可能为logo、标语、搜索提示、导航栏;
  • nav:导航栏包在nav标签内,可能出如今头部、侧边栏、底部等等,这里有个demo-mdn-nav,神奇的地方在于设置nav标签的display:inline-block,是做用在li标签上的;
  • mainbody标签的直接子标签,主内容区域;
  • aside:侧边栏;
  • article:通常出如今main标签内,article标签内能够有sectionfooter等标签,是比较独立的内容,好比像博客网站主页的一个文章简介;
  • sectionsectiondiv很相似,若是使用div标签是为了对内容作样式控制,或者为了便于javascript获取作其余操做,那么使用div就是你的答案,其余状况就用section
  • address:提供联系信息,放在article标签内提供文章做者信息,放在mainbodyfooter内提供网站信息;
  • footer:通常在HTML结构底部,补充网站信息,若是放在article内补充文章信息;

Normal flow是CSS布局的起点,更好的选择是语义化标签(semantic markup)做为CSS布局的起点。github

在具体场景下选择合适的布局方法

css布局方法有不少,如Flexbox、Grid、Float等等等等,在使用以前得把握两个中心思想web

  1. 每种布局方法有它的使用场景、使用上下文,在具体场景中选择对应合适的布局方法才是王道;
  2. 一个页面每每会应用多种布局方法,而不是一种布局方法解决全部问题,布局方法间是合做的关系;

接下来主要以讲demo的形式介绍各个布局方法的使用场景,对于布局方法自身如何使用不会过多说明。浏览器

Flexbox

Flexbox是Flexible Box Layout的简称,Flexbox既能够用于整个页面的布局,也能够用于局部部件的布局。Flexbox存在些浏览器兼容性的问题,在旧浏览器中的实践会在以后说明。接下来几个场景是创建在浏览器支持Flexbox的前提下。服务器

Flexing sizing of flex items

Flexbox全称Flexible Box Layout中的Flexible(灵活性),是它的立命之本。Flexbox的第一个使用场景也呼之欲出——Flexing sizing of flex items,也就是盒子尺寸的高度灵活性:

  1. demo-flexbox-flexsection标签是Flex容器,article标签是Flex item,其中前面两个article标签flex:1 200px,最后一个article标签flex:2 200px。具体表现为,若是不能提供3个Flex item都是200px宽度的空间,则它们仨宽度一致,若是能提供,剩余空间按照1:1:2分配;

  1. demo-flexbox-flex-fixedWidthWithFlex:这是实际使用中一个很常见的作法,这里将footer标签高度固定,section标签由于flex:1而占据余下全部空间。在水平方向,也能够是侧边栏宽度固定,主要内容占据余下全部空间;

水平、垂直位置调整

Flexbox提供像align-itemsjustify-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

Grid布局,和Flexbox设计为在一个方向布局不一样,它帮助咱们更加容易地从两个方向上布局元素。我更加推荐Grid布局应用于整个页面,由于它很是清爽、优雅。它一样存在浏览器兼容问题,且比Flexbox更要重,在旧浏览器中的实践会在以后说明。接下来几个场景是创建在浏览器支持Grid的前提下。

优雅的整个页面布局

为何说它优雅呢?看几个demo就知道了。

demo-grid-layoutdemo-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布局方法既能够针对整个页面,也能够针对局部部件,虽然设计之初并非为了布局整个页面。我是把Floats做为没法使用Grid、Flexbox时候的第一选择。像前面提到的作Grid System的css库,它其实也是将其中的每个item设置为了float:left,而后计算占据宽度的百分比以模拟Grid System。

另外,"floated item"(设置float:leftfloat:right)会从Normal flow中移除。来看看具体应用的demo吧。

文字环绕图片

“文字环绕图片”是Floats设计的初衷:demo-float-avatar image

文本首单词首字母特殊处理

demo-float-a fun drop-cap effect

页面布局:一个最多见Floats问题的解决

"Floated item"的高度是不包括在容器标签内,若是高度超出容器标签,会出现显示上的错误,这是Floats应用于页面布局最多见的一个问题:demo-float-floated items overflow the wrapper

解决方案有三种:

  1. demo-float-clearfix hack:在容器标签伪类::after清除浮动,或者在容器标签内加一个空的div元素清除浮动也能够解决问题;
  2. demo-float-overflow:使用overflow属性创建一个BFC,可是当心overflow:hiddenoverflow:auto可能增长了你不须要的显示效果;
  3. demo-float-display:flow-root:更现代的方法是使用display:flow-root创建一个BFC,并且不会像overflow增长不须要的显示效果,可是得考虑浏览器支不支持这个属性;

Table layout

在许多年之前,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

Positioning的定位和前面四种不太同样,它通常不用于建立整个页面布局,而是管理和微调标签,作一个局部位置的调整。要注意若是已经设置如下几个position属性值的标签,层级是高于Normal flow,层级可经过z-index属性调整。

position:relative 相对定位,作位置调整

demo-positioning-relative-left/right:这个例子不是很深动形象,可是demo糙理不糙,确实是经过设置lefttop等属性值去移动位置。

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

Multicol是Multi-columns layout的简称,它提供了一种在列中布置内容的方法,相似于文本在报纸中的流动方式,使得阅读更加友好,不用上下滚动。Multicol的定位是这一种特殊的内容展现布局。

报纸阅读模式

demo-multi-column layout:经过在container块级元素上设置column-count或者column-width属性开启Multicol:

Flexbox、Grid考虑支持旧浏览的最佳实践

最初吸引我作这个话题的缘由,是目前公司项目得支持IE十、IE11,现状是项目中的布局方法没有Grid、鲜有Flexbox,就比较心痒痒,想搞搞明白到底能不能在支持IE十、IE11的状况使用这两种潮流的布局方法。因此在旧浏览器中的实践重点考虑的是IE十、IE11两位。

Flexbox: Postcss插件Autoprefixer

浏览器对Flexbox的支持仍是挺不错的,IE10支持2012版语法,IE11支持的语法和现代浏览器一毛同样。在IE10和IE11中使用Flexbox存在一些已知的问题,在caniuse-flexbox有说明,同时还有一个Flexbugs是一个问题的列表以及解决措施。

因此这里的最佳实践分两步:

  1. 借助Postcss插件为咱们自动加上前缀,以支持IE10的2012版语法和现代语法;
  2. 使用过程避开在IE10和IE11中使用Flexbox的已知问题,若是仍是碰到了在旧浏览器和现代浏览器中表现不一致,去Flexbugs 找找有没有相同状况。若是再没有,再考虑替换方案,也能够给 Flexbugs 这个项目提issue;

另外贴两篇Postcss扫盲文章:Some things you may think about PostCSS... and you might be wrongIt's Time for Everyone to Learn About PostCSSWhat It Really Is; What It Really Does

Grid: Feature Queries

浏览器对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

  1. 首先是给旧浏览器作支持,准备一套Fallback method,保证在全部浏览器上都是工做的:
.wrapper{
  overflow:auto;
}

.item {
  float:left;
  width:33.3%;
}
复制代码
  1. 再给支持Grid的浏览器作覆盖,覆盖代码分两部分,一部分是直接放入对旧浏览没有影响的:
.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:

  1. 项目得支持IE十、IE11等旧浏览器,可是开发者想尝鲜Grid布局,Feature Queries提供了这样的能力;
  2. 项目周期会很长,可能如今不支持Grid布局的浏览器,之后就支持了;
  3. 要实现的效果不使用Grid布局很难实现,且对在旧浏览器中访问效果要求不高,能看就行;

测试

尤为是支持IE十、IE11的项目,测试是很重要的一个环节,最佳的测试仍是在各个浏览器中打开。但这里存在获取浏览器的问题,例如win10系统上仅有IE11,而不能使用IE10等。有些公司有本身的服务器,有各类浏览器可供测试;若是没有的话,能够考虑下载虚拟机:download the Virtual Machines offered by Microsoft ,或者使用像 BrowserStack 访问远程的虚拟机。

从开发者角度,整个工做流程应该是这样子:

  1. 初始开发计划制定
  2. 开发
  3. 测试、发现问题
  4. 修复问题,重复2~4步骤

总结

  1. 作css布局
    1. 布局的出发点是语义化标签
    2. 考虑在具体场景下使用什么布局方法最合适最简单
    3. 考虑要不要支持旧浏览器,要明确支持不意味着显示如出一辙,可存在体验优秀+体验通常两种模式
  2. Flexbox、Grid考虑旧浏览器的实践(支持IE十、IE11)
    1. Flexbox支持性比Grid好,使用Autoprefixer前缀,避开Flexbox bug、已知issues,放开了使用
    2. Grid布局要想使用,得用Feature Queries的方法,额外准备一套Fallback Methods
    3. Autoprefixer关闭对Grid属性添加前缀(默认行为)
  3. 测试
    1. 测试流程:初始开发计划制定 > 开发 > 测试、发现问题 > 修复问题,重复2~4步骤
    2. 借助虚拟机等

参考连接

MDN-CSS-layout

html-document-structured

Using Feature Queries in CSS

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

相关文章
相关标签/搜索