五个最新的CSS特性以及如何用它们

  • 时间:2018-07-31 22:45 作者:全栈取经之路 来源:全栈取经之路 阅读:264
  • 扫一扫,手机访问
摘要:尽管CSS简单,但CSS是一门非常有意思的语言,CSS每年都有变化,而且都有不同的博主都在不同的时间段总结少量CSS的新特性。尽管这些新特性无法立刻得到众多浏览器的支持,但总是随着时间的发展,这些特性都会得到浏览器的支持。哪怕未得到支持,也有少量方法让浏览器支持,比方最为出外的 cssnext ,即

尽管CSS简单,但CSS是一门非常有意思的语言,CSS每年都有变化,而且都有不同的博主都在不同的时间段总结少量CSS的新特性。尽管这些新特性无法立刻得到众多浏览器的支持,但总是随着时间的发展,这些特性都会得到浏览器的支持。哪怕未得到支持,也有少量方法让浏览器支持,比方最为出外的 cssnext ,即可以让很多未来的CSS特性就立马用,并且不使用花太多时间来考虑浏览器的兼容性。

今天这篇文章, @Daniel Crisp就当下的CSS的新特性 做了一个简单的总结 —— 五个最新的CSS特性(事实上这些特性,对我而言并不是新特性),并且使用示例告诉大家怎样用这些特性。那么接下来,咱们看看这五个新特性是什么?以及怎样用。假如您感兴趣,欢迎继续往下阅读。

前言

@Daniel Crisp在他的博文中 ,讨论了CSS的五个新特性,详情了这五个特性能做什么,以及如何将它们应使用到你的项目中。而且提供示例每一步的代码,可以在 GitHub的仓库中获取这些代码 ,不过在接下来,我将会借助 Codepen 来向大家展现。

接下来要详情的五个CSS新特性是:

  • CSS Display Module Level 3 : display:contents
  • CSS Conditional Rules Module Level 3 : @support(...){...}
  • CSS Overscroll Behavior Module Level 1 : overscroll-behavior: contain
  • CSS Selectors Module Level 4 : :focus-within , :placeholder-shown
  • CSS Containment Module Level 1 : contain:paint

这些CSS特性,预计有些同学已经接触过了,假如你未接触过,建议你继续跟随着下面的步骤继续往下阅读。

案例:创立一个新闻提要(Newsfeed)

通过一个新闻提要为例,分不同的步骤向大家阐述这个新闻提要是怎样制作的,以及在制作这个案例的时候,这五个CSS特性是如何在案例中得到运使用。

Step1:新闻提要的HTML模板

我们这个案例其实很简单,并未用任何JavaScript框架,还是用原始的HTML结构来做这个Demo。所以我们需要少量简单的HTML的标签,帮助我们创立Demo。这里用了一个类名为 .container 的 div ,该 div 包含了一个类名为 .feed 的 ul ,而后创立了十个 li ,每个 li包含了一个类名为 .card 的 div 。

在第五个和第六个 li 之间创立了另一个名为 nested 的 li ,其包含了一个无序列表 ul ,而且包含了三个 li 创立三个卡片。

class="container">

<ul class="feed">

<li><div class="card">Card 1div>li>

<li><div class="card">Card 2div>li>

<li><div class="card">Card 3div>li>

<li><div class="card">Card 4div>li>

<li><div class="card">Card 5div>li>

<li class="nested">

<ul>

<li><div class="card">Card Adiv>li>

<li><div class="card">Card Bdiv>li>

<li><div class="card">Card Cdiv>li>

ul>

li>

<li><div class="card">Card 6div>li>

<li><div class="card">Card 7div>li>

<li><div class="card">Card 8div>li>

<li><div class="card">Card 9div>li>

<li><div class="card">Card 10div>li>

ul>

在没有任何样式的情况之下,你看到的效果是这样的:

Step2:增加样式

现在要给示例增加少量基本样式,使其看起来更像一个新闻提要:

