英文:https://medium.com/actualize-network/modern-css-explained-for-dinosaurs-5226febe3525
编译:缪斯(https://segmentfault.com/u/muse)
CSS一直被web开发者认为是最简单也是最难的一门奇葩语言。它的入门确实非常简单——你只需为元素定义好样式属性和值,看起来似乎需要做的工作也就这样嘛!然而在一些大型工程中CSS的组织是一件复杂和凌乱的事情,你更改页面上任意一个元素的一行CSS样式都有可能影响到其他页面上的元素。
为了解决CSS错综复杂的继承问题,开发者建立了各种不同的最佳实践,问题是哪一个最佳实践是最好的目前尚无定论,而且有些实践相互之间是完全矛盾的。如果你第一次尝试学习CSS,这对于你来说是相当迷惑的。
这篇文章的目的是通过回顾CSS的历史背景,介绍下时至2018年的今天CSS发展过程中的一些设计模式和工具的演变。通过对这些背景的理解,你将会更轻松的理解每个设计思想并且学以致用。接下来让我们开始吧!
CSS基本样式使用
我们从一个最简单的网页index.html 开始,这个文件中包含一个独立的样式文件index.css:
lang="en">
charset="UTF-8">
Modern CSS
rel="stylesheet" href="index.css">
This is the header.
This is the main content.
...
This is the navigation section.
...
This is an aside section.
...
This is the footer.
上面的HTML标签中没用使用任何class或者id。
在没有任何CSS样式的情况下,我们的网站看起来是这个样子:
功能可用,但看起来不好看,我们可以继续在index.css加点CSS美化下排版:
/* BASIC TYPOGRAPHY */
/* from https://github.com/oxalorg/sakura */
html {
font-size: 62.5%;
font-family: serif;
}
body {
font-size: 1.8rem;
line-height: 1.618
;
max-width: 38em;
margin: auto;
color: #4a4a4a;
background-color: #f9f9f9;
padding: 13px;
}
@media (max-width: 684px) {
body {
font-size: 1.53rem;
}
}
@media (max-width: 382px) {
body {
font-size: 1.35rem;
}
}
h1, h2, h3, h4, h5, h6 {
line-height: 1.1;
font-family: Verdana, Geneva, sans-serif;
font-weight: 700;
overflow-wrap: break-word;
word-wrap: break
-word;
-ms-word-break: break-all;
word-break: break-word;
-ms-hyphens: auto;
-moz-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
h1 {
font-size: 2.35em;
}
h2 {
font-size: 2em;
}
h3 {
font-size: 1.75em;
}
h4 {
font-size: 1.5em;
}
h5 {
font-size: 1.25em;
}
h6 {
font-size:
1em;
}
这地方大部分都是关于排版(字体、行高等)样式的定义,也包含一些颜色和一个layout居中设置。为了让每个属性有个合理的值你需要学习点设计理论,但是这个地方我们用到的CSS本身并不复杂,你可以直接定义,结果如下所示:
有所变化了吧!正如CSS许诺的一样——用一种简单的方式给文档添加上样式,不需要编程或者复杂的业务逻辑。不幸的是,实际情况会复杂的很多,我们不单单使用的是CSS的排版和颜色这种简单的样式定义。
CSS的布局使用
在20世纪90年代,CSS还未广泛普及之前,对于页面的布局没有太多的选择。HTML最初是被设计为创建纯文本的一门语言,并不是包含侧边栏、列等布局的动态页面。早期的时候,页面布局通常使用的是HTML表格,在行和列中组织内容,这种方式虽然有效,但是把内容和表现杂糅在一块了,如果你想改变网页的布局就得需要修改大量的HTML代码。
CSS的出现推动了内容(写在HTML中)和表现(写在CSS中)的分离,人们开始把所有的布局代码从HTML中移除放入到CSS中,需要注意的是,和HTML一样CSS的设计也不是用来做网页内容布局的,所以早期的时候试图解决这种分离设计是很困难的。
我们来用个实际例子来看下如何实现布局,在我们定义CSS布局前先重置下padding和margin(会影响布局的计算),不同的区域我们定义不同的颜色(不要太在意好看不好看只要不同区域间足够醒目就可以)
/* RESET LAYOUT AND ADD COLORS */
body {
margin: 0;
padding: 0;
max-width: inherit;
background: #fff;
color: #4a4a4a;
}
header, footer {
font-size: large;
text-align: center;
padding: 0.3em 0;
background-color: #4a4a4a;
color: #f9f9f9;
}
nav {
background: #eee;
}
main {
background: #f9f9f9;
}
aside {
background: #eee;
}
现在页面应该看起来如下:
接下来我们用CSS来布局下页面内容,我们将按照时间顺序采用三种不同的方式,先从最经典的浮动布局开始吧。
基于浮动的布局
CSS浮动属性最初是为了将图片浮动在一列文本的左侧或者右侧(报纸上经常看到)。早在21世纪初,web开发者将这个属性的优势扩展到了任意的元素,这意味着你可以通过div的内容浮动创建出行和列的错觉。同样,浮动也不是基于这样的目的设计的,所以兼容性上会有很多问题。
2006年,A List Apart上发表了一篇热门文章In Search of the Holy Grail,文章概述了实现圣杯布局的详细方法——一个头部、三列内容和一个底部,你一定觉得一个简单的布局被称为圣杯布局很疯狂吧,但是在当时纯CSS的时代这的确很难实现。
下面是一个基于浮动布局的例子,用到了我们文章中提到的一些技术点:
/* FLOAT-BASED LAYOUT */
body {
padding-left: 200px;
padding-right: 190px;
min-width: 240px;
}
header, footer {
margin-left: -200px;
margin-right: -190px;
}
main, nav, aside {
position: relative;
float: left;
}
main {
padding: 0 20px;
width: 100%;
}
nav {
width: 180px;
padding: 0 10px;
right: 240px;
margin-left: -100%;
}
aside {
width: 130px;
padding: 0 10px;
margin-right: -100%;
}
footer {
clear: both;
}
* html nav {
left: 150px;
}
仔细看下CSS代码,这里面为了让它工作包含一些必须的hack方式(负边距、clear: both、硬编码的宽度计算等),稍后我们会对这些细节做详细的解释。最终的结果如下:
看起来不错了,但是通过三列的颜色可以看出来他们的高度不一样,页面的高度也没有填充满屏幕。这些问题是浮动布局导致的,所有的浮动只是将内容放在某一区块的左边或者右边,但是没法知道其他区块的高度。这个问题一直没有个好的解决方案,直到Flexbox布局的出现。
基于Flexbox的布局
flexbox CSS属性实在2009年第一次提出来的,但直到2015年才得到浏览器的广泛支持。Flexbox被设计为定义一个空间在行或者列上如何分布的,这让它比浮动更适合用来做布局,这意味在使用浮动布局十多年后,web开发者终于不再使用带有hack的浮动布局方式了。
下面是一个基于Flexbox布局的例子。注意为了让flexbox生效我们需要在三列的外面额外包装一个div:
lang="en">
charset="UTF-8">
Modern CSS
rel="stylesheet" href="index.css">
This is the header.
class="container">
This is the main content.
...
This is the navigation section.
...
This is an aside section.
...
这种方式和浮动布局相比更加紧凑了,虽然flexbox一些属性和值初看起来有些困惑,但是好歹不需要像浮动布局那样负边距的hack方案了,这是个巨大的进步。最终结果如下:
效果好多了!所有的列高度都相同,并且占据了整个页面的高度。从某种意义上来说这似乎是完美的了,但是这个方式也有些小问题,其中一个就是浏览器的兼容性——主流的现代浏览器都支持flexbox,但是一些旧的浏览器不兼容。幸运的是浏览器厂商也正在尽最大努力终止对旧版本浏览器的支持,为web开发者提供更一致的开发体验。另一个问题是我们需要
包裹HTML内容标签,如果能避免会更完美。理想状态下,任何CSS布局都不需要改变HTML标签的。
最大的缺点是CSS代码本身——flexbox虽然去掉了浮动的Hack,但是代码的可读性上变得更差了。你很难去理解flexbox的CSS,并且不知道页面上是如何去布局所有元素的。在写flexbox布局代码的时,有很多时候靠的是大量的猜测和尝试。
特别需要注意的是,flexbox被设计用来在单行或者单列中分割元素的——它不是设计用来给整个页面做布局的!尽管它能很好的实现(相对于浮动布局好很多)。另一种不同的规范是用来处理多行或者多列布局的,我们称之为CSS 网格。
CSS网格最早在2011年提出的(比flexbox提案晚不了多久),但是花了好长时间才在浏览器上普及起来。截止2018年初,大多数现代浏览器都已经支持CSS grid(这比一两年前有巨大的进步了)。
虽然结果看起来和基于flexbox的布局一样,但是CSS在很大程度上得到了改进,它清晰地表达出了期望的布局方式。行和列的大小和形状在body选择器中定义,每一项item直接通过他们所在行和列的位置定义。
一旦你习惯了grid语法,你会觉得它是一种非常理想的CSS布局方式。唯一缺点就是浏览器支持,幸运的是过去一年中浏览器的支持又得到了进一步的提高。作为专为CSS设计的第一款真正的布局工具很难描绘它的重要性,从某种意义上来说,由于现有的工具需要太多的hack和变通方式去实现,因此web设计者过去对于布局的创意上一直很保守,CSS网格的出现有可能会激发出一批从未有过的创意布局设计——想想还是挺激动人心的!
CSS预处理器允许你使用不同的语言来定义样式,最终会帮你转换为浏览器可以解释的CSS,这一点在当今浏览器对新特性支持缓慢的情况下很有价值。第一个主流的CSS预处理器是2006年发布的Sass,它提供了一个新的更简洁的语法(缩进代替大括号,没有分号等等),同时增加了一些CSS缺失的高级特性,像变量、工具方法还有计算。下面我们使用Sass变量实现下前面例子中带颜色的区域定义: