虽然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创建三个卡片。
- Card 1
- Card 2
- Card 3
- Card 4
- Card 5
-
- Card A
- Card B
- Card C
- Card 6
- Card 7
- Card 8
- Card 9
- Card 10
在没有任何样式的情况之下,你看到的效果是这样的:
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%;
}
}效果如下:
Step03:解决布局问题如果你从未接触过Flexbox相关的知识,强烈建议你花点时间阅读这些文章。因为Flexbox发展到今天,已经开始取代float来布局,成为最主流的布局方式之一,特别是在移动端上的布局。
当你向下滚动列表时,你会发现.nested下的三个li(对应的是CardA ~ CardC)影响了整体的布局效果:
其实我们想要的,或者说理想状态下,所有的卡片按流的方式排列,但事实并未如此。造成这种现象的原因是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元素):
现在你看到的所有卡片都是有序的排列,但是尺寸不对:
可以通过在.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
尽管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的浏览器,你将看到的效果如下:
在不支持display:contents的浏览器,看到的效果又像下面这样:
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 & Feature Queries
Feature Queries for CSS Grid fallbacks
现在我们有了一个漂亮的新闻提要(Newsfeed),接下来在前面的Newsfeed基础上添加一个小的聊天框,这个聊天框固定在屏幕的右下角。
Step7: 添加聊天框我们需要一个消息列表和一个文本域字段,方便用户输入消息。那么在
标签的后面添加这个聊天框所需要的HTML标签:- Message 1
- Message 2
- Message 3
- Message 4
- Message 5
- Message 6
- Message 7
- Message 8
- Message 9
- Message 10
在没有给聊天添加任何样式的情况下,我们看到的效果是:
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上面(如果没有的话,你可以把你的浏览器缩小),如下:
看上去是不是不错。但是你有没有注意到,当你滚动聊天框中的信息列表到底部的时候,会发生什么?感兴趣的话,亲自试一试。咱们做两个小测试,先滚动页面body,看看效果:
然后再聊天框的信息列表中滚动,一直滚动到最底端,滚不动为止,看看效果以是:
滚动Newsfeed,和我们想象的并没有差异;但滚动聊天框中的消息列表时,却不一样,滚动到消息列表末端时,可以看到页面body将开始滚动。这种效果被称为滚动链接,即Scroll Chaining。
在我们这个示例中,这可能不是什么大问题,但在某些情况下,它可能就是一大问题了。比如Modal弹框,那就很有必要解决这样现象。
比较拙的解决方案就是给body添加overflow:hidden,但这有可能会影响我们的操作,甚至影响你浏览你的页面。但值得庆幸的是,CSS有一个新特性可以做得更为完美,体验更佳,而且使用起来并不复杂,只需要一行代码即可,那就是CSS的overscroll-behavior,这个属性有三个可取值:
auto:其默认值。元素(容器)的滚动会传播给其祖先元素。有点类似Javascript中的冒泡行为一样
contain:阻止滚动链接。滚动行为不会传播给其祖先元素,但会影响节点内的局部显示。例如,Android上的光辉效果或iOS上的回弹效果。当��
作者:大漠
原文链接:https://www.w3cplus.com/css/5-hot-new-css-features-and-how-to-use-them.html



