当前位置: 首页 > news >正文

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

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

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

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

Normal flow:css布局的起点

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

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

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

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

  • 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布局的起点。

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

css布局方法有很多,如Flexbox、Grid、Float等等等等,在使用之前得把握两个中心思想

  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-flex:section标签是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-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布局方法既可以针对整个页面,也可以针对局部部件,虽然设计之初并不是为了布局整个页面。我是把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考虑支持旧浏览的最佳实践

最初吸引我做这个话题的原因,是目前公司项目得支持IE10、IE11,现状是项目中的布局方法没有Grid、鲜有Flexbox,就比较心痒痒,想搞搞明白到底能不能在支持IE10、IE11的情况使用这两种潮流的布局方法。所以在旧浏览器中的实践重点考虑的是IE10、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 wrong、It's Time for Everyone to Learn About PostCSSWhat It Really Is; What It Really Does

Grid: Feature Queries

浏览器对Grid的支持较Flexbox要差很多,IE10、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 
 }
复制代码

这里有个细节点,IE10、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. 项目得支持IE10、IE11等旧浏览器,但是开发者想尝鲜Grid布局,Feature Queries提供了这样的能力;
  2. 项目周期会很长,可能现在不支持Grid布局的浏览器,以后就支持了;
  3. 要实现的效果不使用Grid布局很难实现,且对在旧浏览器中访问效果要求不高,能看就行;

测试

尤其是支持IE10、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考虑旧浏览器的实践(支持IE10、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

转载于:https://juejin.im/post/5ca2d60b6fb9a05e6d61aa61

相关文章:

  • PyCharm 2019.1.1 RC 发布
  • 对话Ruby创始人松本行弘、阿里高级技术专家朴灵!
  • 删除Oracle用户及表空间
  • 设计模式:对问题行之有效的解决方式。其实它是一种思想。
  • Linux实战教学笔记02:计算机系统硬件核心知识
  • pytorch Debug —交互式调试工具Pdb (ipdb是增强版的pdb)-1-使用说明
  • 程序结构
  • 设置selinux开机自动关闭
  • Python通用编程 - 第四章:字符编码
  • 微信小程序商店域名由wxapp.dreawer.com永久更换为:store.dreawer.com
  • Java数据解析之JSON
  • 浏览器的兼容性
  • Java基础3:深入理解String及包装类
  • Java基础7:关于Java类和包的那些事
  • 关于从业以来第一个项目的总结
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • Asm.js的简单介绍
  • classpath对获取配置文件的影响
  • create-react-app项目添加less配置
  • GitUp, 你不可错过的秀外慧中的git工具
  • iOS小技巧之UIImagePickerController实现头像选择
  • js ES6 求数组的交集,并集,还有差集
  • React-redux的原理以及使用
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • SegmentFault 2015 Top Rank
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • vue数据传递--我有特殊的实现技巧
  • zookeeper系列(七)实战分布式命名服务
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 编写符合Python风格的对象
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 前端工程化(Gulp、Webpack)-webpack
  • 算法-插入排序
  • 新手搭建网站的主要流程
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • 白色的风信子
  • puppet连载22:define用法
  • (42)STM32——LCD显示屏实验笔记
  • (紀錄)[ASP.NET MVC][jQuery]-2 純手工打造屬於自己的 jQuery GridView (含完整程式碼下載)...
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (深度全面解析)ChatGPT的重大更新给创业者带来了哪些红利机会
  • (四)图像的%2线性拉伸
  • (算法)前K大的和
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (转)LINQ之路
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • .NET 设计模式初探
  • .Net8 Blazor 尝鲜
  • .net安装_还在用第三方安装.NET?Win10自带.NET3.5安装
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • .NET开源的一个小而快并且功能强大的 Windows 动态桌面软件 - DreamScene2
  • .NET开源项目介绍及资源推荐:数据持久层 (微软MVP写作)
  • .pub是什么文件_Rust 模块和文件 - 「译」
  • @column注解_MyBatis注解开发 -MyBatis(15)