关于本书

关于本书

这本书适合谁

这本书的主要目标读者是正在由中级向高级进阶的 CSS 开发者。我们将跳过基础入门部分,直接探索现代 CSS 特性所针对的更高级的应用场景,并将它们融会贯通。不过在此之前,亲爱的读者朋友,我假设你已经具备了以下条件。

  • 假设你已经彻底掌握了 CSS 2.1,并有数年的实践经验。你不需要费劲地猜测定位的原理是什么。在增强网页设计效果时,你会使用生成性内容,而不是依赖冗余的标签和图片。你不会在代码中到处使用 !important 来打补丁,因为你已经深入理解了选择符优先级、继承和层叠机制。你知道盒模型中的各个部分都是什么,而且不会为外边距重叠头疼不已。你对各种长度单位了如指掌,而且清楚它们分别应该用在什么地方。

  • 你已经在书里或在网上了解过最流行的 CSS3 特性都有哪些,并且已经亲手尝试过——哪怕只是在自己的小项目里。即使还没有深入地研究过它们,你也已经知道如何生成圆角、加上投影或生成一个线性渐变图案。你玩过基本的 2D 变形(transform),并通过简单的过渡和动画来增强交互体验。

  • 你知道 SVG,以及它的用途,即使你还不太清楚自己应该怎么写。

  • 你可以读懂简单的、原生的 JavaScript 代码,比如创建元素,操作它们的属性,把它们添加进文档,等等。

  • 你听说过 CSS 预处理器,并且知道它们可以做什么,即使你决定一个也不用。

  • 高一数学应该难不倒你,比如平方根、勾股定理、三角函数、对数等。

尽管如此,为了让不完全符合上述条件的读者也可以愉快地阅读本书,在每篇攻略的开头,我都会准备一个“背景知识”提示框,简要地列出读懂当前攻略所必需的 CSS 知识以及前面相关的攻略(不过 CSS 2.1 的内容就不列出了,否则这个提示框会撑爆的)。这个提示框如下所示:

背景知识

box-shadow,基本的 CSS 渐变,“自适应的椭圆”

这样一来,哪怕你暂时还没有掌握这些基础知识,也可以在补好课之后再回来阅读。只要你具备了某篇攻略所要求的背景知识,就可以直接学习它了,不用在乎顺序。不过,还是建议你按照书中的顺序来阅读,因为我花了很多心思才把这些章节调整到最佳顺序。

请注意,上面列出的条件中写明的是“CSS 开发者”,并没有要求任何“设计能力”。一定要意识到这并不是一本关于设计的书。虽然我们会不可避免地涉及一定的设计原理,阐述一些用户体验的改进方式,但这本书的初衷和核心价值是帮助你用代码解决问题。CSS 会产生视觉上的输出结果,但它仍然是代码,就好比 SVG、WebGL/OpenGL 或 JavaScript 里的 Canvas API——它们都是代码,而不是设计。编程要求我们具备条理性的思维,想要写出合理的、灵活的 CSS 代码同样如此。如今,绝大多数 CSS 开发者都在使用 CSS 预处理器,他们会用到变量、数学计算、条件判断和循环,因此写 CSS 看起来已经像是在编程了。

这并不是说不鼓励设计师们读这本书。只要具备足够的 CSS 编写经验,任何人都可以从本书中受益;而且有很多才华横溢的设计师可以写出非常出色的 CSS 代码。总之,希望大家可以明白,本书的目标并不是教大家如何改进网站的视觉设计或可用性,即使它在这些方面会起到间接的帮助。

本书的格式和约定

这本书包含了 47 篇攻略,并根据主题的不同收入 7 章之中。这些攻略基本上是相互独立的,并且可以按照任意顺序阅读——只要你掌握了各篇攻略所需的背景知识。在每篇攻略中出现的演示案例并不是完整的网站,甚至连网站的片断都算不上。这些案例有意设计得尽量简短,以便降低理解负担。这本书的目的并不是要给出设计创意,而是给出创意的实现方案。

每篇攻略分为两个或多个部分。第一部分叫作“难题”,会引入一项常见的 CSS 挑战,需要我们去解决。这个部分有时会列出一些广泛流行但不够完美的解决方案(比如,需要添加大量的结构标记,需要死写数值,等等),而且往往会以类似“还有更好的方法吗”这样的问题作为结尾。

在引入问题之后,会给出一个或多个解决方案。本书的灵感来源于我在各种技术会议上的 CSS 演讲,因此我尝试在书中尽可能保持那种互动式的风格。每种解决方案都会配以多幅插图,把每个能产生视觉变化的步骤都用图片演示出来。由于所有插图不一定都能紧贴着对应的段落,我给它们编上 了号,这样就可以在正文中引用这些插图。你可以在图 P-1 看到一个插图的示例,而且这句话本身也是一个引用插图的示例。