body {

background-color: grey;

}

.container {

max-width: 800px;

margin: 0 auto;

}

.card {

background-color: #fff;

padding: 10px;

margin: 10px;

min-height: 300px;

}

最后,在 .feed 上用Flexbox相关的特性,让每行有两张卡片:

.feed {

display: flex;

flex-wrap: wrap;

li {

flex: 1 0 50%;

}

}

效果如下:

假如你从未接触过Flexbox相关的知识, 强烈建议你花点时间阅读这些文章 。由于Flexbox发展到今天,已经开始取代 float 来布局,成为最主流的布局方式之一,特别是在手机端上的布局。

Step03:处理布局问题

当你向下滚动列表时,你会发现 .nested 下的三个 li (对应的是 CardA ~ CardC )影响了整体的布局效果:

五个最新的CSS特性以及如何用它们

其实我们想要的,或者者说理想状态下,所有的卡片按流的方式排列,但事实并未如此。造成这种现象的起因是Flex容器 —— ul.feed 设置了 display:flex (创立了一个Flex容器),创立Flex容器之后,只会对其子元素( ul.feed > li.card )有影响,就可子元素自动会变成Flex项目。但不会影响其后代子元素,换句话说, .nested > li 是无法自动变成Flex项目。

通常处理这个问题的唯一方法是更改HTML模板,但有些情况之下,比方说在CMS系统中(假设你没有修改HTML标签的权利),那么面对这种情况,你就会束手无策了。当然,你也许会想到用JavaScript来解决。或者许以前你会这么想,但时至今日,咱们可以通过新的CSS特性来处理这个问题 —— display:contents 。

W3C规范是这样对 display:contents 形容 的:

“The element itself does not generate any boxes, but its children and pseudo-elements still generate boxes as normal. For the purposes of box generation and layout, the element must be treated as if it had been replaced with its children and pseudo-elements in the document tree.“

大至意思是:“ 元素本身不产生任何边界框,而元素的子元素与伪元素依然生成边界框,元素文字照常显示。为了同时照顾边界框与布局,解决这个元素时,要想象这个元素不在元素树型结构里,而只有内容留下。这包括元素在原文档中的子元素与伪元素,比方 ::before 和 ::after这两个伪元素,如平时一样,前者依然在元素子元素之前生成,后者在之后生成。 ”

那么 display: contents 这一简单的代码实际上让元素体现得如同不存在一样。但依然可以看到元素的后代,而且元素自身并不影响布局。也就是说, .nested 的子元素 .card 也将变成Flex项目。

首先删除现有 .feed li 的类名,而后在 ul 和 li 是用 display: contents :

.feed ul,

.feed li {

display: contents;

}

这个时候 .feed 下所有的 .card 都变成了Flex项目(不仅是 .feed 下的子元素 li ,还包括后代的 li 元素):

五个最新的CSS特性以及如何用它们

现在你看到的所有卡片都是有序的排列,但是尺寸不对:

五个最新的CSS特性以及如何用它们

可以通过在 .card 上增加 flex 属性来处理这个问题:

.card {

flex: 1 0 40%;

}

这个时候每张卡片的尺寸就又恢复正常了:

这个时候就好象 ul 不存在了一样。假如你够仔细的话,你可以发现 flex-basis 的值设置为 40% 了,尽管我们设置了所有元素的 box-sizing 的值为 border-box ,但大家都知道, box-sizing 可以影响盒模型的计算,但对 margin 不包括在内,所以为了有足够的空间放置卡片,把 flex-basis 的值重新计算了,也就是大家所看到的 40% 。

这个示例也再次向大家说明了 display:contents 的神奇之处。当然,这里并没有对 display:contents 做详细的详情,但也足够向大家展现其强大之处。假如你对该特性感兴趣,或者者想深入的学习,建议阅读下面这几篇文章:

  • 如何了解CSS的 display 属性
  • CSS的 display:contents
  • 为什么是 display:contents 而不是CSS Grid的 subgrid
  • How display: contents; Works
  • Vanishing boxes with display contents
  • More accessible markup with display: contents

