进入我的博客

这里有您在其他地方看不到的web前端方面的技术、知识及资源

这里有您在其他地方看不到的web前端方面的技术、知识及资源

张鑫旭-鑫空间-鑫生活

it's my whole life!

备份内容浏览

« 查看全部推荐内容

CSS vs. JavaScript: 相信 vs. 控制

lunasun

当阿姆斯特丹的GotoConf的组委会要求我发言时,我以为会让我讲机器学习或Progressive Web Apps。但是,组织者要求我讲CSS,这门在他们的“编程语言”中被低估的语言。说起来,我从最开始就一直是CSS的粉丝。但我觉得一个重磅技术云集的大会上的参与者并不会对CSS那么有兴趣。他们不会去关心CSS的细节。而且我知道CSS肯定困扰着他们。所以我写了一篇演讲来讨论为什么要使用CSS,以及我们为何没有发挥它的长处。

这是我演讲的笔记。

一场无聊的战争

某天我又看了一遍《美军队长:内战》,我又一次感到了厌烦,依然不太清楚它究竟想表达些什么。超级英雄被迫对他带来的损害负责,这样的想法并不新鲜。要求控制他们也不新鲜了。在这点上,《超人总动员》就做得很好。

让我感到更无聊的是所有这些优秀的超级英雄互相对抗的剧情。我们了解他们的能力,知道他们是挚友并在无数场景中挽救了彼此的性命,知道他们势均力敌。在这些故事里,没有暴力、没有真正的对抗、也没有愤怒。感觉就像Marvel特地创造了大量酷炫的角色,试图让观众选择支持的立场,借此出售更多的玩具,人为创造戏剧性。

当我们谈论使用CSS还是JavaScript进行布局时,我产生了同样的感觉。这两者都有自己的优点,都有自己的能力,有它们自己的粉丝群,他们时刻准备挖掘最详细的信息来呼吁使用其中的一个而不是另一个。但我觉得这挺无聊的。事实上,正是将这两者结合起来使用,才能使得网络得以向前发展。而壁垒分明的两个阵地则让我们止步不前。有的人将CSS看作过去的事情,认为在我们这个模块驱动的世界里,应该在脚本里完成一切。有的人则认为CSS和它的预处理器以及构建脚本足以做任何事情。还记得在DHTML的时代我们用JavaScript做所有事吗?还记得“CSS是唯一解决方案”的反击吗?还有我们(滥)用复选框来做复杂的互动以避免使用JavaScript的时候吗?

Giana Blantin说得好:

“CSS太简单了,它甚至不是一种代码” “CSS太难用了,我们需要用JS代替它!” 这两波人能不能和对方谈一谈?

对CSS的很多误解都是因为开发人员不了解它与编程的区别。我们瞎改一气,然后在把事情搞砸后,得出结论:它不够好,我们需要替换它。

常见的问题是过度使用标记。就像使用OpenGL创建简单渐变 我们不需要用牛刀来杀鸡。CSS里有一些袖里玄机是客户端脚本无法相比的。这些与语法或语言功能无关,关键是如何分配任务。

谁在犯错,谁应当宽容?

CSS,很像HTML,是容错的。这可能不太好理解。它意味着终端用户不会因为开发人员的错误而受到影响。当开发人员出错时,使用CSS构建的产品仍然会显示出来。他们看起来不完美,但仍然能工作。当CSS解析器遇到无法解读的属性时,就会跳过它。遇到不能处理的值或不支持的属性时 - 也会跳过它。这样我们可以保持向后兼容。

具有背景颜色和渐变的按钮会在较老的环境显示背景颜色。在由于性能问题不支持渐变的环境下也会显示背景颜色。而在更快、更高保真和支持渐变的环境下则显示渐变色。

你不需要了解环境,也不需要做出这个决定。相关操作系统、浏览器和代理可代你决定。

JavaScript不是容错的。这可能产生许多问题。在使用JavaScript时,你获得了更多控制权,同时也要承担更多责任。

客户端上的JavaScript可能因为很多原因中断。浏览器的不支持会使得连接变得不可靠。移动提供商还可能会把减少和打包下行脚本当作自己的工作。当JavaScript遇到无法解读的东西 - 它会中断,停止运行并且不显示任何东西,从而因为你的错误而惩罚使用你产品的用户,或是让引入的其他人员和脚本的错误代码影响你的终端用户。