图 P-1
这是一个插图的示例。图中是伟大的 Sir Adam Catlace

行内代码采用等宽字体来表示,颜色值也是如此。颜色值前面通常还会加一个小的预览色块(比如 {%} #f06)。代码块是这样的:

background: url("adamcatlace.jpg");

或这样的:

HTML

<figure>
    <img src="adamcatlace.jpg" />
    <figcaption>Sir Adam Catlace</figcaption>
</figure>

 这是一个警告。它的作用是警告你(要做好心理准备哦),为你指出一些常见的误区,或提醒你哪些地方容易出错。

你可能已经看出来了,只有当代码块的语言不是 CSS 时,语言类型才会在右上角标记出来。同样,为简洁起见,当示例代码只涉及单个元素、不涉及伪类或伪元素时,通常就不再把选择符和花括号写出来了。

本书中的所有 JavaScript 示例都是原生的 JavaScript,不需要依赖任何类库或框架。我们只会用到一个工具函数——$$()。它可以让我们更容易地获取和遍历所有匹配特定 CSS 选择符的 DOM 元素。这个函数的定义如下:

JS

function $$(selector, context) {
    context = context || document;
    var elements = context.querySelectorAll(selector);
    return Array.prototype.slice.call(elements);
}

小花絮 随便聊两句

书页底部的“小花絮”段落会扯得稍微远一些,比如介绍某个 CSS 特性背后历史性的或技术性的趣闻。它们对使用和理解正文内容没有直接作用,但读者或许会在这里发现他们感兴趣的东西。

每篇攻略至少会附上一个在线示例,URL 都在 play.csssecrets.io 域名下,而且都很简短易记。这些在线示例的链接是这样展示的:

试一试 

强烈建议你打开这些“试一试”示例,尤其是当你对文中所述的技巧不那么清楚时,或者当你在读到某个地方卡住了的时候。

该表扬就表扬:当文中提到的技巧是某人在社区中首次提出时,我们都会在类似本段这样的“致敬”环节向他发出谢意,同时也会给出相关链接。如果把这些链接都放在全书末尾的“参考资料”中,查起来会很不方便,因此我们将采用就近注解的方式。

在每篇攻略的末尾,你还会发现一份相关规范的清单,就像下面这样:

相关规范

  • CSS 背景与边框

  • 选择符

  • 可缩放矢量图形(SVG)

这份清单列出了当前攻略所述技术所对应的各项技术规范。不过,跟前面提到的“背景知识”提示框一样,这份清单也不再列出 CSS 2.1()的内容。这意味着,少数几篇只讨论 CSS 2.1 的攻略就根本没有“相关规范”这个段落。

关于未来 未来的解决方案

“关于未来”段落(通常安排在书页的最底部并配以深色背景)会介绍一些已经被列入规范草案的技术,但在编写本书时可能还没有浏览器实现。你在阅读本书的时候,别忘了再次查证这些特性是否已经可用,因为当本书出版后,浏览器可能已经实现了。考虑到这些特性的草案可能还很不稳定,浏览器兼容性查询网站可能还没有包含它们,因此这个段落同样也会提供一个测试性的示例页面,以便读者自行查验。这些测试页面的URL同样也很简短易记,会以下面这样“测一测”的形式标注出来。这些测试通常是这样设计的——绿色阴影表示当前浏览器已经支持某个特性,而红色阴影反之。在测试代码的注释中,也提供了明确的说明。

测一测 

浏览器支持与回退机制

本书的最大创举可能就是完全不提供浏览器兼容性表格。这是一个经过深思熟虑的决定,因为以当前浏览器的更新速度来看,这些信息必定在书还没有上架时就已经过时了。我认为,不准确的浏览器支持信息极具误导性,还不如干脆没有。

尽管如此,书中大多数攻略要么已经在浏览器中获得了良好的支持,要么可以做到平稳退化。万一某项技术在目前的支持程度下特别不理想,我会在相关段落处设置一个“不完全支持”的警告图标,比如本段旁边就有一个示例。它应该足以提醒你在正式使用这些技术之前不要忘了查证一下浏览器的支持情况,并且要特别注意做好回退机制。

有很多优秀的网站提供了及时有效的浏览器兼容性信息。推荐如下:

  • Can I Use...?()

  • WebPlatform.org()

  • Mozilla Developer Network()

  • 维基百科上的“浏览器排版引擎对比(CSS 兼容性)”词条())

有时候你可能会发现某个特性已经得到浏览器支持了,但不同浏览器的表现可能还有着细微的差异。比如说,它可能需要一个浏览器前缀 1,或者在语法上存在细微的差别。我们的示例代码中只会包含符合标准的、无前缀的语法。不过在绝大多数情况下,你都可以同时使用各种不同的语法,并且通过层叠机制来确保哪条声明最终生效。出于这个原因,你应该把标准语法排在最后。举例来说,要得到一条从黄色到红色的垂直渐变色,本书只会列出标准语法:

1关于浏览器前缀的更多信息,比如它们为什么会存在,以及如何在代码中把它们抽象出来,你可以在“冰与火之歌:浏览器前缀”一节中进一步了解。

background: linear-gradient(0deg, yellow, red);

但是如果你想要支持那些较早的浏览器,可能得把代码写成这样才能奏效:

background: -moz-linear-gradient(0deg, yellow, red);
background: -o-linear-gradient(0deg, yellow, red);
background: -webkit-linear-gradient(0deg, yellow, red);
background: linear-gradient(0deg, yellow, red);

这种差异的局面跟浏览器兼容性的局面一样,时刻处在变化之中。因此,当你在使用某项 CSS 特性之前,不要忘记这方面也是你要做好的功课,本书就不再为此花费过多篇幅了。

还有一些内容我们也不再赘述。提供回退机制通常是一种很好的做法,这样可以确保你的网站不会在低版本浏览器中挂掉,只是看起来没有那么炫而已。当这些后备机制很明显的时候,我们就不展开讨论了,因为你应该已经很清楚样式声明的层叠机制了。举例来说,当我们像上面那样指定一个渐变色作为背景的时候,应该在前面添加一行实色背景的声明。添加实色的一个好方法是取渐变色的平均色值(比如在这个例子中是{%} rgb(255, 128, 0))。

background: rgb(255, 128, 0);
background: -moz-linear-gradient(0deg, yellow, red);
background: -o-linear-gradient(0deg, yellow, red);
background: -webkit-linear-gradient(0deg, yellow, red);
background: linear-gradient(90deg, yellow, red);

不过,有些时候不太可能只通过样式的层叠就提供完善的回退样式。这时别忘了你还有一招,可以使用 Modernizr()这样的工具来给根元素(<html>)添加一些辅助类,比如 textshadowno-textshadow 等。这样你就可以针对支持或不支持某些特性的浏览器来分别编写样式了,就像这样:

h1 { color: gray; }

.textshadow h1 {
    color: transparent;
    text-shadow: 0 0 .3em gray;
}

如果你想尝试使用的某个 CSS 特性非常新,还可以试试用 @supports 规则来实现回退,可以将其视作浏览器“原生”的 Modernizr。比如说,上面的代码还可以这样写:

h1 { color: gray; }

@supports (text-shadow: 0 0 .3em gray) {
    h1 {
        color: transparent;
        text-shadow: 0 0 .3em gray;
    }
}

但在眼下,还必须慎用 @supports。在上面的例子中,我们想要的文本投影效果只会在那些支持 text-shadow 且同时支持 @supports 规则的浏览器中生效。这个范围明显比我们所期望的要窄。

最后,同样值得一提的是,即使你不打算使用 Modernizr,也可以自己写一小段 JavaScript 代码来实现相同的功能——做一些特性检测然后给根元素加一些辅助类。如果要检测某个样式属性是否被支持,核心思路就是在任一元素的 element.style 对象上检查该属性是否存在:

JS

var root = document.documentElement; // <html>

if ('textShadow' in root.style) {
    root.classList.add('textshadow');
}
else {
    root.classList.add('no-textshadow');
}

如果我们需要检测多个属性,也可以很容易地把上述代码改造成一个 函数:

JS

function testProperty(property) {
    var root = document.documentElement;

    if (property in root.style) {
        root.classList.add(property.toLowerCase());
        return true;
    }

    root.classList.add('no-' + property.toLowerCase());
    return false;
}

如果我们想要检测某个具体的属性值是否支持,那就需要把它赋给对应的属性,然后再检查浏览器是不是还保存着这个值。很显然,这个过程会改变元素的样式,因此我们需要一个隐藏元素:

JS

var dummy = document.createElement('p');
dummy.style.backgroundImage = 'linear-gradient(red,tan)';

if (dummy.style.backgroundImage) {
    root.classList.add('lineargradients');
}
else {
    root.classList.add('no-lineargradients');
}

这段代码同样也可以被很容易地改造成一个函数:

JS

function testValue(id, value, property) {
    var dummy = document.createElement('p');
    dummy.style[property] = value;

    if (dummy.style[property]) {
        root.classList.add(id);
        return true;
    }

    root.classList.add('no-' + id);
    return false;
}

如果要检测选择符和 @ 规则的支持情况,则会稍稍复杂一些。不过原理也很简单,在解析 CSS 代码时,浏览器总会丢弃它自己无法识别的部分,因此我们可以动态地应用样式并检查它是否生效,以此来判断浏览器是否可以识别某个特性。当然,我们也要清楚地认识到,浏览器可以解析某个 CSS 特性并不代表它已经实现(或正确实现)了这个特性

目录