Step04:探究CSS查询特性

虽然 display:contents 实现了我们想要的效果,但它依然处于W3C的工作草案状态。目前只在Chrome 65+、Firefox 59+ 中看到效果。

假如你在浏览器开发者工具中,禁掉 display: contents ,你可以看到你的布局又开始混乱了。这样做只是模拟浏览器不支持该属性时的效果。那么我们接下来能做什么呢?这就引出了下一个CSS新特性 —— CSS查询特性

它的原理有点相似于CSS中的媒体查询( @media )一样,但是它允许你单独用CSS表达式,相似于JavaScript语言中的 if / else 之类。假如条件符合应使用对应块中的样式。接下来让我们把 display:contents 作为查询特性的条件,而后将对应的CSS样式放置在 {...} 块中。就像下面这样:

@supports (display: contents) {

.feed ul,

.feed li {

display: contents;

}

.card {

flex: 1 0 40%;

}

}

在CSS中,查询特性很多时候也被称为CSS的条件特性,其主要包括 @media 、 @supports和 @viewport 。有关于这方面的详情可以阅读@webinista写的PPT —— 《 Conditional CSS》。

可能你第一次接触到 @supports() 的话会感到很好奇,并不知道该属性的具体用,假如你愿意的话,建议你花点时间阅读早期整理过的文章《 CSS3条件判断: @supports 》和《 说说CSS中的 @supports 》。

Step05: 用 not 关键让代码变得更清晰

在CSS的世界中,像 @supports 这样其实也就是一种 渐进加强和优雅降级的方案 。我们可以用 @supports 来增加新的样式,但也可以增加降级所需的少量原始样式。

假如忽略IE浏览器的话, @supports 已得到很好的支持。实际上你可能希望用的是CSS查询特性,而不是某一种操作符。它的工作方式和你预期的一样,因而我们可以通过 @supports 的 not 关键词对那些不支持 display: contents 浏览器增加对应的样式。基于这个起因,我们可以把示例的代码修改成:

// 支持 display: contents的浏览器,采使用的是这段代码

@supports (display: contents) {

.feed ul,

.feed li {

display: contents;

}

.card {

flex: 1 0 40%;

}

}

// 不支持display:contents的浏览器,采使用下面这段代码

@supports not (display: contents) {

.feed li {

flex: 1 0 50%;

}

.feed li.nested {

flex-basis: 100%;

}

.feed li.nested ul {

display: flex;

flex-wrap: wrap;

}

}

在支持 display:contens 的浏览器,你将看到的效果如下:

五个最新的CSS特性以及如何用它们

在不支持 display:contents 的浏览器,看到的效果又像下面这样:

五个最新的CSS特性以及如何用它们

Step06: 更进一步优化

经过上面的示例,预计你已经体会到了CSS查询特性的魅力与潜力了,上面使用到的仅仅是查查询特性中的部分功能,更强大的是你可以 and 、 or 和 not 结合起来,让你的条件表达式更为强大。比方说,你的降级方案除了考虑 display:contents 之外,还会说有可能使用户的浏览器对 display:flex 也不支持。在这样的情况之下,咱们可以继续降级到 float 的布局。

不过我们在这里不会考虑降级到 float 的布局。但我们可以对 display: flex 和 display:contents 进行降级解决。这里会使用到 @supports 中的 and 和 not 关键词。上面的代码就变成像下面这样:

@supports (display: flex) and (display: contents) {

.feed ul,

.feed li {

display: contents;

}

.card {

flex: 1 0 40%;

}

}

@supports (display: flex) and (not (display: contents)) {

.feed li {

flex: 1 0 50%;

}

.feed li.nested {

flex-basis: 100%;

}

.feed li.nested ul {

display: flex;

flex-wrap: wrap;

}

}

