解决Flexbox跨浏览器兼容Bug

早在2013年9月,我在测试我的Solved by Flexbox项目时,在IE10和IE11中发现了一个Bug,就是Sticky footer实际上不会粘贴在页面的底部。我花了很多时间来解决这个问题,但始终没有成功。

起初,我真的很生气。在Flexbox出现之前,如果在不知道页脚的确切尺寸情况之下,要使用纯CSS来实现Sticky Footer的效果是不太可能。Flexbox改变了这一切,可以使用CSS解决这个问题。

失望之后,我最终得出一个结论,这不是什么大不了的事情。我的意思是,从渐进增强的角度来看,我的解决方案还是相当不错的。虽然它在IE并不完美, 但不至于坏得一塌糊涂,内容依然可以访问,它只会在较小的内容页面上展示,而在较长的页面上,它看起来和Chrome、Firefox、Opera和 Safari浏览器得到的展示很像。

几周前,我在Github看到一个新的请求,在IE下使用@media规则来解决Sticky Footer的问题。这让我再次思考起这个问题,我决定找到一个特定的解决方案,而不再使用任何浏览器特殊的Hack技巧。

事实证明了是有相应的解决方案可以实现的,也再次证明了我自己还是不够努力。

在这篇文章中,我将解释这个解决方案,并且讨论一些我在浏览器中发现的的Bug。并且对相应的Bug提出一些修复建议,让Flexbox能更好的实现跨浏览器的兼容。

有哪些Bugs呢?

Flexbox规范还没有最终确定,所以自然会有一些最新的草案和浏览器实现滞后现象。本文不打算在背后对任何组织进行指指点点,他们的目的是帮助我们做前端开发的人员管理好浏览器的不一致。

下面列出了我在制作Sticky Footer案例时在各个浏览器是碰到的问题清单:

  • 在IE10~11浏览器中,flex项如果设置了最小高度(min-height)将会忽略它们的父容器的高度(height);
  • Chrome、Opera和Safari浏览器中flex项目没有最小内容的概念;
  • IE10~11在flex标准中不允许出现不带单位值的flex-basis

min-height的问题

在IE10和IE11中,min-height属性可以设置flex容器列方向的大小,但是,如果容器的flex项目在不知道他们父容器的大小时,也就是没有给他们父容器设置height时,设置min-height将会失效。

这个问题就存在我的Sticky Footer案例中,因为Sticky Footer布局中就需要给内容设置一个min-height100%(或100vh)的声明,确保内容区域至少和浏览器窗口的高度是一样高。

既然flex项目无法识别min-height,我们就需要找到另一种能让其工作的方式。

flex项目内容最小尺寸

当一个大的flex项目放到flex容器中时,其他的flex项目就会相应的变小(这就是flex布局的算法)。flex-shrink会根据内容来进行计算。但许多浏览器刚好与其相反,他们不应该允许flex项目无限的缩小。他们小到最低宽度或高度的声明时不应该再继续缩小,如果没有声明最低宽度或高度,应该缩小到其内容的尺寸为止,不再继续缩小。

Flexbox规范是这样描述的:

默认情况下,flex项目收缩后不会低于其最小内容尺寸(最长单词的长度或固定大小的元素)。为了改变这一状况,给flex项目设置min-heightmin-wdith属性。

Chrome,Opera和Safari目前已经忽略了这个规范,让flex项目可以缩减为零。作为一个结果,你的内容就会重叠在一起。

不带单位的flex-basis

之前发布的IE10版本的flexbox规范时表示,flexbox项目在使用flex要需要设置单位。

如果更想的大小是“0”,它必须指定一个单位(如0px)以避免歧义;不带单位的”0“要么被视为灵活性,要么被视为一个语法上的错误。

这不是真正的规范,但IE10~11仍然把它当作是真实的。如果您使用flex声明了一个1 0 0,那么这个规则在IE10~11中将被视为是一个错误,整个规则的灵活性将被浏览器忽略。

找到一个替代Sticky Footer的解决方案

我选择Sticky Footer布局做为本文的主要例子,那是因为遇到很多人都在想找到一个跨浏览器的解决方案。但是在我们正式进入介绍细节之前,先让确认一下我们都是在同一个页面上。

下面是我用来制作Sticky Footer布局的结构:

<body class="Site">
  <header class="Site-header">…</header>
  <main class="Site-content">…</main>
  <footer class="Site-footer">…</footer>
</body>

遵循规范的浏览器使用下面的代码可以实现Sticky Footer布局效果:

.Site {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
.Site-content {
  flex: 1;
}

现在正如我们提到的,这个CSS是可以正常工作,但是不是所有浏览器都完全遵循规范的,所以在一些浏览器中,他是存在问题的。

如果你是一位有经验的前端开发人员,你应该知道,任何解决跨浏览器的问题,不仅要让他今天能正常工作,还需要保证你的项目完成后续也能正常工作。

    解决方案取决于解决方案的任何行为。

到目前为止,基于前面所说的一切,我个人的要求是,找到解决Sticky Footer布局的替代方案,其必须满足:

    在所有浏览器下都能正常工作
    浏览器修复了这些不良的行为也要能继续工作
    不依赖浏览器任何特殊的Hack手段

使用height替代min-height

如果你做前端开发有一段时间的话,你应该记得IE6中永远都不支持min-height(或者min-width)属性。然而,在解决这个问题时,总是使用height:100%来替代min-height:100%。因为浏览器对其解析出来的效果是一致的。因此,在制作Sticky Footer布局时,建议像在IE6中的解决方案一样,设置一个height:100%。

知道这一点之后,我试过了我的找到的第一个解决方案,就是使用height:100 vh来替代min-height: 100vh。经过测试,他确实能在IE中正常工作,但它不能在Chrome中工作,所以我立即记录下来了。

事实证明,我们应该认真的了解规范,而不能一味的认味Chrome是正确的,IE就是错误的。

在CSS中,你通常都会使用min-height来替代height避免内容超过高度是溢出问题。当有太多的内容时,你显式的设置了height值,这也就意味着,内容要被剪切,重叠或出现滚动条。在很多情况之下,这些都是不好的表现形式。然而,当你在body元素上这样处理时(就比如Sticky footer布局),出现滚动条并没什么大不了的。其实这也正是你想要的。所以在body元素上显式定义height:100 vh和有太多内容时,其表现的结果应该是一样的。

那么问题来了:为什么在Chrome浏览器中不能正常工作呢?
最小尺寸的问题

前面我提到过,一些浏览器错误地将flex项目缩减到小于其默认内容的尺寸,导致内容重叠。这也就是为会要将min-height换成height,但我在Chrome浏览器中测试时,不能正常工作。

页头,页脚和内容元素都缩小到元素内容最小尺寸(但不是更少)时会发生些什么呢?如果这些元素(组合)有更多的内容在屏幕上,body元素应该与滚动条溢出是一样的。页头、页脚和内容元素都应该正常显示,一个在另一个之下,没有重叠在一起。

Chrome发生了什么,而不是允许页头,页脚和内容元素收缩小于默认内容的最小尺寸。其结果是body元素并没有溢出,而发生在页头,页脚和内容元素自身上。由于这些元素的overflow默认值是visible,他们的内容是会相互层叠的。页脚是固定在页面底部,而页面主内容是溢出和其层叠在一起。

幸运的是,有一种简单的方法可以解决这个问题。

Flexbox规范定认了一个flex-shrink属性,其默认值为1,表示的是其flex项目缩小不应小于其内容默认的最小尺寸。你也可以使用flex-shrink:0;取得flex-shrink:1相同的表现形为。如果元素的大小是根据其子元素的来决定,并没有设置width、height或flex-basis值,然后设置flex-shrink:0;可以取得同样的效果,来避免前面提到的错误。
避免没单位的flex-basis

不带单位的flex-basis的Bug是几个Bug中最为简单的一个,但它可以说也是最难跟踪的。

原来在解决Sticky Footer问题时,在content元素上声明了flex:1。因为flex:1是flex: 1 1 0px的简写,而且自从知道不需要任何缩放时,我决定使用flex: 1 0 0px。

这个一直都能正常工作,直到我在IE中测试为止。

IE中存在一个组合的漏洞和CSS的压缩:为了缩小CSS文件大小,常常将1 0 0px省略单位值1 0 0(没有带单位的flex-basis值)。因此IE10~11完全忽略了这个声明。

一旦发现了问题根源所在,那么解决办法就微不足道。设置一个明确的flex-basis值,或在使用flex简写值时,使用flex:0%。注意,使用0%比0px强。
将他们放在一起

下面将本文讨论的Bug和相应的解决方案,总结到一起:

    在IE10~11浏览器,min-height不适合于flex容器的子元素flex项目。如果可能的话,使用height来替代min-height。
    在Chrome,Opear和Safari浏览器不识别flex项目内容的最小尺寸。可以设置flex-shrink的值为0(而不是默认的1),以避免不必要的收缩。
    不使用无单位的flex-basis值,因为在IE10~11中,flex简写被忽略。常使用0%来替代0px。

记住所有的缺陷和解决方法,这是我最后想出的替代解决方案。它可能没有最初那样清爽,但它满足我们所有要求的一个解决方案:

    它可以在所有浏览器中工作
    规范的兼容性,错误是有,但可以继续工作
    不使用任何浏览器的特定hack
 

我在CSS中添加了注释,来解决那些解决方法:

/**
 * 1. Avoid the IE 10-11 `min-height` bug.
 * 2. Set `flex-shrink` to `0` to prevent Chrome, Opera, and Safari from
 *    letting these items shrink to smaller than their content's default
 *    minimum size.
 */
.Site {
  display: flex;
  flex-direction: column;
  height: 100vh; /* 1 */
}
.Site-header,
.Site-footer {
  flex-shrink: 0; /* 2 */
}
.Site-content {
  flex: 1 0 auto; /* 2 */
}

可以点击这个案例,查看使用Flexbox解决Sticky Footer的方案。
脚注:

    从技术上讲,如果不需要兼容IE7以及其以下版本,在不知道页头和页尾高度时,创建一个Sticky Footer布局可以使用display:table;。在实现跨浏览器,要使用浏览器的Hack,可以说不是一个实际解决方案。
    这里所说的”所有浏览器“,我指的是所有实现2012年3月或更新发布的Flexbox规范的浏览器。换句话说,支持flexbox的现代浏览器。
    使用flex-basis:0解决大多数问题,但不是全部问题。如果你想让flex项目收缩不小于默认内容大小,这个解决方案是行不通的。
    2014年3月更新的flexbox规范改变了flex:1含义,从1 0 0px变成1 0 0%。也就是说flex:1的简写相当于是flex: 1 0 0%。

时间: 2024-08-04 08:36:09

解决Flexbox跨浏览器兼容Bug的相关文章

Flexbox跨浏览器兼容Bug解决方法

在IE10和IE11中发现了一个Bug,就是Sticky footer实际上不会粘贴在页面的底部.我花了很多时间来解决这个问题,但始终没有成功. 起初,我真的很生气.在Flexbox出现之前,如果在不知道页脚的确切尺寸情况之下,要使用纯CSS来实现Sticky Footer的效果是不太可能.Flexbox改变了这一切,可以使用CSS解决这个问题. 失望之后,我最终得出一个结论,这不是什么大不了的事情.我的意思是,从渐进增强的角度来看,我的解决方案还是相当不错的.虽然它在IE并不完美,但不至于坏得

解决跨浏览器兼容的CSS编码准则

浏览器越来越多,也就意味着做web前端开发的就越困难.现在的浏览器的内核都同,对于css的兼容也会有一定的差别!以前讲的用css hack来也不是一件容易的事,用过多的css hack来兼容也会出现许多臃肿的代码:所以掌握一些跨浏览器兼容的css编码准则是非常有必要的. 第一:理解css盒子模型(学习div+css布局也是很重要的,学会的css的盒子模型学习div+css也就不难了) 透彻地理解 CSS 盒子模型是首要事情,CSS 盒子模型并不难,且基本支持所有浏览器,除了某些特定条件下的 IE

如何调试CSS的跨浏览器样式bug

首先要做的是挑选一个好的浏览器.我的选择是Chrome,因为它拥有强大的调试工具.当我在Chrome上完成调试后,我会接着在Safari或者Firefox上调试. 如果在这些"好的"浏览器上没有达到期望的效果,很有可能是代码本身违背了CSS规则.不要试图使用hack方法来解决在这些"好的"浏览器上出现的问题,而是应该找出问题的原因.通常我会检查以下可能的BUG出处: HTML代码解释 - 你是否忘记闭合一个标签? 你是否用一个inline元素包住一个block元素?

使用 PostCSS 跨浏览器兼容教程

这里我们将使用PostCSS创建一个跨浏览器兼容性的样式表.我们将要做的: 有前缀的自动添加前缀添加一系列的IE版本,回退到IE8.IE9和IE10为没有支持的属性添加will-change属性 设置项目 你需要做的第一件事情就是使用Gulp或Grunt设置您的项目.如果你没有一个完美的项目模板,我建议你使用Gulp,可以使用较少的代码来达到相同的目的. 你可以阅读前面有关于Gulp或Grunt创建PostCSS项目的教程:     PostCSS深入学习:Gulp设置    PostCSS深入

跨浏览器兼容测试有关的大量资源

跨浏览器是所有网页设计师都会碰到的常见问题,当完成一个页面后,经常会要测试IE,FF等多种常用浏览器软件.有时候客户也会要求兼容更多浏览器,当电脑里没有安装这类浏览器时就会显得很麻烦,所以推荐那些为跨浏览器测试范畴的网页设计师可以阅读下本文 我们生活在一个幸福又痛苦的时代,有太多的浏览器可以使用,对 Web 开发与设计者而言,你有义务保证你的设计兼容所有主流浏览器.然而跨浏览器测试是件相当复杂的事,涉及不同的浏览器,不同的版本,不同的平台.本文介绍了与跨浏览器兼容测试有关的大量资源. 在线测试资

编写跨浏览器兼容的 CSS代码的金科玉律

作为 Web 设计师,你的网站在各种浏览器中有完全一样的表现是很多人的目标,然而这是一个永远无法真正实现的目标,很多人认为,完美的跨浏览器兼容并不必要,这样说虽然没错,但在很多情形,一种近似的兼容还是很容易实现的,本文讲的是各种跨浏览器兼容的 CSS 编码准则和技巧. 理解 CSS 盒子模型 如果你想实现不需要很多奇巧淫技的跨浏览器兼容的 CSS 代码,透彻地理解 CSS 盒子模型是首要事情,CSS 盒子模型并不难,且基本支持所有浏览器,除了某些特定条件下的 IE 浏览器. CSS 盒子模型负责

跨浏览器兼容测试8大利器

中介交易 SEO诊断 淘宝客 云主机 技术大厅 仅仅是一年前,跨浏览器兼容测试还不是一件容易事,市面上的测试工具都有一些缺陷,要么太贵,要么功能有限,要么很难用.最近我们终于看到了一些新 的工具出现,其中的一些可谓十分出色.本文精选8种最新的跨浏览器测试工具,这7款简单的工具让你的工作变得十分容易,而且它们完全免费. #1 - Xenocode Browser Sandbox Xenocode Browser Sandbox 改变了基于 Windows 的浏览器兼容测试工具的游戏规则,只需点一下

IE统治地位受到挑战 跨浏览器测试知识

IE 独霸天下的那些日子,Web 设计师不时陷入 IE 同它竞争者的口水战,然而,当一些新的,注重 Web 标准的浏览器出现时,事情发生了改变,IE 的统治地位受到了挑战. Web 设计与开发师的一个重要工作环节是跨浏览器测试,谁让我们生活在这个既幸福又痛苦的时代,有那么多浏览器摆在我们面前,还有那个噩梦般总也摆脱不掉的 IE6.本文讲述了与跨浏览器测试有关的各种问题与知识,包括渲染,平台,设备以及 JavaScript 引擎. 梦幻五组合 IE 独霸天下的那些日子,Web 设计师不时陷入 IE

跨浏览器测试资源大全

我们生活在一个幸福又痛苦的时代,有太多的浏览器可以使用,对 Web 开发与设计者而言,你有义务保证你的设计兼容所有主流浏览器.然而跨浏览器测试是件相当复杂的事,涉及不同的浏览器,不同的版本,不同的平台.本文介绍了 与跨浏览器兼容测试有关的大量资源. 在线测试资源 Browsershots 是一个备受欢迎的免费在线跨浏览器测试工具,包含各种平台的各种浏览器,会为你的网站截图,因为太受欢迎,所以要排队. Netrenderer 针对不同版本的 IE 进行测试,甚至即将包含 IE9. Browsrca