换句话说:

  • CSS - 你应用样式,并期望它可行。

  • JavaScript - 你控制样式,能够并且应当验证它的可行性。

CSS意味着拥抱网页的“杂乱无章”,就像布拉德·弗罗斯特(Brad Frost)所说的那样。网页不是可以摆放像素的固定画布。很多事情会脱离你的掌控:

  • 你目标用户的浏览器

  • 其设备的分辨率,像素密度和颜色设置

  • 他们的连接可靠性和速度

  • 他们的连接限制 - 资源封锁是一个问题

  • 他们的字体大小和网页缩放

  • 你的的产品在他们机器上的资源可用性(CPU是不是已经烧起来了?)

  • 你的产品中的文本内容和图像大小的数量 - CMS任何人?

这可能会让人心生畏惧,通常我们想要控制产品运行的环境 - 为了让我们自己不陷入疯狂。这意味着我们把很多潜在用户拒之门外。

在这个未知的环境中,我们必须决定谁负责处理其性能问题:

  • CSS - 重点需要浏览器表现良好,使用GPU资源,不去理会功能。

  • JavaScript - 你的任务是测试支持程度,确保渲染、绘制和回流的高速,并保持动画同步。

CSS是非常棒的,而且浏览器厂商投入了大量精力来调整界面性能。

那么为什么我们低估了CSS的价值并且高估了JavaScript的优势呢?我想最应该责怪的是经典的 - Internet Explorer。

CSS和它的曲折历史

CSS的成长过于快速,以至于没有得到浏览器的支持而无法成为可靠的工具。

CSS一开始有很大的局限性,它意味着对可见的HTML和属性的替代。它会替代所有fonts,bgcolor,align,center, HR 和 friends。不一致的浏览器支持和没有调试选项的奇怪的错误对它毫无助益。我们知道出错了,但是我们束手无策。甚至没人可以询问,因为浏览器制造商不提供反馈机制。

当iPhone出来的时候,CSS已经开始崭露头角。 “HTML5是未来”的故事需要很多额外的功能。虽然有苹果的摇旗呐喊,但标准化需要太长时间,而且“仅限Webkit”。

这带来了CSS中的前缀,并再次导致对不同的渲染引擎写出分支代码。浏览器制造商开始革新,并以其他前缀功能显示出优势。对开发人员来说,这就意味着重复劳动,并且必须为每个浏览器选择一个支持计划。当然,还得有一个计划支持旧的、过时的浏览器。这些围绕前缀的新浏览器战争引起了很多争议和混乱。

最后,但同样重要的是,直到最近CSS中才出现布局模型。此前,我们想办法使用定位和浮动。定位,特别是以像素为单位的绝对定位在网页上是不明智的。一旦人们调整字体大小,内容就会重叠。浮动定位则需要清除浮动。

如果你不是“网页老手”,这些对你来说是不靠谱的,或者无法轻易理解。

我们要突破浏览器的限制让CSS生效

过去的解决方案是用JavaScript打补丁。我们可以读出条件,然后相应地创建HTML和应用样式。由于JavaScript是一种编程语言,我们可以完全控制正在发生的事情。我们有条件、循环、以及比较语句— 所有程序员在CSS中都无法使用的东西。然而,在某种程度上,这是对CSS概念的误解。匹配多个元素的选择器本质上是一个循环。我们甚至可以使用:nth-child()来定位集合中的元素。