甚至你还可以在 @supports 中用CSS的自己设置属性,比方像下面这样:

@supports (--foo: green) {

...

}

假如你对 @supports 或者CSS查询特性相关的知识点还不足够满足的话,建议你阅读下面的文章,深入的学习这方面的知识:

  • CSS3条件判断: @supports
  • 说说CSS中的 @supports
  • Conditional CSS
  • 在 CSS 中用特征查询
  • Conditional CSS using CSS feature queries
  • Using Feature Queries in CSS
  • How to use CSS Feature Queries
  • Basic grid layout with fallbacks using feature queries
  • Layout Design with CSS Grid &amp; Feature Queries
  • Feature Queries for CSS Grid fallbacks

案例:聊天框

现在我们有了一个漂亮的新闻提要(Newsfeed),接下来在前面的Newsfeed基础上增加一个小的聊天框,这个聊天框固定在屏幕的右下角。

Step7: 增加聊天框

我们需要一个消息列表和一个文本域字段,方便使用户输入消息。那么在 标签的后面增加这个聊天框所需要的HTML标签:

class="chat">

<div class="messages">

<ul>

<li><div class="message">Message 1div>li>

<li><div class="message">Message 2div>li>

<li><div class="message">Message 3div>li>

<li><div class="message">Message 4div>li>

<li><div class="message">Message 5div>li>

<li><div class="message">Message 6div>li>

<li><div class="message">Message 7div>li>

<li><div class="message">Message 8div>li>

<li><div class="message">Message 9div>li>

<li><div class="message">Message 10div>li>

ul>

div>

class="input">

div>

在没有给聊天增加任何样式的情况下,我们看到的效果是:

Step08:给聊天框增加样式

先给聊天框增加少量基本样式,让它看起来有点像聊天框的样子:

.chat {

background: #fff;

border: 10px solid #000;

bottom: 0;

font-size: 10px;

position: fixed;

right: 0;

width: 300px;

}

.messages {

border-bottom: 5px solid #000;

overflow: auto;

padding: 10px;

max-height: 300px;

}

.message {

background: #000;

border-radius: 5px;

color: #fff;

margin: 0 20% 10px 0;

padding: 10px;

}

.messages li:last-child .message {

margin-bottom: 0;

}

.input {

border: none;

display: block;

padding: 10px;

width: 100%;

}

效果看起来像下面这样:

Step09:滚动链接

现在页面上可以看到已经美化好的聊天框了,这个聊天框有一个可滚动的消息列表和一个文本输入框,而且位于前面创立子的Newsfeed上面(假如没有的话,你可以把你的浏览器缩小),如下:

五个最新的CSS特性以及如何用它们

看上去是不是不错。但是你有没有注意到,当你滚动聊天框中的信息列表究竟部的时候,会发生什么?感兴趣的话,亲身试一试。咱们做两个小测试,先滚动页面 body ,看看效果:

五个最新的CSS特性以及如何用它们

而后再聊天框的信息列表中滚动,一直滚动到最底端,滚不动为止,看看效果以是:

五个最新的CSS特性以及如何用它们

滚动Newsfeed,和我们想象的并没有差异;但滚动聊天框中的消息列表时,却不一样,滚动到消息列表末端时,可以看到页面 body 将开始滚动。这种效果被称为 滚动链接 ,即 Scroll Chaining

在我们这个示例中,这可能不是什么大问题,但在某些情况下,它可能就是一大问题了。比方Modal弹框,那就很有必要处理这样现象。

