flex 双飞翼实现

双飞翼又叫做圣杯布局。简单的说,双飞翼是中国叫法,圣杯是老外叫的。这是由: Matthew Levine 提出的。简而言之有几点注意事项:

双飞翼又叫做圣杯布局。简单的说,双飞翼是中国叫法,圣杯是老外叫的。这是由: Matthew Levine 提出的。简而言之有几点注意事项:

  • 中间一栏最先渲染
  • 允许任意一栏放最上面
  • 只需一个额外 div 标签
  • 少用 HACK

实际上,强制要求就是前 3 个。他给的实现方式已经有了,我就简单的讲解一下他的实现吧。

原始双飞翼实现

完整demo,可以参考: 双飞翼布局

他的基本 HTML 为:

<div id="header">#header</div><div id="container"> <div id="center" class="column">#center</div> <div id="left" class="column">#left</div> <div id="right" class="column">#right</div></div><div id="footer">#footer</div>

没啥特殊的。这里就满足了任意一栏放上面的要求。因为 container 里面包括了圣杯布局的基本实现。使用 div 来包裹他,防止影响到其他元素。 主要还是 CSS (因为这里根本就没用 JS) header 和 footer 随便大家怎么放了,就是用到了 clear:both 清楚浮动。我们来观摩 container 里面的内容。

#container { padding-left: 200px; padding-right: 150px; } #container .column { height: 200px; position: relative; float: left; } #center { background-color: #000; width: 100%; } #left { background-color: red; width: 200px; right: 200px; margin-left: -100%; } #right { background-color: blue; width: 150px; margin-right: -150px; } // IE6 的 HACK 可以不用管 * html #left { // 定位 右边 container 的盒模型位置 left: 150px; }

最最重要的是前面两个。

#container { padding-left: 200px; // 定义 #left 的宽度 padding-right: 150px; // 定义 #right 的宽度 } #container .column { height: 200px; position: relative; // 设置相对布局,便于调整位置 float: left; // 让包裹元素脱离文档流 }

ok, 也就是说,#container 里面的属性,应该是至关整个页面布局的属性。这里,可以根据单一职责原则,再进行优化,将清除浮动这个 trick 让他本身自己实现。即:

#container::after{ display:block; content:''; clear:both; }

后面,我就挑 left 来进行简单说明(这篇想说的是 flexbox)。

#left { background-color: red; width: 200px; right: 200px; margin-left: -100%; }

主要属性就是 margin-left:-100%; ,用来将自己吃掉。那么此时,看起来他的宽度就为0,这就意味着,他可以上移了。对应于 right 就是:

#right { background-color: blue; width: 150px; margin-right: -150px; }

但,这有一个问题,right 怎么会浮动到最右边呢?感觉他应该是紧挨着 left。我们现在讲 margin-right 给忽略,会得到:

flex 双飞翼实现

关键的秘密在于,使用 margin-left 是不会当前层的文档流,更直观的就是,他们是在一个 Layer 上。

flex 双飞翼实现

right 跟着上移时,会根据上面那一行进行布局。so,他就会到右边去了。补充一下: margin 为负值的 problem

  • 没有设置 width: 使用 margin 负值,会向指定方向拖动
  • 设置 width: 会让元素内部塌陷,原来的样子不变。也就是说,其他元素会覆盖到它。

基本内容就是这些,MDZZ,一个双飞翼能扯出这么多。。。怪不得很多公司都喜欢问。。。主要的考点就是,margin 负值,position,left,清除浮动。 不过,我们这里,不扯这些,我们就用 flexbox。纯原生,快速实现。

flexbox 实现

这里,再说一下要求吧:

  • 中间一列自适应
  • 左右永远固定

对比与 flex 实现方式来说,这简直 so easy。我直接上代码吧:

// HTML<div id="header">#header</div><div id="container"> <div id="left" class="column">#left</div> <div id="center" class="column">#center</div> <div id="right" class="column">#right</div></div><div id="footer">#footer</div>// CSSbody { min-width: 550px; } #container{ display: flex; justify-content: center; align-items: flex-start; } .column{ height: 200px; color:white; } #center{ flex-grow: 1; background-color: black; } #left{ flex-basis: 200px; background-color: red; } #right{ flex-basis: 200px; background-color: blue; }

里面主要用到的就是 justify-content 和 align-items 来进行布局设置。 具体可以参考: holy grail 那两者有没有什么差异呢? 查看了 timeLine 发现, flexbox 渲染的层数也是一层:

flex 双飞翼实现

ok… 这当然说明不了什么,我们具体来看一下渲染完成时间就 ok:

  • flexbox: ~80ms
  • 原始 css: ~120ms

ok, 这下你知道该用哪一个了吧。

当然 flex 实际上就为了各种各样比较 HACK 的布局方式实现的。比如,侧边栏布局,多列布局等等。

flex 双飞翼实现

侧边栏布局,我就不多说了,关键是掌握 flexbox 的基本属性。直接看 源码 就 ok。 当然,flexbox 最适合做的就是多列布局,而且你多列的顺序可以随意切换,只要简单修改 order 就 ok。

flexbox 兼容处理

当然,说了这么多,兼容性肯定是个大问题,因为从第一版的 box 到现在 W3C 标准的 flex。中间经历了很多让人费解的阶段,那使用 flex 的时候,非要让你手动加上每一个时代的 flexbox,这估计就疯了。所以,编译 flex 的插件就出来了。我经常使用的就是 flexboxfixer 。简单的说,他就是将以前的 flexbox 的tip 给加上。它源码里也很清楚的写明了 flexbox 怎样做映射。

var mappings = { 'display': { valueMap: { 'box': 'flex', 'flexbox': 'flex', 'inline-box': 'inline-flex', 'inline-flexbox': 'inline-flex' }}, 'box-align': { newName: 'align-items', valueMap: { 'start': 'flex-start', 'end': 'flex-end' }}, 'flex-direction': { valueMap: { 'lr': 'row', 'rl': 'row-reverse', 'tb': 'column', 'bt': 'column-reverse' }}, 'box-pack': { newName: 'justify-content', valueMap: { 'start': 'flex-start', 'end': 'flex-end', 'justify': 'space-between' } }, 'box-ordinal-group': { newName: 'order', valueMap: {}}, 'box-flex': { newName: 'flex', valueMap: {}}};

这里就不过多赘述了。用的话也很简单,直接 postcss([flexboxfixer]) 即可。放一个我常用的 gulp 配置:

gulp.task('css', () => { var processors = [ //这里就是中间件 autoprefix({ browsers: ['last 3 Safari versions', "last 2 Explorer versions", 'last 2 Explorer versions', "iOS 5"], cascade: true, remove: true }), flexpost ]; return gulp.src(["xx/*.css"]) // 引入CSS .pipe(postcss(processors)) // 处理相关 css  .pipe(gulp.dest('dev/styles'));});
未登录用户
全部评论0
到底啦