上个周末由于本身要写PPT而没来得急整理,因此又错过了一期。在这一期中,大部份内容将围绕着@Bill Mei的《Top 10 most deadly CSS mistakes made by new and experienced developers》文章中提到观点来展开。这里面的一些观点虽然不彻底对,但仍是有相应的参考价值,取舍由你们本身来决定。若是你在这方面也有相关的经验,也欢迎在下面的评论中分享。另外在后面会简单的整理几个最近以为有意思的新东西。感兴趣的同窗,请继续往下阅读。javascript
多年来,不少工程师在使用CSS时容易犯一些常见的错误,无论是老司机仍是新手。而CSS一直又是简单但不容易的语言(不直观和难以使用),真正探究的并很少,而不少常见的错误又每每会阻碍项目的开发进程。若是咱们在编写CSS的时候就能避免这些错误,是否是在实际开发的时候能事半功倍。css
如下是编写CSS中常见的10个错误,也是最致命的错误。html
接下来的10条内容来自于@Bill Mei的《Top 10 most deadly CSS mistakes made by new and experienced developers》一文。前端
有一些开发人员喜欢追求一种极简主义的风格,他们试图着不在HTML中有大量的类名(class
),经过使用DOM结构来做为CSS的选择器,这样他们的选择器就会遵循DOM树的结构。好比有这么一个DOM结构:vue
<body>
<div class="container">
<div class="main-content">
<div class="blog-row">
<div class="blog-col">
<section>
<article>
<a href="#">This link is not bold</a>
<p><a href="#" class="bold">This link is bold</a></p>
</article>
</section>
<section>
<a href="#">This link is not bold</a>
</section>
</div>
</div>
</div>
</div>
</body>
复制代码
有些同窗在给a
连接添加样式的时候,会这样的操做:html5
body .container .main-content .blog-row .blog-col section article p a {
font-weight: bold;
}
复制代码
就算是在使用CSS处理器的时候也无限级的嵌套,经如:java
body {
.container{
.main-content{
.blog-row{
.blog-col{
section{
article{
p{
a{
font-weight: bold;
}
}
}
}
}
}
}
}
}
复制代码
特别是在CSS的处理器中,不要说是新手,不少老司机也会出现相似上面这样的错误。react
虽然在编写HTML结构的时候,不少司机也提倡DOM结构能简洁就尽可能的简洁,但并非提倡这种无约束的极简主义。由于这种极简主义虽然保持了HTML的干净,但会让CSS变得混乱,使其更难理解、调试和更改。就如上面的示例所示,CSS会变得不灵活,由于长组合的CSS选择器承担了复制HTML结构的任务,但这有背于CSS应该作的事情。css3
CSS的任务是提供样式;HTML的任务是提供结构。这也是Web构建中最基本的原则之一。若是仅仅追求DOM简洁干净,而忽略CSS,不考虑与CSS相互结合,这是错误的一种作法。另外这种编写CSS的方式强度依赖于HTML的DOM结构树,也会形成不少致命性的错误,好比说,你的HTML结构作出调整,那么CSS选择器也将作调整,而这种长链条的组合是最易于出错的。这种作法也在无形中增长不少没必要要的工做。web
相反,我更建议CSS的类和HTML的DOM更应该合理的结合起来。若是你须要从页面中选择一个特定的元素,应该在该元素上添加一个类名来完成:
.bold {
font-weight: bold;
}
复制代码
就算是你要使用这种长组合的方式来定位到DOM元素,我也强烈建议:
CSS的选择器不超过三级。
幸运的是,如今有不少方式能够帮助咱们避免这种方式,好比借助StyleLint来监控你的CSS代码,让选择器不超三级嵌套。也可使用CSS-in-JS和CSS Modules方式来维护你的CSS代码。特别今天(截至2019年),这种方式更被普遍的采用。
若是你对CSS-in-JS和CSS Modules感兴趣的话,我建议你花点时间阅读下面的相关文章:
话说回来,咱们在项目中应该避免目标过于明确或指定过多的选择器,而且要避免使用!important
。CSS权重的对比让咱们更直观地了解为何选择器器权重过大是很差的。若是选择器权重过大,它会更易被采用,若是咱们想要经过另外一个选择器来覆盖它,就须要一个权重更大的选择器。这也是令不少同窗在覆盖样式时感到痛苦之处。
CSS选择器权重的争夺战是一直存在你的CSS中,这也是令不少老司机和新手痛苦之处。若是你是新手,那么掌握CSS选择器权重是的计算是很是有必要的:
说到CSS选择器权重之争,我又要上@Elijah Manor
若是上图还没法让你整明白CSS选择器权重的计算,那么下面这个计算器就能够帮助你更好的理解:
搜索引擎优化(SEO)不只仅是你完成编码后交给营销团队来处理。咱们在编码的时候就须要考虑到SEO的内容,特别是由于一些影响SEO的因素。由于影响SEO因素一旦产生,那么后续要优化的难度就会更大。好比网站的URL Scheme
或服务体系结构。
众所周知,HTML的语义化标签是影响SEO的因素之一,由于标签的选择会影响搜索引擎对内容的理解和排名。若是你想显示在搜索结果的顶部附近,那么就得选择正确的标签。
假设你正在写一篇关于CSS教程的文章。你能够把全部内容都放在一个<div>
中,然而<div>
是一个通用的非语义的标签,它不包含内容中的任何内在的含义。相反,你应该选择一个更具体的语义标签,例如<article>
来包含文章的内容,<nav>
来包含到跳转到其余文章的连接。
选择更具体的语义标签而不是通常非语义标签的好处是,你能够向搜索引擎提供关于你的网站更多的信息,这样一来,搜索引擎的爬虫能更好的理解和交付与读者的搜索查询相关的内容。
例如,用于文章标题的HTML标签,它有六个潜在的标题标签,按最重要的标题到最不重要的标题的顺序排列h1~h6
(数值越小,表示越重要)。<h1>
是你最重要的标题,由于它是一个特殊的信号,搜索引擎会把这个理解为你内容的标题或者页面的标题(<title>
,大多数搜索引擎二者都会考虑)。此外,若是你的用户视力受损,而且使用屏幕阅读器,大多数屏幕阅读器都知道要当即大声的朗读<h1>
中的内容,由于它会先假定这是你的内容的标题。
这也意味着,若是你使用<h1>
来处理任何不是标题的内容,或者你在一个页面上有多个<h1>
,搜索引擎就会被混淆,你的“真实”标题(想要第一时间让搜索引擎识别的标题)可能不会出如今搜索结果中。另外的一个状况是,在不一样的部分嵌套多个<h1>
,好比:
<article>
<h1>My cool blog post</h1>
<p>This blog is so cool!</p>
</article>
<footer>
<h1>Contact Us</h1>
<p>Tel: 867-5309</p>
</footer>
复制代码
尽管这个页面上有两个<h1>
标签,但第一个是在<article>
中,而另外一个是在<footer>
标签中。因为搜索引擎理解<article>
的内容要比<footer>
的内容更重要,更有趣;因此它会使用<article>
中的<h1>
,而不是<footer>
中的<h1>
看成标题。因此在某种意义上,你的父母是谁,决定了你有多重要。现实生活中也是如此,有个好爹是多么的重要。
有关于HTML正确的打开姿式,@Daniel Tonon的《How to Section Your HTML》一文就作过这方面深刻的探讨:
有关于HTML标签和SEO之间的关系,更多的内容能够阅读下面的文章:
随着JavaScript框架的崛起,好比Vue
,React
等。不少同窗平时在使用这些JavaScritp框开发页面的时候,可能也不太关注什么SEO相关的事情。事实上在国外有关于Vue,React开发页面时对SEO方面的讨论仍是蛮多的,感兴趣能够阅读:
另外在Reddit和知乎上也有相关的讨论:
最后在给你们推荐一个工具Prerendering,号称是最好的SEO解决方案:
The best SEO solution, and SSR replacement for JavaScript websites. It’s like SSR with no need of coding.
px
单位使用px
单位并非一个错误,但要看使用的场景。真正的错误是使用绝对单位而不是相对单位。
有关于CSS单位更多的介绍,能够阅读《图解CSS:CSS 的值和单位》一文或点击这里了解更多的内容。
咱们更喜欢使用相对测量方法,好比em
、%
、rem
和其余可能的方法。之确保了网站的缩放比例能根据font-size
进行缩放。
// 很差的用法
p {
font-size: 16px;
line-height: 20px;
margin-bottom: 8px;
}
// 好的用法
body {
font-size: 16px;
}
p {
font-size: 1rem;
line-height: 1.25;
margin-bottom: 0.5em;
}
复制代码
好比下图,就是使用em
单位好的缩影:
时至今日,使用px
这种绝对单位的问题是没法较好的适配于不一样终端,特别是在移动终端上,面对的场景更为复杂。若是使用px
单位不能让你的Web页面或Web应用程序在任何地方都保持相同的比例,因此你必须尝试将你的元素放在相对项中,而不是绝对项中。不然,屏幕上的可用空间不能适当地缩放到每一个窗口大小。相对单位使用这种简单的px
锁定你的设计到特定的缩放级别,使你的设计难以缩放到不一样的设备。
在移动端的天下,我更建议使用视窗单位来作测量单位,更易于让你的设计能在不一样的设备终端达到缩放效果。若是你对这方面感兴趣,建议您花点时间阅读:
更广泛地说,在编写CSS时,“像素级”的完美设计并非一个好的目标。
现代Web页面或Web应用程序必须跨多种设备(移动设备、桌面设备、平板电脑、TV大屏和手表)运行,其中有多样的屏幕大小、屏幕分辨率、操做系统、用户设置和JavaScript引擎,这些都会干扰渲染“像素级”完美设计的能力。
在我看来,一味地追求“像素级”完美的设计将须要更多额外的代码来处理,这些额外的代码将带来更大的复杂性和潜在的风险。能够说是“付出与收益不成正比”。
不过有一点须要特别提出,不要将“像素级”的完美设计和优秀的设计混淆。真正伟大的设计是给用户留下持久的情感影响。这是当他们打开你的产品时所获得的快乐,也是他们从你的Web应用中获得的快乐。而这一切并非你选择16pt
字号而不是15pt
字号的崇拜。
CSS的棘手之处在于使用不一样的CSS代码能够实现相同的视觉效果。例如,要将页面上的元素水平垂直居中,能够有不少种方式,使用任何一处均可以让你的用户看到相同的效果。
@Amos整理了相关的技巧,可达23种方式来实现垂直居中。
虽然实现同一效果有不少种方式,但我建议咱们在实现效果的时候应该尽可能的避免中断文档流。由于过于频繁地中断文档流(例如,过分使用float
)会增长对内存的占用,并且让别的小伙伴甚至是你本身更难理解。
当有多个方案实现相同的视觉效果时,我更喜欢使用中用内存空间更小的技术。
CSS的任务是提供样式,HTML的任务是提供结构。一般,你应该首先以捕获页面信息结构层次的方式编写HTML。即:
在编写HTML的时候,应该忽略任何设计关注点。
而后,添加CSS,让视觉上看起来很好。
虽然HTML提供告终构,但它不能老是将元素定位在你但愿它在页面上出现的准确位置。所以,可使用CSS构建页面的正确布局,以便元素出如今正确的位置。一旦一个元素被放置在页面的正确位置,就能够很容易地修饰它,使它看起来很漂亮,而不用担忧它的位置。所以:
CSS布局(Layout CSS)和CSS美化(Lipstick CSS)是作着不一样的事情。
简单的看两示例:
// 很差的示例
.article {
display: inline-block;
width: 50%;
margin-bottom: 1em;
font-family: sans-serif;
border-radius: 1rem;
box-shadow: 12px 12px 2px 1px rgba(0, 0, 0, .2);
}
.sidebar {
width: 25%;
margin-left: 5px;
}
<div class="article"></div>
<div class="article sidebar"></div>
// 好的示例
/* Layout */
.article, .sidebar {
display: inline-block;
}
.article {
width: 50%;
margin-bottom: 1em;
}
.sidebar {
width: 25%;
margin-left: 5px;
}
/* Lipstick */
.card {
font-family: sans-serif;
border-radius: 1rem;
box-shadow: 12px 12px 2px 1px rgba(0, 0, 0, .2);
}
<div class="article card"></div>
<div class="sidebar card"></div>
复制代码
CSS布局(Layout CSS)和CSS美化(Lipstick CSS)工做的分开也被称为关注点分离(Separation of Concerns),这是软件工程的一个通用原则,有助于保持代码的可维护性和易于理解。
咱们但愿使用合适的工具来完成这项工做,由于以这种方式分离CSS能够很容易地将一个元素移动到页面的另外一部分,而不会弄脏Lipstick CSS,还能够很容易的更改Lipstick,而不会破坏Layout。每次咱们添加一个新特性时,混合使用之两种方法都会迫使咱们同时作这两项工做。
随着移动终端的普及率的提升,移动网站(或应用)成为主流。不少人开始提“移动第一”,在提这个理念的时候也意味着桌面(PC端)是二等公民。相反,“移动优先”的拥护者则表现出相反的行为,他们首先为桌面编写代码,而后试图将网站塞进移动端。他们使用@media
来处理移动端设备上的异常,但实际状况是桌面端才应该是异常。
在这个移动端的时代,你的用户首先经过他们的手机找到你,而后他们要是足够喜欢你的产品,才会到桌面端去体验。但在你的设计师、开发者和产品经理看来,手机真的是第一位吗?你是否先编写移动端的代码,而后再构建桌面端?你的设计师是先为手机建立线框图和模型,而后再为台式机建立线框和模型吗?在测试桌面版本以前,你是否在移动端版本上执行A/B
测试,并征求用户的反馈?
//很差的作法
.container {
width: 980px;
padding: 1em;
}
@media (max-width: 979px) {
.container {
width: 100%;
padding: 0.5em;
}
}
// 好的作法
.container {
width: 100%;
max-width: 980px;
padding: 0.5em;
}
@media (min-width: 980px) {
.container {
padding: 1em;
}
}
复制代码
另一个主要的缘由是,从移动端上往大屏幕上扩展会更容易;但要从大屏幕上删除元素使其适合较小屏幕,就会比较棘手。
Namespaces are one honking great idea – let’s do more of those! — PEP 20: The Zen of Python
在CSS中给元素命名老是很烦人的,若是让你不要考虑命名方案就直接写代码,你必定会很兴奋。例如你给一个<img>
元素添加类名的时候,你可能会将它命名为.img
、.image
、.blog-img
、.img-blog
等。若是你将它命名为.blog-img
,那以后你还会接受.ad-img
和.thumbnail-img
的命名?
给元素命什么样的名,虽然看起来是一件很小的事情,可是CSS要比其余语言更难重构,由于咱们目前没有任何用于CSS的静态分析工具来执行自动重构或重命名。CSS类可使用JavaScript动态地添加、删除和构造,所以不可能找到“未声明”的CSS选择器 —— 仅仅由于CSS片断没有在一个页面的一个状态中使用,并不意味着它从示使用过。
另外,若是你的团队不能就是否将其命名为.center
、.centre
、.centered
、.text-center
或.align-center
达成一致,那么BEM也就没法解决之个问题。
在一些JavaScript框架中,使用CSS-in-JS能够部分地解决这个问题,由于这些框架删除了CSS的全局做用域,并鼓励你将样式与其关联的组件放在一块儿。然而,CSS-in-JS尚未被普遍采用,并且这方面的争议也不少。
还有一个主要缘由是,开发人员在删除任何可能破坏网站的内容时老是会犹豫不决。所以你们宁肯谨慎行事,也可愿增长垃圾代码,也不敢去冒险。更糟糕的是,除非你很努力的推广和清晰地沟通你的设计系统,不然它可能会被忽视,由于你的同事会避免阅读你的文档,继续他们的老习惯。
这看起来彷佛很简单。好比说使用Bootstrap,不少同窗认为只要安装了就能够了。不幸的是,若是你不真正理解CSS框架(CSS Framework),而且不当心违背了它的原则,那么它经常会致使比引用它来解决问题更多的问题出现。不管你使用的是Bootstrap、Material Design、Foundation等开源设计系统,仍是你本身团队开发的设计系统。
所以,在使用任何一个框架或系统以前,颇有必要花必定的时间去阅读相关的文档。
认真阅读文档是很重要的,由于许多框架要求你取消从之前的框架中提取的肌肉记忆,并且只有阅读了整个手册,你才能知道其缺陷在哪里。例如,组件继承是较老的前端框架中的一种常见模式。然而,React这样的新框架在使用组合而不是继承时工做是最好的。若是跳过文档的阅读,你极可能就不会意识到这一点,你可能就会默认使用你习惯的继承模式。
更广泛地说,你被从旧技术发展而来的肌肉记忆所困住是很危险的,这会致使咱们犯最后一个致命的错误。
技术是不断革新的,保持相关性的惟一方法是遵循一个持续学习和改进的计划。
从教条中死记硬背知识是很危险的。一些有经验的开发人员一听到“内联样式(Inline Style)”就有着一种本能的反感,由于在他们的职业生涯的早期就被教导**“样式和结构的分离;永远不要使用内联样式”**。
事实上,“永远不要使用内联样式”是好久之前的最佳实践。那是当时的背景下会使HTML难以阅读、调试和更新。然而,这项技术的进展缓慢,最终颠覆了致使这些“最佳实践”的假设。新的假设导至新的最佳实践。
内联样式只有在行内写样式才是真正的痛苦,但若是使用CSS-in-JS的库来管理你的内联样式时,这些所谓的缺点就消失了,而你的优点也就只剩下代码模块化,自动化测试和简单的管理工做等。
若是你固守着“永远不要使用内联样式”的教条,那么当最初的假设发生变化时,你就不会有好奇心去探究它意味着什么。使用系统的,结构化的计划从头开始学习CSS是很重要的,而不是仅仅搜索来寻找一些只关注表面实践的教程。
不幸的是,我尝试着寻找免费的在线资源来帮助你结构化、系统化的学习CSS,但并无找到任何好的资源。现有的CSS资源要么过于技术化,而且假设你已经了解了浏览器渲染原理,要么它们只提供一些简单的技巧,而没有教给你一些有关于CSS的基本原理。
由于没有好的资源可让你对CSS从内心就有一个可靠的心理模型,因此不少时候碰到问题都是依赖搜索,而后复制和粘贴来解决。这使得不少人对CSS的知识都是东拼西凑的,只知道解决出现的特定的Bug就足够了,可是当面对一个看起来须要花费数小时才能修复的,又难以理解的Bug时,会立马感到彻底无助。
并且一直以来,在整个前端社区有一种不成文的理解。
CSS很是的简单,正由于其简单,才以为很容易。了解它的属性就会使用。
也正因这样的误导,你们以为CSS很容易,没有任何学习成本。甚至有一些同窗会认为,CSS就是手到擒来的东西。
而我想再次表达一个不一样的观点是:CSS是简单,但毫不容易:
Unlike a programming language that requires knowledge of loops, variables, and other concepts, CSS is pretty easy to pick up. Maybe it’s because of this that it has gained the reputation of being simple. It is simple in the sense of “not complex”, but that doesn’t mean it’s easy. Mistaking “simple” for “easy” will only lead to heartache.
上面罗列的一些观点不必定全对,但仍是蛮有参考价值的。虽然不是什么技巧,但能够帮助我学习更多的技巧。
backdrop-filter
实现磨砂玻璃效果磨砂玻璃的效果最先来自于苹果手机设备上的效果。
早在2015年的《CSS3 Filter的十种特效》和《高级CSS filters》介绍滤镜使用的时候就知道background-filter
这个属性。那个时候仅在Safari上才能看到效果,但从Chrome 76开始也能看到background-filter
带来的磨砂玻璃效果。
output
元素或许不少人听过input
元素,但对于output
元素据说过的应该不多吧。
其实在W3C的HTML5工做草案12(2019年02月)就添加了output
元素。在此工做草案以前,它在HTML5中被引用,直接是Web Forms 2.0中的定义。
从HTML规范中的原始定义到如今,output
的一些细节已经发生了变化,可是元素始终在表单元素的家族中。如今对output
的定义从“output
元素表示计算结果”到“output
元素表示应用程序执行的计算结果或用户操做的结果”转变。
来看一个简单的使用用例:
<form oninput="added.value=parseInt(i1.value)+parseInt(i2.value)">
<input type="number" min="0" name="i1" value="0"> +
<input type="number" min="0" name="i2" value="0"> =
<output name="added">0</output>
</form>
复制代码
有关于output
元素更多的介绍能够阅读:
:not()
在《初探CSS 选择器Level 4》一文中有详细介绍过:not()
这个函数伪类的使用。
否认伪类:not()
是一个函数伪类,以选择器列表作为参数,它表示的元素不是由其参数表示的。:not()
选择器能够用来作为判断的一个选择器,比如JavaScript中的非。其主要做用就是将符合规则的元素剔除,将样式规则应用于其余元素上。事实上,在CSS Selector Level 3就有:not()
的身影,只不过当初的功能比较弱,好比:not(p)
用来选择不是<p>
的元素。但在新版本的中,其功能变得更为强大,能够应用更为复杂的规则,可是一样地不容许嵌套使用,好比:not(:not(...))
。
咱们平时开发项目的时候,时常会碰到列表这样的效果,列表项之间有一个margin-bottom
,而每每想在最后一项中不设置margin-bottom
。好比像下图这样的效果:
若是要避免多个类的时候,能够将它们链接起来,由于:not()
没有逻辑组合符的操做,因此咱们能够这样作:
body:not(.home):not(.away):not(.page-50) {
}
复制代码
前几天@张鑫旭老师在《CSS :not
伪类可能错误的认识》一文中也详细阐述了咱们对:not()
使用时容易搞错的几个点。好比,搞不清楚其优先级、不支持复杂选择器、容易搞不清楚的否认逻辑关系等。
JavaScript中从字符串中删除最后一个字符的两种方法:
// 使用`slice`
let input = "w3cplus.com"
function removeLastCharacter(str){
let charcter_arr = str.split('');
return charcter_arr.slice(0, charcter_arr.length - 1).join('');
}
let output = removeLastCharacter(input);
console.log(`Output is ${output}`); // => Output is w3cplus.co
// 使用substring方法
let input = "w3cplus.com"
function removeLastCharacter(str){
return str.substring(0, str.length - 1);
}
let output = removeLastCharacter(input);
console.log(`Output is ${output}`); // => Output is w3cplus.co
复制代码
这两年有关于CSS Grid Layout的相关讨论在社区中很是的火爆。强大到只须要添加一行代码就能够实现响应式的布局(一些特定场景)。
这一行代码就是:
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
复制代码
代码中用到了repeat()
、auto-fit
、minmax()
和fr
。接下来用@Per 文章中的几张GIF图来向你们展现他们的做用:
<!-- HTML -->
<div class="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
</div>
// CSS
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 50px 50px;
}
复制代码
看到的效果以下:
把100px
换上1fr
:
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 50px 50px;
}
复制代码
效果以下:
使用repeat()
可让代码更干净:
.container {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-template-rows: repeat(2, 50px);
}
复制代码
使用auto-fit
作自动填充:
.container {
display: grid;
grid-gap: 5px;
grid-template-columns: repeat(auto-fit, 100px);
grid-template-rows: repeat(2, 100px);
}
复制代码
加上minmax()
用一行代码在一些场景中就能够达到响应式效果:
.container {
display: grid;
grid-gap: 5px;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
grid-template-rows: repeat(2, 100px);
}
复制代码
有关于repeat()
、auto-fit
、minmax()
和fr
更多的介绍,能够阅读:
fr
minmax()
函数如何工做minmax()
and min()
auto-fill
vs auto-fit
文章围绕@Bill Mei的《Top 10 most deadly CSS mistakes made by new and experienced developers》进行展开。在Chrome78开始可使用backdrop-filter
实现磨砂玻璃的效果,HTML新增的output
元素能够用来表示应用程序执行的计算结果或用户操做的结果;CSS的:not()
虽然没有逻辑符来,但能够经过多操做符来组合,达到相似逻辑组合的效果。最后使用@Per制做的几张Gif图简单粗暴的告诉你们如何使用CSS Grid Layout中的repeat()
、fr
、auto-fit
和minmax()
,从而使用一行代码达到响应式的效果。经常使用于列表布局的场景中。
最后,但愿这一期的内容你们会喜欢。若是你有更好的建议或相关的积累,欢迎在下面的评论中与咱们一块儿分享。