比较拙的处理方案就是给 body 增加 overflow:hidden ,但这有可能会影响我们的操作,甚至影响你浏览你的页面。但值得庆幸的是,CSS有一个新特性可以做得更为完美,体验更佳,而且用起来并不复杂,只要要一行代码就可,那就是CSS的 overscroll-behavior ,这个属性有三个可取值:

  • auto :其默认值。元素(容器)的滚动会传播给其祖先元素。有点相似JavaScript中的冒泡行为一样
  • contain :阻止滚动链接。滚动行为不会传播给其祖先元素,但会影响节点内的局部显示。例如,Android上的光辉效果或者iOS上的回弹效果。当使用户触摸滚动边界时会通知使用户。注意, overscroll-behavior:contain 在 html 元素上用,可以阻止导航滚动操作
  • none :和 contain 一样,但它也可以防止节点本身的滚动效果

overscroll-behavior 属性是 overscroll-behavior-x 和 overscroll-behavior-y 的简写,假如你只想控制其中一个方向的滚动行为,可以用其中的某一个属性。

回到我们的示例来,在 .messages 类中增加下面这行代码:

.messages {

overscroll-behavior-y: contain;

}

现在你再尝试一下,在聊天框中的消息列表中上下滚动。此时你再滚动到消息列表末端时,它不再会影响 body 的滚动了(页面的滚动):

五个最新的CSS特性以及如何用它们

假如你想在PWA中实现下拉刷新的效果,比方下拉时刷新Newsfeed,那么这个属性就非常方便。只要要在 body 或者 html 元素中增加 overscroll-behavior:contain 就可。

值得注意的是,这个属性还不是W3C标准,而是Web孵化器WICG的一个建议。不过,说不定哪一天,这个特性就进入到W3C工作组中,成为W3C的一个标准。

有关于这方面的更多详情,建议阅读下面几篇文章:

  • 滚动的特性
  • CSS overscroll-behavior
  • Take control of your scroll: customizing pull-to-refresh and overflow effects

Step10:折叠聊天框

目前,聊天框占据了相当大的空间,假如我们不与其交互的话,会有点分散使用户的注意力。辛运的是,我们可以使用CSS的选择器特性来处理这个问题。这也是CSS的另一新特性,再一次向大家展现了CSS的魔力。

首先调整一下现有的样式。默认情况下,我们希望聊天框是解决一个折叠状态,因而把 .message 的 max-height 值重置一下,在此设置为 0 ,并且把 padding 也重置为 0 。由于这个值刚恰好折叠了聊天框,而且又不影响其美观。为了让聊天框折叠和开展时有一个过渡的动画效果,借助 CSS的 transition 属性来实现。

.messages {

...

max-height: 0;

padding: 0;

transition: max-height 500ms;

}

效果看起来还不错,如下所示:

Step11:当聊天框得到焦点时,开展聊天框

现在我们的聊天框中的信息列表是看不到。由于我们前面把信息列表折叠起来了。现在我们要思考的是如何通过CSS来将其开展。这就会使用到CSS的另一新特性 —— :focus-within

有点相似于 :focus 伪类选择器一样,但是 :focus-within 与其不同之处是, 假如元素的任何后代元素得到焦点,它就会被匹配 。这就是这个属性特别之处,由于它与CSS通常的工作方式相反,通常我们只能根据元素的祖先来选择元素。

在我们这个示例中,当 .chat 区域内的任何内容得到焦点时,重置一下 .message 的 max-height 和 padding 值。请记住,一个元素必需接受键盘或者鼠标事件或者其余形式的输入,以便接收焦点。比方我们这个示例,点击 输入框就符合这个要求,可以达到我们想要的预期效果。

.chat:focus-within .messages {

max-height: 300px;

padding: 10px;

}

你现在可以尝试一下效果。点击 input 让其得到焦点,可以看到聊天框可以开展,反之聊天框又会折叠起来:

五个最新的CSS特性以及如何用它们

Step12:进一步突显 :focus-within 的魔力

假如仅仅实现聊天框的折叠和开展效果,到上一步其实已经完成了。但对于一位有追求的前台,总是在尝试很多极限性。回到我们的示例中来,假如PM跟你提了一个新需求,当文本输入框得到焦点之后,除了能开展聊天框之外,还希望聊天框底下的Newsfeed变得模糊。对于这样的一个效果,怎样来实现呢?