总的说来,因为我们必须使用JavaScript来修补它,所以CSS一直在跳跃式发展。与此相比,特别令人失望的浏览器支持只是是一个小得多的问题。

  • 长青的浏览器都在不断地升级,我们甚至可以从浏览器制造商那里知道有哪些新玩意儿被创造了出来。

  • 浏览器工具告诉我们某些CSS的具体表现,我们甚至可以使用一些动画编辑器或者拾色器等可视化工具。 火狐(Firefox)浏览器开发工具里有贝塞尔曲线动画的可视化编辑器。

  • 不同浏览器的CSS支持程度有着明确的文档:caniuse.com是一个棒极了的网站。它不仅显示哪个浏览器和哪个环境支持什么。它还解析了应用中的bugs,提供了说明和错误报告的链接,甚至还有 一个 API将这一信息镶嵌到开发文档和工具中!“我可以在Visual Studio代码编辑器页脚中使用信息吗”通过在 Visual Studio Code 中使用“Can I use” 扩展,可以直接在编辑器中显示浏览器支持信息。这样你在写代码的时候就知道你将那部分用户拒之门外了。

  • 几乎所有浏览器都有支持渠道和错误跟踪。有些甚至允许你 在Twitter上提交bug。浏览器制造商的团队都在社交媒体上非常活跃,出现问题可以直接联系上。

  • SassLess这样的预处理器已经加快了对CSS规范的更新速度。好比jQuery激发了今天的JavaScript的想象力,这些处理器带来了人们想要的功能。

  • 社区花费了大量时间使CSS更易维护。Nicole Sullivan写作的《面向对象的CSS》Brad Frost《原子设计》已经存在多年了,并应该有助于降低复杂性。

CSS能为你做什么

这里有一些CSS的超赞功能,你可以尝试用用。

计算CSS值(Calculated CSS values)

CSS中似乎一直缺失计算值的方法。典型的例子是宽度为100%但需要padding的绝对定位元素。在过去,我们需要通过嵌套另一个元素并它加上padding来应用填充。现在我们可以使用 CSS calc() 并添加宽度calc(100% – 1em)。

计算属性(calculation) 在浏览器中支持良好,可以放心使用。

媒体查询

CSS媒体查询 允许你对文档视口的更改做出反应。实质上,它们意味着当视口满足某些标准时,你将应用部分样式表。这可以是至少一定宽度或至多一定高度的视口。如果文档是打印件,你还可以查看屏幕是纵向或横向。

CSS媒体查询在JavaScript有着一个相应的模块叫做matchMedia。它允许按需加载内容。媒体查询的一个问题是,无论合适与否,浏览器都会以块的形式加载图像。

内容生成

使用::before::after这类CSS中的伪选择器允许你创建纯视觉的内容。这个方法非常好,因为它能确保只是出于美观而做的东西不需要一个单独的空的DIV、SPAN、B或I元素。使用这个方法,开发者可以不在脚本或者HTML文档中,而是在样式表中保留所有视觉信息。你可以将其与阴影,渐变和其他创建视觉效果的CSS功能配对。一个令人印象深刻的例子是“一个DIV“。该网站展示了单个DIV元素创建的数十个视觉效果。

这张图片就是一个用生成内容创建的单个DIV

动画和过渡

CSS里的动画过渡是iPhone出现后的一个重大突破。过渡让你能够创建从一个状态到另一个状态的平滑变化。你不需要知道应该发生什么变化。只需要告诉浏览器转换时间的长度和使用什么缓动函数。动画则给你更精细的控制。你能够定义关键帧,以及动画的表现方式。动画和过渡能够发生在事件开始阶段、进行阶段和结束阶段。这允许你以可预测的方式与JavaScript进行交互。使用CSS的好处是浏览器能够确保动画的性能,通过在GPU上运行它们并在需要时调节帧速率来实现。这也是确保用户手机电池寿命良好的关键。如果在JavaScript中动画,可能很容易发生错误。

视口单位(Viewport Units)

当你想要详细定义体验时,媒体查询很有用。但是,你还能用视口单位根据可用空间对元素进行大小调节。视口宽度(vw)是完整视口宽度的百分比。所以在480px宽屏幕上,10vw是10%或48px。这与%单位不同,%单位是父元素的百分比,而不是视口。嵌套的百分比会变小,vw则不会。视口高度(vh)是完整视口高度的百分比。你也可以使用的vmin和vmax的设置,采用的vw和vh中较小或者较大的那个。支持视口单元的唯一的缺点是,到目前为止,Edge仍然不支持vmin和vmax。

CSS Tricks有一篇很好的文章《视口单位能有多强大》。从分辨率独立嵌入到依赖视口的排版,你可以使用视口单元创建高度灵活的界面。

弹性盒子(Flexbox)