要实现这样的效果,其实并不复杂,假如你有做过 自己设置单选按钮或者复选框 (当然是纯CSS),你应该会想到处理方案。我们可以 用CSS选择器中的兄弟组合器 ~ ,即可以很容易的做到这一点。用 ~ 选择器有一个前提需要注意,聊天框 .chat 需要在Newsfeed( .container)前面(指的是HTML结构,事实上我们已经这样做了)。只有这样才能通过下面的方式让Newsfeed变得模糊:

.chat:focus-within ~ .container {

filter: blur(5px)

}

当然,这可能不是最佳的一个方案,但仅通过CSS的技术手段就能达到预期的效果,已经很酷了。感兴趣的话,自己可以体验一下:

五个最新的CSS特性以及如何用它们

注意,Newfeed增加了 filter 效果,这将会改变元素的层叠顺序,造成聊天框在Newsfeed下面。所以需要显式的 .chat 中增加 z-index 的值。比方这里设置了 z-index: 1001 。具体起因可以查阅@张鑫旭老师的《 深入了解CSS中的层叠上下文和层叠顺序 》一文。

探究 :placeholder-shown

五个最新的CSS特性以及如何用它们

首先要先分清楚, :placeholder-shown 和 ::placeholder 是不同的两个东东。神奇的是 :placholder-shown 是W3C标准规范的一个属性,而 ::placeholder 却不是。 ::placeholder-shown 依然会影响占位符文本的样式。

注意: :placeholder-shown 是一个伪类选择器(它是一个处于特定状态的元素); ::placeholder 是一个伪元素(一个在DOM中并不存在的可见元素)。

另外, :placeholder-shown 也是新的选择器之一(CSS Selectors Module Level 4新添加了很多种伪类选择器),它可以匹配任何显示占位符文本的输入。在我们的示例中,文本输入框( input )并没有任何占位符文本,所以先在HTML中的 input 元素中,增加 placeholder ,新添加占位符文本。

type="text" class="input" placeholder="Enter your message">

而后在 input 之后增加一个新的元素,使用来帮助使用户操作:

class="prompt">Press enter to send

现在给这个帮助信息 .prompt 增加少量样式,默认情况之它是被折叠起来了。

.prompt {

line-height: 2em;

max-height: 0;

overflow: hidden;

padding: 0 10px;

text-align: right;

transition: max-height 500ms;

}

仅从外观上看,似乎如同没多出什么,就是在文本框中多了一个占位符文本:

五个最新的CSS特性以及如何用它们

尽管没多大区别,但这为后续的效果已埋下了一个伏笔。接着往下看。

Step14:用提醒信息可见

此时提醒信息处于折叠状态,并不可见,我想大家也想到了,要怎样用 :placeholder-shown 让其可见?大多数浏览器会显示占位符文本,直到使用户在 input 中输入真的值。为了 提高使用户用表单的体验 ,假如 input 得到对应的焦点之后,占位符文本并不隐藏,还起着提醒作使用,是不是更有意思,也对使用户有更好的帮助,毕竟我们不希望使用户发送空的消息,所以我们可以将这种行为关联起来,只有在使用户输入值时才显示提醒信息(也就是 .prompt 开展可见)。

:placeholder-shown 表示的是占位文本符可见的状态,而提醒信息可见的时候,占位文本符不可见,也就是 input 有了一个真正的值。换句话来说,我们需要有一个 :placeholder-shown 的反转(占位文本符不可见),这个时候我们可以借助 :not() 选择器来帮我们做这样的反转。

.input:not(:placeholder-shown) + .prompt {

max-height: 2em;

}

将 max-height 设置为 font-size:10px 的两倍,这里用了 2em ,这个时候可以开展提信信息块。简单而有整洁。假如这个看似平凡的伪类选择器能过通过最终的规范,那么我们将会看到少量巧妙的运使用。来到这一步,效果变成:

亲身体验一下,你在 input 随意输入一点内容,哪怕是空格,也能看到提醒信息被展现出来了:

五个最新的CSS特性以及如何用它们

不论 :focus-within 还是 :placeholder-shown ,它们都是CSS选择器新添加加的伪类选择器,假如感兴趣,建议你花些时间对这些方面进行了一理解:

  • Focusing on Focus Styles
  • A CSS Approach to Trap Focus Inside of an Element
  • CSS :focus-within
  • CSS :focus-within via @w3cplus
  • :placeholder-shown
  • Visually validate an input field using CSS
  • Intriguing CSS Level 4 Selectors
  • The Future Generation of CSS Selectors: Level 4
  • 下一代选择器:CSS4
  • 即将推出的CSS4 Level 4 Selectors
  • CSS Level 4 Selectors to Watch Out For

Step15:让它充满生机

到目前为止,我们通过简单的HTML和少量CSS特性完成了一个带有聊天功能的新闻提要的基本架构,但是目前它是没有生命的,只是一个纯静态的东西。也就是说使用户并不有使用它做任何事情。这个案例包含了少量有趣的CSS新特性,但到现在为止不能修改DOM。假如想让这个案例更为生动,那么就需要借助少量JavaScript功能,以便使用户能通过聊天框增加消息。

首先,需要向 和类名 .messages 的子元素 ul 增加一个 ID ,以便JavaScript更好的获取到对应的元素。同时给 input 元素增加一个 required 属性,当使用户未输入任何信息的时候,表单可以自动较验。

    type="text" id="input" required ...

    而后创立一个名为 script.js 文件,并且放置在 之前。不过我们的案例是在Codepen上做相应的演示,所以无需考虑创立一个单的 .js 文件。

    Step16:增加少量JavaScript

    我们需要给 增加一个事件函数,当监听到键盘的 Enter 事件,获取到 input 的值(假如有效)并将其增加到消息列表的末尾,清理字段并滚动到消息的底部。

    // 获取相应的元素

    const input = document.getElementById('input');

    const messages = document.getElementById('messages');

    // 监听input的键盘事件

    input.addEventListener('keypress', (event) => {

    // 检查能否按下Enter键

    if (event.keyCode === 13) {

    // 检查字段能否有效

    if (input.validity.valid) {

    // 用该值创立DOM元素

    const message = createMessage(input.value);

    // 将新创立的DOM元素增加到消息列表

    messages.appendChild(message);

    // 清理输入框的值

    input.value = '';

    // 滚动到消息列表的底部

    messages.parentNode.scrollTop = messages.parentNode.scrollHeight;

    }

    }

    });

    // 将input的值转换为HTML的字符串

    function createMessage (value) {

    return stringToDom(`

  • class="message">${value}
  • `)

    }

    // 将字符串转换为真实的DOM

    function stringToDom (string) {

    const template = document.createElement('template');

    template.innerHTML = string.trim();

    return template.content.firstChild;

    }

    现在,当你在 input 中输入字段并按 Enter 键时,你将看到你输入的消息增加到消息列表的底部。

    五个最新的CSS特性以及如何用它们

    Step17:增加一引起额外的信息

    为了向大家演示最后一个CSS新特性 —— contain ,咱们需要做少量设计。我们将实现一个效果,在消息列表顶部的框中发送新消息的时间。当你将鼠标悬停在消息上时,就会有这个效果。

    首先,我们需要将这些信息增加到我们的新消息中。我们可以修改 createMessage 函数返回的值。

    function createMessage (value) {

    return stringToDom(`

  • ${value}

  • `);

    }

    你已经注意到了,在 message 中新添加加了一个类 message--mine 。并给这个类增加相应的样式:

    .message--mine {

    background: #ff2089;

    margin-left: 20%;

    margin-right: 0;

    }

    当你新输入内容,按下 Enter 键时,新添加加的消息列表对应的结构就变成像下图这样的:

    五个最新的CSS特性以及如何用它们

    显示时间戳

    我们的目的是将创立消息的时间戳显示在消息列表的顶部,我们需要这样做,以便即便在滚动消息列表时,这个时间戳也总是可见的。这里我们借助CSS的伪元从来做:

    .message--mine::after {

    content: attr(data-timestamp);

    }

    这个时候你所看到的效果是这样的:

    五个最新的CSS特性以及如何用它们

    这个效果并不是我们想要的。我们在样式上稍做修改,鼠标悬浮到新增的消息列表上时才能看到时间戳,而且这个时间戳固定在消息区域的顶部。

    .message--mine:hover::after {

    background: #000;

    color: #ff2089;

    content: attr(data-timestamp);

    left: 0;

    padding: 5px;

    position: fixed;

    top: 0;

    width: 100%;

    }

    这个效果现在变成这样了:

    五个最新的CSS特性以及如何用它们

    现在时间戳固定在页面的顶部,可以继续优化一下,在 .messages 中增加 position: relative 。

    但也不起作使用,那是由于固定定位是相对于 viewport 的,而不是相对于其祖先元素。那么这个时候,最后一个CSS新特性应该要出场了。

    Step19:探究Containment

    CSS Containment是一个令人兴奋的新命题。它有许多选项,可以限制浏览器的样式、布局和对特定元素的绘制。这在修改DOM时特别有使用。在浏览器中,哪怕是很小的变化都有可能造成浏览器重绘整个页面,这样的消费是很贵,即便浏览器努力为我们做了很多优化,页面的重绘还是对性能有肯定影响的。

    用CSS Containment,我们可以把页面的部分圈起来,而后说“这里发生了什么,只在这里做相应的事”。这也是另一种方法,可以保护元素不受外部的变化而受影响。

    五个最新的CSS特性以及如何用它们

    CSS的Containment是一个新属性,用关键字 contain ,它支持四个属性值:

    layout

    paint

    size

    style

    您还可以结合关键字,如 contain: layout paint ,这将仅适使用于一个元素的这些行为。但也包含支持两个额外的值:

    • contain: strict 意同 contain: layout style paint size
    • contain: content 意同 contain: layout style paint

    每个值都有点不透明,所以我建议你阅读规范并在开发者工具中用它们来查看实际发生的情况。

    layout 和 paint 是两个重要的值,由于它们在需要大量操作DOM时,对性能有肯定的优化。然而,在我们的演示中,我们可以利使用 contain: paint 我助我们进行时间戳定位。

    根据规范所形容,当用 paint 时,“ 元素作为一个包含绝对定位和固定定位后代的块 ”。这意味着,我们可以在 .chat 上设置 contain: paint ,这样一来, .chat 中元素的固定定位将基于 card 而不是 viewport 。你可以通过用 transform: translateZ(0) 取得相同的效果。

    尝试一下下,效果完美了:

    五个最新的CSS特性以及如何用它们

    CSS Containment是较新的特性,目前只在Chrome 52+版本可以看到。假如你想深入的理解这方面的知识,可以阅读一下下面的文章:

    • CSS Containment in Chrome 52译文

    总结

    到这里就结束了,我们对这五个新的CSS特性有了肯定的理解。其中大多数都是非常简单的,但对于CSS Containment而言还是较为复杂,建议花更多的时间去详细理解。尽管这是少量新特性,而且在部分浏览器中还未得到较好的支持,但这些新特终将有一天会来到你的身边,你可以在项目中用。今天花这么的篇幅,并且通过两个示例来阐述这五个特性,主要是向大家展现这五个特性有何功能,如何在实际项目中用。

    文章篇幅较长,感谢你花这么长的时间阅读完这篇文章。最后再次感谢 @Daniel Crisp 整理的 内容 和带来的 案例

  • 全部评论(0)
手机二维码手机访问领取大礼包
返回顶部