弹性盒子 是一种在CSS中创建元素布局的方法。实质上,所有声称布局表格更容易的人,都会在CSS中错过这点——及更多的功能。你可以将元素的子元素右对齐、左对齐、顶部对齐或底部对齐。你可以让它们来填充可用空间,每个元素使用相同的或大于其它元素的空间。你还可以让它们使用彼此之间或其周围的可用空间。它与在tin上说的一样灵活。如果你想要一个可视化的编辑器来看看这是什么意思,可以玩玩这个:用React生成的一个好用的flexbox编辑器

还有一个名为Flexbox Froggy的游戏的游戏。它用好玩并且方便的形式教导这些概念,对于孩子们来说从CSS起步非常不错。

Zoe Gillenwater在许多场合都做过一个关于弹性盒的优秀演讲。讲演中我最喜欢部分是Zoe展示他们如何在产品中使用弹性盒子。范例来自booking.com,同时还展示了不支持这个的浏览器上的回退(fallback)方案。

CSS 网格(Grid)

如果说弹性盒子解决了一行或一列中元素布局的问题,CSS网格则进入了下一个阶段。它可以让你在两个维度(行和列)定义的网格里摆放元素。网格已经存在了一段时间,现在终于得到了(浏览器的)全面支持。

一些设置将一系列元素转换为灵活的网格

网格可能会不太好看,因为它的灵活性意味着有很多选项可供选择。到目前为止,最简单的方法是Rachel Andrew的 “Grid by Example” 资源。这里给出了一个网格布局的复制+粘贴的示例。他们中的许多人对于不支持的浏览器都有备选项。

如果你在有挑战的环境下才能学得更好,你可以通过玩CSS Grid Garden来学习CSS网格。

学着用CSS网格来给胡萝卜浇水。

有一些“必看”的关于CSS网格的演讲。第一个是“CSS网格布局“,同样来自Rachel Andrew,

Jen Simmons 采取了不同的做法。在她“网页真实艺术指导” 演讲中,她说明了网格的多功能性是如何帮助我们突破“盒子布局”思维的。

另外还可以将网格和弹性盒子配合使用在单元格中可以并且应当使用弹性格子。一起使用这些工具可以帮助你创建灵活的布局,允许可变的内容和适应可用空间发生的改变的布局,Web的布局。

CSS 自定义属性 (变量)

一个在类似Sass和Less这样的预处理器已经有了的,人们期待已久的CSS功能之一就是变量。现在我们有了CSS自定义属性,这个消息让我非常振奋的。你可以在文档中定义一次可重用的设置,并将其应用于整个文档。最常见的使用场景是自定义颜色和大小。但是你可以进一步定义字体和其他排版。你还可以使用它们来嵌套CSS中的计算。这在之前是完全不可能的。此外,让人惊讶的是,自定义属性也可以使用JavaScript动态设置。

如何使用JavaScript阅读和编写自定义CSS属性 - (摘自Lea Verou的演讲)

如果你想了解所有关于CSS自定义属性的惊人能力,这里有一个你不应该错过的演讲:Lea Verou’s “CSS Variables: var(—subtitle)”,这就是一个信息的宝库。

CSS 特性查询

另外一个非常受欢迎的CSS功能是特性查询(Feature Queries)。这非常像媒体查询。通过使用@supports,你可以检查当前用户代理是否支持某个功能。接着可以定义一个CSS块,仅在功能支持时才应用。你可能会觉得奇怪,因为CSS的容错性质应该已经照顾到了这点。但是,它的作用是提供更精细的控制。当部分用了“not”关键字的特定功能不被支持的时候,还可以定义回退。

CSS和JavaScript?

同时使用CSS和JavaScript能够作出强大的、正确的事情。就CSS而言,它仍然无法做到所有事情。在一些场合,CSS的天然特性与我们想要实现的效果是相反的。

就像Cristiano Rastelli在他的 “让CSS充满和平” 的演讲中所说,“分离问题”(Separation of Concerns)的珍贵特征不适用于模块世界。

当CSS成为一种趋势,我们将所有的外观、感觉和行为从HTML转移到CSS和JavaScript中。我们可以在文档上甚至是项目范围下定义。我们庆祝CSS能够继承父元素样式的事实。但当我们构建可以重新使用的组件时,又不希望如此。我们希望它们带有自己的外表、感觉和行为,并且不会渗透到邻近的元素上或从父母继承。

CSS和JavaScript在非模块化的世界中合作

在构建基于文档的解决方案时,完全有理由去挖掘CSS的力量。你可以并且应该使用JavaScript来为CSS提供它不能读取信息。尽管以最小的影响来这样做需要慎之又慎。

在这种情况下,用CSS和JS搭配工作的层次结构如下:

  • 如果你能使用css的时候 – 使用你在这篇文章里看到的东西

  • 如果需要与CSS通信,考虑 更改自定义属性(Custom Properties)

  • 如果该选项不成立,通过classList在父级元素上应用类(classes)

  • 作为最后手段,你可以 直接更改样式

一个绝佳的例子,展示了如何在JavaScript中读取鼠标位置并将其存储在CSS自定义属性中 – (摘自Lea Verou的演讲)

每当你动态更改样式时,请记住你正在对付浏览器。每种风格的变化都会在回流、渲染和绘画方面产生后果。Paul LewisDas Surma维护着一个名为《CSSTriggers》的便捷指南。在里面详细描述了哪个CSS更改导致了浏览器的哪个问题。

CSS 触发器提供不同样式变化的效果信息。

总结

CSS比过去可靠得多,剩下不符合标准的地方也不多了。 需要牢记的最主要的事情是,CSS并不意味着与JavaScript做同样的事情。即使布局语言也不能像CSS那样工作,满足同样的需求。它所承担的任务艰巨,但表现出色。 当你使用CSS时,无论终端用户的设置是怎么样的,浏览器都能够帮助你满足他们的需求。这是网页的核心原则,并在 W3C HTML设计原则中被定义为:

用户高于页面作者高于实现者(或者浏览器)高于规范制定者(W3C/WHATWG)高于理论的纯粹性

我们的用户应该获得平滑的、可靠的、省电的界面。 所以,再考虑一下CSS把。你还可以通过借鉴社区的成果来偷懒。

以下是一些灵感来源和活跃的CSS使用者

在准备这个话题时,我会时不时回看网上一些特别优秀的人撰写和维护的资源。 如果你想要跟上CSS的发展,这里有一个简短的没有特定排序的人员列表供你关注。我要感谢他们每个人。他们正在为我们所有人提供更易使用的的网页。

  • Ire Aderinokun (@ireaderinokun) 在博客bitsofco.de.上写了很多易于掌握的并且切中要害的CSS信息点。

  • Ana Tudor (@anatudor)是一名开发人员,她在CSS中创建极其复杂而美丽的动画。她的Codepen 是最活跃的之一,并对CSS引擎所做工作为浏览器制造商测试浏览器性能提供了很大的帮助。

  • Jen Simmons (@jensimmons) 是Mozilla(火狐浏览器的公司)的CSS布局和设计专家。

  • Rachel Andrew (@rachelandrew) 对我来说是 #1 的CSS网格专家。

  • Chris Coyier (@chriscoyier) 是超赞的CSS资源共享网站CSS Tricks 与交互开发社区 Codepen的创始人。

  • Sarah Drasner (@sarah_edo) 是一位专注于构建可维护产品的动画和设计专家

  • Zoe M. Gillenwater (@zomigi)是一位在产品中使用最前沿CSS技术的开发主管。

  • Brad Frost (@brad_frost)是《原子设计》(Atomic Design)的作者,讲述了在大型项目中如何使用和重用CSS的可扩展方式。

  • Rachel Nabors (@rachelnabors)是一位漫画家和动画专家,会撰写关于Web动画和不同技术的优点的文章。

  • Una Kravets (@una)是专精CSS及其新功能的开发人员。 她也是一个播客主,她总能把握住CSS和其他视觉技术的最新脉动。

  • Lea Verou (@leaverou) 是《CSS揭秘》(CSS Secrets)的作者、麻省理工学院研究员、W3C的CSS工作组的特邀专家。 她在研究中一丝不苟,严于律己,并能在短时间内交付大量丰富的信息。

  • Sara Soueidan (@sarasoueidan)是一位响应式设计及将新技术实际运用的专家。

我每天都能在这些人(还有其他人)那里得到灵感,希望你也能拥有这样的体验。

PS: 备份内容仅显示纯文字。

抱歉,服务器忙,未能成功提交,稍后重试。