哔哩哔哩系统部网络团队
负责B站数据中心网络规划、设计、建设、运维与优化,为公司业务提供稳定且可靠的网络服务。整个团队专注于数据中心内网、骨干网络、负载均衡、传输网络、虚拟化网络以及国际化网络的落地和应用,并根据业务的发展需求不断迭代更新底层基础网络设施。
在设计任何网络结构时,网络的稳定性和扩展性是两个必然要考虑的因素。丢包、拥塞、扩容三大标准决定了网络质量的上限和下限。任何程度的网络质量波动都会对点直播视频业务的生产和消费造成最为直接的影响。基于B站始终把用户体验放在第一位的前提下,在设计网络前必须对网络的流量模型,业务对网络的要求做出充分调研。继而从设备选型、网络规划、技术应用、协议设计、生态演进等多维度做出最贴合当下B站客户需求的网络方案并落地实施。
随着视频化时代到来,承载业务的数据中心其规模也与日俱增,新增的数据中心所包含的服务器容量从几千台迅速攀升至数万台。传统的树形网络结构中,在网络结构和带宽容量方面,未曾考虑到数据中心内东西向流量的需求,大多是为了满足南北向流量的大带宽应用而设计,因此这种结构虽然能满足业务一时的应用场景。但是由于各层上下联带宽存在较高的收敛比现象,后期如果需要扩容带宽,就需要通过升级各网络元件,如扩容核心设备的业务板卡、Fabric等。
同时,在线、离线主机应用程序,比如AI、大数据计算集群,产生了显著的东西向流量。一些特定应用和场景(比如多活改造),需要集群间的大量数据复制。传统的树形结构在满足东西方向大带宽需求上捉襟见肘,要么组网成本太高,要么无法实现,因为整个组网受限于商用物理设备形态限制,比如设备端口密度等等。
B站的网络基础设施CAPEX(Capital Expenditure)在整体IT成本中占比显著。因此,技术团队通过优化个别网络单元的成本来改善这一现象。具体可以用以下两种实现方式:
随着网络设备数量增加,网元故障频次必然增多,缩小网络故障域是降低网络OPEX(Operational Expenditure)的一个重要指标。网络中容易产生广播和单播风暴,这会对网络稳定性和可靠性造成影响。如何高效运营管理网络,这是一个热门的话题。在网络设计之初,按全路由设计能缩小故障范围,将故障域设定在更小的网络范围中。在全路由设计时,尽量使用同一种路由协议(比如BGP协议),来简化设备控制面复杂度,从而降低网络崩溃的概率。
B站DCN V1.0方案中,接入层和核心层均采用堆叠组网方案,网关配置在Spine设备,整个网络处于一个大型的二层广播域。如图1:
图1 DCN V1.0结构
在堆叠方案中将两台接入交换机虚拟为一台,起到冗余备份的作用,服务器通过Bond接入交换机,提升接入层面网络的可靠性和稳定性。Spine层也是将两台核心网络设备通过堆叠虚拟为1台。堆叠带来的好处是设备控制面只有一个,两台交换机进行集中式配置,减少了频繁登录不同设备的操作时间,整体简化了网络设备管理成本;两台接入交换机的表项依靠堆叠心跳线进行同步。但在组网方案和后期运维中堆叠方案逐渐暴露了两个风险。
无论是哪个厂商的设备,都无法保证软件系统不存在BUG,一旦出现BUG就需要对设备软件升级补丁或软件版本。虽然有类似ISSU的技术可以实现不中断升级,但ISSU的适用范围仅限两个版本差距很小的情况,且在实践过程中各厂家无损升级技术复杂度高,升级风险较大,成功率低,会或多或少引入额外问题,导致升级过程中网络连通性异常。另外堆叠成员节点单独升级会影响控制面,影响网络稳定性。
交换机之间互联的堆叠线路出现故障或者异常时,将导致堆叠分裂,虽然不常见,但是在实际运行过程中仍会遇到,B站历史上就曾经出现过此类Case。产生的问题是分裂后,等同于网络中出现了两台配置完全相同的交换机,造成网络配置冲突,最终导致堆叠系统所承载的业务中断。
面对这个分裂风险,当然也有相应的解决办法,就是一旦系统检测到分裂情况,就会将除去堆叠口、管理接口以及管理员指定的例外端口之外的其他端口全部DOWN掉,来防止分裂后对网络造成影响。虽然这种方式规避了配置完全相同的两台交换机出现在网络里面,但代价也是显而易见的,业务恢复操作变得复杂,远程恢复操作变得极难。
基于以上两个风险点及其他堆叠组网带来的隐患,B站当前数据中心接入层组网堆叠技术已不再使用。
为了解决堆叠方案的问题,2019年初开始,团队开始对DCN网络结构进行重新设计。Leaf接入层采用M-LAG技术(跨设备链路聚合组)取代原来的堆叠方式,Spine层不再使用堆叠,每台设备独立运行,同时为了更好的冗余和提升带宽收敛比,在Spine层增加网络设备数量。Spine-Leaf层运行EBGP路由协议,破除大二层网络带来的广播风暴风险。DCN V2.0网络结构如下图2:
图2 DCN V2.0结构
M-LAG(Multichassis Link Aggregation Group)跨设备链路聚合组,是一种实现跨设备链路聚合的机制,让两台接入交换机以同一个状态和被接入的设备进行链路聚合协商,从而把链路可靠性从单板级提高到了设备级,组成双活系统。在被接入的设备看来,就如同和一台设备建立了链路聚合关系。相比DCN V1.0结构,V2.0结构有效解决了交换机软件版本升级难问题,两台接入交换机可以独立进行升级,保证有一台设备正常工作即可,对正在运行的业务几乎没有影响。同时接入层面做一些配置优化,如配置Monitor联动设备上下行端口,BGP路由协议配置优化等,相比V1.0时代网络稳定性和可扩展性提升了一个层级。但与此同时,DCN V2.0网络结构中还是存在以下问题:
基于以上M-LAG组网带来的相关问题,B站网络团队在DCN组网结构上继续探索,砥砺前行寻找最新DCN结构组网方案,由此B站DCN V3.0组网结构登场。
2020年底B站网络团队与国内外互联网头部企业、设备供应商等广泛交流与学习,开始调研新一代DCN盒式组网方案,并于2021年中旬完成DCN V3.0网络结构整套方案验证。且于2021Q3在新建数据中心落地应用3.0组网结构,经过半年的灰度验证,整个组网稳定运行,当前此组网方案已全量在B站数据中心部署;DCN 3.0网络结构如图3所示:
图3 DCN V3.0结构
DCN V3.0网络结构说明:
B站网络团队按稳定和高效原则设计网络结构。底层物理网络通过物理线路、硬件设备和网络技术,形成了一张稳定且可靠的DCN网络,为上层业务提供高效和快速的转发通道。基础网络下承机房基础设施、上接业务,需要解决业务需求变化快和基础网络升级难这一对永恒的矛盾点。未来基础网络会继续紧跟技术发展潮流,根据业务需求,探索新型网络结构,为B站业务提供更稳定、更高效及高扩展的网络服务。
[1] Facebook’s data center network: https://engineering.fb.com/2019/03/14/data-center-engineering/f16-minipack/
[2] A Border Gateway Protocol 4 (BGP-4). https://tools.ietf.org/html/rfc4271, 2006.
[3] BGP in the Data Center: https://www.oreilly.com/library/view/bgp-in-the/9781491983416/
[4] Use of BGP for routing in large-scale data centers. https://tools.ietf.org/html/rfc7938, 2016.
作者:SYS-网络团队
来源:微信公众号:哔哩哔哩技术
出处:https://mp.weixin.qq.com/s?__biz=Mzg3Njc0NTgwMg==&mid=2247487939&idx=1&sn=bcf362e7d5d6969dc02fb124cb8e37d3
022年3月24日,国家税务总局及时发布了《关于小规模纳税人免征增值税等征收管理事项的公告》(国家税务总局公告2022年第6号)公告,进一步明确了有关征管事项。
打开贵州省电子税务局网站
https://etax.guizhou.chinatax.gov.cn/xxmh/html/inde x.html,点击右上角登录,进入电子税务局登录页面,登录电子税务局。
1. 代开增值税发票
1.1 增值税小规模纳税人在电子税务局申请代开增值税专用发票时,系统会弹出提示:
您在2022 年4月1日以后取得的适用 3%征收率的应税销售收入,应当开具免税普通发票。若您有特殊情况,需要开具其他增值税发票,请按提示选择相应原因:
1.1.1 开具发票为2022年3月31日前发生纳税义务的业务
1.1.2. 前期已开具相应征收率发票,发生销售折让、中止或者退回等情形需要开具红字发票,或者开票有误需要重新开具
1.1.3. 因为实际经营业务需要,放弃享受免征增值税政策
如需继续开具增值税专用发票,纳税人需选择相应原因后才可继续办理。
1.2 自然人在电子税务局申请代开增值税普通发票时,系统已自动默认征收率为“免税”,纳税人可以自行选择修改,如果选择3%征收率,系统会弹出提示:
您在2022 年4月1日以后取得的适用3%征收率的应税销售收入,应当开具免税普通发票。若您有特殊情况,需要开具其他增值税发票,请按提示选择相应原因:
1.2.1. 开具发票为 2022 年3月31日前发生纳税义务的业务
1.2.2. 前期已开具相应征收率发票,发生销售折让、中止或者退回等情形需要开具红字发票,或者开票有误需要重新开具
1.2.3. 因为实际经营业务需要,放弃享受免征增值税政策,如需继续开具征收率为3%的增值税发票,纳税人需选择相应原因后才可继续办理。
2. 增值税及附加税(费)申报(小规模纳税人适用)
登录电子税务局后,依次点击【我要办税】→【税费申报及缴纳】→【按期应申报】,选择【增值税及附加税费申报表(小规模纳税人适用)】填写申报表,系统自动弹出提示: 自 2022 年 4 月 1 日至 2022 年 12 月 31 日,增值税小规模纳税人适用 3%征收率的应税销售收入,免征增值税;适用3%预征率的预缴增值税项目,暂停预缴增值税。
3. 增值税预缴申报
登录电子税务局后,依次点击【我要办税】→【税费申 报及缴纳】→【其他申报】,选择【增值税预缴申报表】填 写申报表,点击【下一步】,进入增值税预缴申报表,此时 如填写建筑服务一栏,系统在右上方自动弹出提示:自 2022年 4 月 1 日至 2022 年 12 月 31 日,增值税小规模纳税人适用 3%征收率的应税销售收入,免征增值税;适用 3%预征率的预缴增值税项目,暂停预缴增值税。
于2022年的CSS新特性,自己之前也有篇原创,CSS 的未来:Cascade Layers (CSS @layer),专门是在介绍@layer(级联层)的文章,而新的一年会有更多的CSS的新特性会出现在浏览器中。
今天分享一篇大漠老师的文章,主要内容是2022年哪些CSS特性将在浏览器中出现,以下是正文。
原文: https://www.w3cplus.com/css/what-is-new-css-in-2022.html
作者:大漠老师,请联系作者获得授权,非商业转载请注明出处。
虽然近些年 CSS 变化很快,但我认为 2021 年是 CSS 的元年。在即将过去的 2021 年,CSS 变化非常地大,其中新增了很多特性,比如 CSS 容器查询、CSS 父选择器、CSS 层叠控制规则、CSS 子网格等等。而且这些特性已经在个别,甚至是在大部分主流浏览器已经可以看到了。几大主流浏览器(Chrome、Firefox、Safari和Edge)还专注于修复浏览器兼容性痛点,让 Web 开发者的工作变得更轻松。
浏览器兼容性方面的修复,在 Web.dev 上发布了 2021 年的年中和年终报告,报告虽然简单,但我们可以看到浏览器厂商都在致于力磨平 CSS 特性在浏览器上的兼容性。为此,我们应该感谢他们的付出!
随着 2021 年的结束,让我们一起来看看 2022 年,我们可以期待哪些 CSS 特性将会在浏览器中出现。这了是我连续第三年整理有关于 CSS 新特性方面的文章了,另外两篇是(可自行搜索):
你即将看到是 2022 年的,你会发现这三篇文章提到的 CSS 特性有相同的,但他们也是有变化的。
@Bramus 前两天在Twitter 上发了一条信息,他整理了一份 2022 年的将会出现在浏览器的 CSS 清单:
有关于清单中列出的 CSS 相关介绍,可以阅读他的文章:《CSS In 2022》
这份清单中列出的 CSS 特性和 @Adam Argyle 分别在 2020 年 和 2021 年分享的 CSS 新特性列的出的清单差不多,不同的是,在2021年,有些CSS特性已经得到了浏览器的支持,有些已经进入了浏览器的实验属性列表清单,说不定2022年,你就能看到了!
有关于 @Adam Argyle 在 2020 和 2021 分享的 CSS 新特性,我也曾整理过一份,清单有些类似,但内容还是有差异,主要涵盖了一些我自己在 CSS 方面的认识和尝试,分别记录在《2020年CSS有哪些新特性》和《2021年你可能不知道的 CSS 特性》以及《应用于下一代Web的样式》
当然,如果你也是 CSS 的忠实爱好者,不断的在关注和推进 CSS 向前发展,那么你可能已经知道了,自 2019 年开始,每年年低都会有一份关于 CSS 发展状态相关的报告(2019、2020 和 2021)呈现给你。在每年的报告中,我们都可以看到一项关于”开发者期待的CSS特性“的统计:
在第一份报告出来的时候,我特意还花了一点时间去理解这份有关于 CSS的报告:《从9102年的CSS状态报告中看CSS特性的使用》,另外有幸运在 2020年年底和一些大学生一起聊了一个关于CSS状态和学习的话题!如果你对该话题感兴趣的话,可以阅读《CSS现状和如何学习》,文章中附有分享时录制的视频!
除此之外,W3C 的 CSS 工作小组,这两年也都出了 CSS 规范的重点报告,最新的是 2020年 和 2021年的。注意,W3C 关于 CSS 规范的重点报告并不是每年都有的!接下来,我将按着 @Bramus 的 《CSS In 2022》大纲往下梳理,其中会加入一些我自己对这方面的认识和见解。
我需要额外提出的是,接下来内容中提到的 CSS 特性只会涉及到那些全新的或仍然没有得到浏览器支持的(哪怕是实验性方面的)特性。但这并不代表着它们不值得期待,说不定在2022年你就能使用了!如果你对这方面感兴趣的话,请继续往下阅读!
在这节中提到的 CSS 特性是近些年来,Web 开发者一直期待的特性(或者说 CSS 中遗失的特性)。这些特性将在 2022 年的某个时候就得到了主流浏览器的支持。庆幸的是,有些特性已经在一个或多个主流浏览器中得到了支持,其他特性也将随着时间的推移也会随之而来。在 2022 年,学习或了解这些 CSS 特性,我想你会获得收益的!
有意思的是,CSSWG一直还维护着一份关于 CSS 设计中不完整的错语列表。感兴趣的可以点击这里阅读!
CSS 容器查询的特性一直以来都是 Web 设计师和开发者所期待的功能之一,从这几年的 CSS 发展状态的报告就可以看得出来。在没有容器查询之前,Web 开发者大多是依赖于 JavaScript 脚本来做判断,从而改变 UI 网格。虽然 CSS 容器查询存在于 CSS Containment Module 中有些年头,但一直未得到浏览器的支持。庆幸的是,在 2021 年,该特性得到了飞速的发展,时至今日,能在主流浏览器中看到 CSS 容器查询功能。这一切,都离不开 @TerribleMia ,是她为我们带来了这么好的 CSS 特性,并且一直在推进该特性向前发展。
@TerribleMia 除了设计 CSS 容器查询特性之外,还设计了 CSS 另外两个非常优秀的特性,那就是 CSS 的 @layer 和 @scoped 两个 @ (At rule)规则。详细的可以阅读《Miriam's CSS Sandbox》。
CSS 容器查询 @container 有点类似于 CSS 的媒体查询 @media ,只是它将根据元素的父容器(或祖先元素)的尺寸(size)或样式(style)来调整自己或自己后代元素的样式规则。在没有 CSS 容器查询,Web 开发者为了能在不同容器下调整 UI,大多都是依赖于媒体查询来做。也就是说,有了该特性之后,不需要再依赖视窗大小加添加类名的方式来调整UI了:
上图演示了,基于视窗的设计和基于容器的尺寸设计。可以说, CSS 容器查询的出现,除了改变 Web 开发者的开发方式之外,也将给 Web 设计带来变革命。这个论点在 2021 年的 GDS 大会上,@Una Kravets 在分享的 《The New Responsive: Web design in a compoent-driven world》主题(该主题视频可以在 YouTube上访问)中就提出这样的观点:
CSS 容器查询将会成为下一代响应式 Web 设计必不可少的特性之一。
有了 CSS 容器查询之后,我们就可以基于同一个组件,在不同尺寸下调整其UI,比如我们手淘 APP 顶部的搜索框效果:
上面效果的关键性代码如下:
.form__container {
container: inline-size;
}
.form {
display: grid;
align-items: center;
}
@container (min-width: 480px) {
.form {
grid-template-columns: min-content 1fr 200px;
grid-template-areas: "searchIcon searchInput button";
grid-template-rows: 88px;
gap: 10px;
}
}
@container (min-width: 768px) {
.form {
grid-template-columns: min-content 1fr min-content 200px;
grid-template-areas: "searchIcon searchInput cameraIcon button";
grid-template-rows: 88px;
gap: 10px;
}
}
详细代码可以点击这里阅读或获取。
CSS 容器查询在主流浏览器都能体验效果了,但需要开启其相关标记。如果你要运用于生产环境,可以考虑其相应的 Polyfill:
CSS容器查询特性绝对是众望所归的一个特性,在2022年更会全速向前!
有关于 CSS 容器查询更多的介绍可以移步阅读下面这些文章:
CSS 选择器是 CSS 中最基础的知识,也是必不可少的一部分,如果你没掌握好 CSS 选择器的话,那么你将会在 CSS 的世界中有那种”众里寻她千百度,蓦然回首,那人却在灯火阑珊处“的感觉!也正因此,CSS 选择器模块的迭代非常的快,现在已经进入 Level 4 版本了。在 Level 4 版本中,添加了多个伪类选择器,比如 :is() 、:where() 、:not() 和 :has() 等,而其中 :has() 选择器也是我们期待已久的一个选择器。@SaraSoueidan 在 Twitter 上引用 @Jen Simmons 的话说:
:has()选择器本质上就是CSS中期待已久的父选择器!
CSS 的 :has() 伪类选择器和 :not() 有点相似,也被称为结构性伪类选择器,在 CSS 的函数中也称之为 动态伪类函数。它允许你更精细地匹配元素:
:has() 伪类代表一个元素,如果作为参数传递的任何选择器至少与一个元素相匹配!
简单地说,元素只有在传递到 :has() 中的选择器至少匹配一个元素时才会被选中。这样理解起来似乎有点晕,我们来看个简单地示例:
figure img {
aspect-ratio: 21 / 9;
border: 5px solid #3f51b5;
}
figure:has(figcaption) img {
border: 5px solid #9c27b0;
}
上面示例中的 figure img 选择器大家应该都明白,表示选中 <figure> 元素中的所有 <img> 元素;而 figure:has(figcaption) img 选择器表示的是选中 包含了<figcaption> 元素的 <figure> 元素中的所有 <img> 元素。注意,这里:has() 中传了个 figcaption 选择器作为其参数。
<!-- 未匹配,因为 figure 没有包含 figcaption 元素 -->
<figure>
<img alt="" src="" />
</figure>
<!-- 会匹配,因为 figure 包含了 figcaption 元素 -->
<figure>
<figcaption></figcaption>
<img alt="" src="" />
</figure>
在支持的浏览器中你将看到的效果如下:
注意,Safari TP 137 是目前唯一一个默认支持 :has() 选择器的浏览器。
虽然说 :has() 被称为 CSS 的父选择器,但它的作用远不止于此。我们可以使用 :has() 和 :not() 等选择器相互结合,实现一些更复杂的效果。
就上面示例而言,当你在 <input type="email"> 输入的值是否有效时,表单不同状态下有不同的 UI 效果:
是不是很有意思。如果对 CSS 的 :has() 选择器感兴趣的话,还可以阅读《CSS 选择器:is() 和 :where() 与 :has() 有什么功能》一文。
更多关于选择器的内容:
CSS的级联顺序一直以来令众多开发者(特别是不熟悉CSS的开发者)感到困惑和头痛。CSS 新的 @ 规则 @layer 将可以让 CSS 的级联顺序按照你的意图来进行控制。简单地说,@layer 可以通过分层的方式,让你适当控制同源规则的级联排序。
比如下面这个示例:
/* 预设级联层的顺序,并且相邻级联层之间有逗号分隔 */
@layer setting, tool, generic, element, object, component, utilities;
@layer setting {
/* 附加到级联层 setting 中的 CSS */
}
@layer tool {
/* 附加到级联层 tool 中的 CSS */
}
@layer generic {
/* 附加到级联层 generic 中的 CSS */
}
@layer element {
/* 附加到级联层 element 中的 CSS */
}
@layer object {
/* 附加到级联层 object 中的 CSS */
}
@layer component {
/* 附加到级联层 component 中的 CSS */
}
@layer utilities {
/* 附加到级联层 utilities 中的 CSS */
}
上面只是演示了 @layer 规则的一个基本使用,而与 @layer 相关的知识和细节很多,这里就不深入展开了。要是你对该特性感兴趣的话,可以阅读《初探 CSS 的级联层(@layer)》一文。到目前为止,你们可以在 Chromium 99、Firefox 97 和 Safari TP 133 中查阅。注意,Safari 是最早支持该特性的浏览器。
有关于 CSS 中层叠更多的话题还可以阅读:
在 CSS Color Module Level 5 中新增了两个处理颜色的新函数,即 color-mix() 和 color-contrast() ,除此之外,还扩展了以前的颜色函数(比如 rgb() 、hsl() 、hwb() 、lab() 和 lch() 等)功能,可以在一个颜色的基础上改变某一个或某几个参数的值,从而得到一个新的颜色。比如上图部的 hsl() 函数,我们可以基于 --theme-primary 颜色(假设它的值为 hsl(274, 61%, 50%))改变其饱和度(从 50% 调整到 30% )从而得到一个新的颜色 hsl(274, 61%, 30%) 。这个特性,可以让我们在很容易的在 CSS 控制品牌色的色盘:
说个题外话,我最近的主要工作内容之一是将 Design Token 运用于前端生产的工程链路中,并且根据组件可变参数来自动生成不同风格的 UI 组件。那么,在未来的某一天,我就可以使用这种特性来为品牌色构建色盘。
新增的 color-mix() 和 color-contrast() 函数相对来说要更复杂一些。其中 color-mix() 函数有点类似于设计师调色一样:允许你在一个给定的颜色空间中混合两种颜色。
比如:
:root {
--theme-color: #ff0000;
}
.text-primary-dark {
color: color-mix(var(--theme-primary), black 10%);
}
.text-primary-darker {
color: color-mix(var(--theme-primary), black 20%);
}
color-contrast() 函数比较有意思,特别是在用于构建可访问性 Web 的时候特别有用。因为它可以帮助我们提高 Web 可访问性方面的能力(更好的控制文本色和背景色的对比度)。其主要作用是获取一个颜色值,并将其与其他颜色的列表进行比较,从列表中选择对比度最高的一个。
比如color-contrast(white vs red, white, green) ,分别会拿red 、white 和 green 与 white 进行对比,其中 green 和 white 对比度最高,最终会取 green 颜色:
你也还可以像这样使用:color-contrast(wheat vs tan, sienna, #d2691e to AA-large) 。它会将 wheat 与 tan 、sienna 和 #d2691e 进行对比,最终 sienna 颜色获胜,因为它与 wheat 颜色的对比度为 4.273 ,超过了 AA-large 的阈值。
Safari TP 124 已将 hwb()、lch() 、lab() 、color-mix() 和 color-contrast() 置为默认功能!
额外提一下,其中 hwb() 、lch() 和 lab() 所表达的颜色空间和 rgb() 还是有差异的,它们能将颜色表达的更细腻。就拿 hwb() 函数来说:
基于同一色相 0deg 描述的颜色:
有关于 CSS 颜色更多介绍,可以阅读:
”视窗单位“对于大家来说应该不会感到陌生了,特别是针对移动端开发的同学来说。因为移动端现在主流的适配方案之一就是采用视窗单位来处理的。但很多同学所知道的视窗单位应该只是 vw 、vh 、vmin 和 vmax :
视窗单位给移动端开发的适配是带来了极大的优势,但我想你在使用视窗单位的时候,应该也碰到了iOS上 Safari 的兼容性问题。因为,在iOS上的 Safari 有一个长期存在的,极其恼人的Bug,它不能与 vh 单位很好的配合。如果你将一个容器的高度设置为 100vh 时,会导致这个元素有点太高(会出现滚动条)。造成这种现象的主要原因是移动端上的 Safari 在计算 100vh 时忽略了它的部分用户界面。
如果你对 iOS 的 Safari上 100vh 的相关问题以及解决方案感兴趣的话,还可以移步阅读:
如果你不想花过多时间搞清楚这个问题的话,只是想快速解决这个问题,那可以将下面这段代码放到你的代码片段中:
body {
height: 100vh;
}
@supports (-webkit-touch-callout: none) {
body {
height: -webkit-fill-available;
}
}
虽然上面的代码可以解决 100vh 在 iOS Safari 引起的问题,但终究也只能说是一种 Hack 手段(事实上,CSS 中有很多黑魔法,这里不是主要聊这个的,顠过)。庆幸的是,CSS Values and Units Module Level 4 新增了几个与视窗有关系的新单位:
也有相应的单位用于 CSS 的逻辑属性中,比如 svi/svb 。有关于 这几个新增的视窗单位更详细的介绍,可以阅读 @Bramus 的 《The large, Small, and Dynamic Viewports》一文和@Arek Nawo 的 《Investigating the new CSS viewport relative units》一文。既然聊起了 CSS 的单位,那就再多花点篇幅和大家再多聊几个新增的 CSS 单位,也是蛮有意思的。先说 CSS Values and Units Module Level 4 新增的 lh 和 rlh 吧。
简单地回忆一下 CSS 中另一对单位:em 和 rem 。稍微了解 CSS 的同学都知道:- em 是相对于元素自已的 font-size 值计算(除元素自身的 font-size 取值为em时,元素自身的 font-size 值单位为 em时,其相对于其父元素的font-size值计算) - rem 是相对于HTML文档的根元素的 font-size 值计算,文档的根元素一般是指 <html> 元素
这两个新增的 lh 和 rlh 与 em 和 rem 非常的相似,只不过他们相对的是 line-height 的值计算:- lh 相对于元素自己的 line-height 计算 - rlh 相对于文档根元素(<html> )的 line-height 计算
你肯定会问,这样的单位有何用处呢?我想大家在还原 UI 设计稿的时候,肯定碰到了因为字体不同以及 line-height 值不同,让元素在视觉上看上去总是对不齐。那么,有了 lh 和 rlh 之后,事情会变得好一点。比如下图这样的场景:
以前上图这样的标记,常把宽高设置为 1em ,那么现在可以设置 1lh :
::marker {
width: 1lh;
height: 1lh;
}
到目前为止,仅 Safari TP 105 声称支持这两个相对单位 lh 和 rlh 。前面提到 CSS 容器查询特性一直以来是 Web 设计师和开发者一直期待的特性,并且在 2021 年得到快速发展。同时,和 CSS 容器查询特性一起出现的 ”*容器查询单位“ 也是很有意义和作用的。只不过,CSS 容器查询单位与 CSS 容器查询模块放在一起,并未和其他的 CSS 单位纳入一起。CSS 容器查询单位和视窗单位有点类似,不同的是 视窗单位相对于浏览器视窗尺寸计算,而容器查询单位相对于查询容器计算。使用容器查询长度单位的样式表可以更容易将一个组件从一个查询容器中移到另一个查询容器。CSS容器查询的单位主要有:
早其容器查询的单位定义的是 c*(比如,cw 、ch 、cmin 和 cmax )之类的,但其中有些单位会和 ch 单位产生冲突,因此,最终确定的容器查询单位是以 cq* 开始的。也就是上面所列的几个!
正如 @Miriam Suzanne(最初提出建议的人,也是规范的编辑)所分享的,这些 CSS 单位是Chromium中实验性容器查询支持的一部分。
更为有趣的是,@Ahmad Shadeed 在他的文章《CSS Container Query Units》一文中提出 qw 、qh 、qmin 和 qmax 以及他们对应的逻辑属性的单位qi 、qb 。
@Ahmad Shadeed 使用这些新的CSS单位运用在 font-size 上。可以用于容器查询的一坨 CSS 代码,在clamp() 比较函数中使用cqw 单位来取代。
早在2018年和大家聊改变滚动体验的时候就介绍过 overscroll-behavior 属性,我们可以通过该属性覆盖 overscroll 容器(指的是内容宽或高大于容器的宽或高,出现滚动条)时的默认行为。拿一个具体的实例来说,比如我们在构建弹框的时候,弹框内容过高也会出现滚动条,这个时候就会有两个滚动条出现,一个是弹框的,一个是body 的,其默认行为会像下面录屏的效果:
弹框无法滚动时,其底部的内容可以继续滚动。说实话,这样的默认滚动行为给用户的体验是极差的。更多的时候,我们希望弹框无法滚动时,其底部的滚动条也不能滚动。如下所示:
要实现上面视频的效果,我们就需要使用 overscroll-behavior 属性,并且将其值设置为 contain :
.modal {
overscroll-behavior-y: contain;
overflow-y: auto;
}
这个特性早在 Firefox 36 和 Chrome 63 就开始得到支持了,只不过Safari还未得到支持,不过 Safari 也在迎头赶上。
有关于 overscroll-behavior 的相关介绍,可以阅读 @Ahmad Shadeed 的《Prevent Scroll Chaining With Overscroll Behavior》一文。
在 CSS 中改善滚动体验,除了overscroll-behavior 属性之外,还有其他的一些属性,比如滚动捕捉 scroll-snap (Scroll Snap模块中的属性)、pull-to-refresh 等。CSS 除了要以控制滚动行为之外,也可以控制滚动条的样式。在今年以前,CSS 控制滚动条样式是使用浏览器的一些私有属性来搞定:
就在 2021 年 12 月 09日,W3C 发布了的 CSS Scrollbars Styling Module Level 1 规范,该规范提供了 scrollbar-color 和 scrollbar-width 两个属性,用来给滚动条设置样式。以后,我们要以使用它们来轻易完成滚动条样式的定制:
.section { scrollbar-color: #6969dd #e0e0e0; scrollbar-width: thin;}
我想大家都知道,使用 CSS 来美化滚动条样式主要原因之一是因为滚动条在不同的系统平台上显示有差异,外观不统一。除此之外,还有另一个问题。在 Web 上显示滚动条有一个副作用,那就是 内容的布局可能会根据滚动条的类型而改变。如果我们想防止由滚动条引起的一些不必要的布局变化,希望有相应的 CSS 属性来处理。以前没有,但现在有了。CSS Overflow Module Level 4 新增了一个 scrollbar-gutter 属性,有了这个属性,开发者就可以更好的控制滚动条,或者说解决因滚动条类型不同引起布局的差异变化。下图中展示了 scrollbar-gutter 的取值不同时的效果:
如果你对美化滚动条以及 scrollbar-gutter相关的知识感兴趣的话,可以阅读:
就 Web 布局 而言,虽然 Flexbox 很优秀了,但在二维布局中 Flexbox 还是有很大的局限性。在整个 Web 布局的技术体系中,只有 CSS Grid 才是唯一的二维布局。CSS Grd 布局在这几年中一直在不断的向前推进,已经得到了主流浏览器的支持。CSS Grid 能这么快向前推进,除了要感谢浏览器厂商的开发者团队之外,我个人认为还必须要感谢 @Jen Simmons 和 @Rachel Andrew。
@Jen Simmons 和 @Rachel Andrew 除了是 CSS Grid 规范的缔造者,还是 CSS Grid 布道者,她一直在社区努力推进 Grid 向前发展。
CSS Grid 已经有很多年了,该模块中的很多特性在主流浏览器中都得到了支持。在 2021 年,我自已陆续花了近半年的时间,对 CSS Grid 技术进行了系统的学习,并且整理了二十多篇有关于 CSS Grid 方面的系列教程,在这个系列中除了 CSS Grid 的理论知识之外,还有一些实战案例。要是你对这方面感兴趣的话,可以从《2022年不能再错过 CSS 网格布局了》一文中索引。这里着重把 CSS 网格中的子网格 subgrid 单独拿出来是原因的。子网格从定义到今天,经历了很多个版本的演变,而且在 CSS 社区也引起来很大的争议。在 CSS Grid 出现之后,就有人提出:
在 CSS 网格布局系统中应该要有一个子网格,即 subgrid
为此,最早定义的 subgrid 像 grid 和 inline-grid 一样,它只是 display 属性的一个值:
.subgrid {
display: subgrid;
}
不过没过多年,subgrid 就从 display 属性中移除了。使用嵌套网格来模拟子网格:.grid { display: grid; grid-template-columns: repeat(4, 1fr); }
.grid__item { display: grid; grid-template-columns: repeat(4, 1fr);}
简单地说,在需要嵌套网格的网格项目上再次使用 display: grid 以及 grid 相关的属性重新定义一个网格。只不过,这种方式也问题存在:很难将嵌套网格项目与父网格对齐。换句话说,父网格和嵌套网格是两个独立的网格,他们有着自己独立的网格参数。为了让子网格能继续父网格的相关参数,才又将 subgrid 再次引入到 CSS Grid 系统中,只不过,subgrid 不再是 display 的值,而是网格属性 grid-template-columns 或 grid-template-rows 属性的值。
.grid__container { display: grid; grid-template-columns: 1fr 2fr 3fr 2fr 1fr; grid-template-rows: 1fr 2fr 2fr 1fr; gap: 1rem; } .grid__container--subgrid { grid-column: 2 / 5; grid-row: 2 / 4; } .grid__container--subgrid { display: inherit; grid-template-columns: subgrid; grid-template-rows: subgrid; }
正如上图所示,这就是subgrid的作用:通过设置grid-template-columns或grid-template-rows为subgrid,它将与父网格对齐。真正的子网格可以使用父网格的相关参数。简单地说,使用该特性,可以轻易实现像下图这样的卡片布局:
还有一段时间,也有另一种建议,那就是使用 display: contents 来替代 subgrid 。而到今天为止,在网格布局系统中,嵌套网格、子网格和 display: contents 模拟的子网格都同时存在。他们都有着自己的特性。这里就不花过多时间阐述了。subgrid已成为 CSS Grid 模块中不可或缺的一个特性,直到今天为止(2012年的最后一天),也仅 Firefox 浏览器支持。不过,Chrome 已进入 WIP 阶段,我想 2022 年上半年,你就能在 Chrome 浏览器体验 subgrid 的效果。
既然提到 CSS Grid,那就顺嘴说一下 CSS 的 gap 属性吧。该属性不只是 Grid 布局独有的,在 CSS Flexbox 、Grid 和多列布局中都有 gap 属性。在布局中,在某些场景中,给相邻元素之间设置间距要比 margin 容易地多。
从 @Jen Simmons 发的推特消息中可以获知,Safari 14.1 开始也支持 Flexbox 中的 gap 属性。我自测了一下,Grid中的 gap 也得到支持了。也不是说,现在主流浏览器都已支持 gap 属性了:
Web 中有很多控件的 UI 效果是跟随系统走的。比如表单中的一些控件,比如常用的输入框(<input>)、单选按钮,复选框,进度条等。
以往,为了在 UI 的风格上能满足设计师的需求,即 所以平台上使用风格一致的UI效果。为此,Web 开发者需要增加额外的开发工作量,采用自定义表单控件的方式来让 UI 网格统一。为了让开发者能更好的满足设计师的需求,并且快速让各种平台统一 UI 网格, CSS Basic User Interface Module Level 4 新增了 accent-color 属性,可以很轻易的控制 Web 控件 (Widget Accent) UI:
:root { accent-color: deeppink; } @media (prefers-color-scheme: dark) { :root { accent-color: hsl(328 100% 65%); }}
既然提到 Web 表单中的控件,那就给大家提两个有关于 `` 元素的属性。因为这两个属性能给你的用户带来更好的体验,特别是在操作表单的时候。除了给 <input> 元素的 type 指定不同值时,可以提供不同键盘类型之外,还可以使用 inputmode 属性:
inputmode 可以唤起不同类型的软键盘,另一个改善用户体验的是给 <input> 元素的 enterkeyhint 属性设置不同的值,可以改变软键中的 Enter 键的类型的操作行为:
上面提到的,不管是 CSS 还是 HTML 的属性,都是用来改变用户体验的。再提一个和 HTML相关的属性。
自Safari 15 开始,我们在 HTML 的 <meta> 标签为 theme-color 设置颜色,让浏览器自身的 UI 颜色有让开发者来控制:
特别声明,这里的 theme-color 不是 CSS 属性,他是 HTML 的 <meta> 元素的 name 的一个值,结合 content 和 media 能轻易控制系统级的颜色。
似乎跑题了!我们要聊的是 2022 年的 CSS !嗯!那我们继续回到 CSS 的世界中来。
CSS 媒体查询 @media 已不是什么新特性了(除了新增的一些用户偏好的条件设置)。但今天要提出的是他的语法规则的写法。先上一张图吧:
以往在 @media 或者在 @container 规则中写判断条件时使用 min-width 和 max-width 较多,不知道大家是否和我一样有这样的感觉,使用 min-width 和 max-width 很多时候傻傻分不清楚他们的范围。为此,我总是喜欢使用下图来做判断:
自 CSS Media Queries Level 4 开始,我们可以使用较为熟悉的数学表达式了,在媒体条件中使用 > 、>= 、< 或 <= 等数学表达式:
上图中使用 @media 语法表达的话,像下面这样:
/* Old Way */
@media (max-width: 768px) {
…
}
@media (min-width: 375px) {
…
}
@media (min-width: 375px) and (max-width: 768px) {
...
}
/* New Way */
@media (width <=768px) {
…
}
@media (width >=375px) {
…
}
@media (375px <=width <=768px) {
...
}
同样的,数学比较运算符表达式也同样可以运用于 @container 容器查询的条件判断中。
如果你对媒体查询方面的知识感兴趣的话,还可以阅读:
F-mods 是 Font Metrics Override Descriptors(字体度量覆盖描述符)的简称。它对应着 CSS Fonts Module Level 4 规范中的 @font-face 部分的第十一小节,即 默认的字体度量覆盖。简单地说,在 @font-face 规则中新增了 ascent-override、descent-override、line-gap-override 和 advance-override 等属性:
@font-face { font-family: 'Arial' src: local('Arial'); --unitsPerEm: 1000; --lineGap: 10; --descender: -237; --ascender: 1041; --advanceWidthMax: 815; ascent-override: calc(var(--ascender) / var(--unitsPerEm) * 100%); descent-override: calc(var(--descender) / var(--unitsPerEm) * 100%); line-gap-override: calc(var(--lineGap) / var(--unitsPerEm) * 100%); advance-override: calc(var(--advanceWidthMax) / var(--unitsPerEm)); }
其中 advance-override 还未进入 W3C 规范,目前还仅处于提案中;而 ascent-override、descent-override 和 line-gap-override 属性目前已在 Chromium 87+ 和 Firefox 89+ 中实现!
这四个描述符的组合可以让我们告诉浏览器在下载 Web Fonts 之前字符占用多少空间,来覆盖回退字体(系统字体)的布局,使其与 Web Fonts 相匹配。简单地说:这四个描述符可以让你的系统字体更接近 Web Fonts!其中 ascent-override、descent-override 和 line-gap-override 描述符使我们 能够完全消除垂直布局的偏移,因为这三个描述符都会影响行高。在 CSS Fonts Module Level 5 规范中又为 @font-face 规则添加了几个新属性。比如,用来覆盖字体上标(sup)和下标(sub)的 superscript-position-override、subscript-position-override、superscript-size-override 和 subscript-size-override 描述符。虽然这几个属性还没有得到任何浏览器的支持,但对于 Web 开发者而言,这是希望。
除此之外,还新增了 size-adjust 描述符,它允许我们调整字形的比例系数(百分比)。该描述符取代了前面提到的 advance-override描述符。正如 @Addy Osmani在他自己推特上,是这样描述 size-adjust:
size-adjust 已经得到了 Chromium 92+ 和 Firefox 89+ 的支持。
说到 @font-face 那就有必要提到大家也一直期待的另一个 CSS 特性,那就是 leading-trim:
leading-trim 其主要作用就是用来改变文本布局。
在铅印刷术中,为了让铅字块(排成行)之间有一定的间距,排字工人会在行与行之间垫一些铅条,让阅读变得更舒服一些。在那个时代,锅条一般都放置在铅块下方。同样的,在Web排版上也有铅条的身影,只不过他分面上下两个部分。在CSS中引入该特性,它的工作原理就像一个文本框剪切刀。去掉文本框上下之间多余的空间(这个空间其实就是铅条高度的一半):
h1 { text-edge: cap alphabetic; leading-trim: both; }
示例中用到了text-edge 属性,简单地用下图来描述其作用:
开发 Web 时,对于排版方面是较为复杂的,涉及到的CSS知识也较多,如果你感兴趣的话,可以阅读下面这些文章:
这个和前面提到的 CSS 媒体查询有点类似。不是 CSS 的新特性,在 CSS Transform Level 2 规范中把以前用到 transform 属性的 rotate() 、scale() 、translate() 函数变成独立的 CSS 属性。而且它们都已经成为主流浏览器的实验属性,能在浏览器中体验他们。
element {
scale: 2;
rotate: 30deg;
translate: -50% -50%;
}
平移(translate)、旋转(rotate)和缩放(scale)属性允许开发者独立地指定简单的变换,其方式与典型的用户界面使用方式一致,而不必记住变换中的顺序,使transform()、rotate()和scale()的动作保持独立并在屏幕坐标中发挥作用。它们被应用的顺序是,首先是平移,然后是旋转,然后是缩放,而不是你定义它们的顺序。有了独立的变换属性,这也意味着我们可以对它们分别进行动画和过渡。
@keyframes individual {
50% {
translate: 0 50%;
}
75% {
scale: 1;
}
}
element {
transition: rotate 200ms ease-in-out, scale 500ms linear;
}
element:hover {
scale: 2;
rotate: -3deg;
}
有关于这方面更详细的介绍可以阅读:
接下来提到的 CSS 特性只是部分浏览器的实验性功能,不会得到大多数浏览器的支持,或者可能只有在相应的浏览器中开启了实验性功能标记才能看到效果。这些特性在 2022 年,甚至是再往后一两年都有可能得不到所有主流浏览器的支持。除了不会得到浏览器支持,而且规范都有可能会变更。说不定还会从 CSS 中移除!
上图看上去很熟,对吧!但它不是 SCSS 中的嵌套,是原生 CSS 中的嵌套。在 CSS 方面这算是一个突破性的补充,也算是继续 CSS 自定义属性(CSS 变量)的又补充。以往这样的规则,只能在 CSS 的处理器中运行。在 CSS 的嵌套模块中,我们可以使用 & 和 @nest 规则在一个样式规则块中嵌套另一个样式规则块:
table.colortable { & td { text-align: center; &.c { text-transform: uppercase } &:first-child, &:first-child + td { border: 1px solid black } } & th { text-align: center; background: black; color: white; } @nest footer & { font-size: 0.8em; }}
有关于 CSS 的原生嵌套更多的介绍,可以阅读《图解CSS:CSS的嵌套》一文。
CSS Cascading and Inheritance Level 5 中引入了 @layer 规则,将在 Level 6 中会引入另一个规则 @scope 。这是一种将样式范围扩大到DOM树的一种用法。
<!-- HTML -->
<div class="dark-theme">
<a href="#">plum</a>
<div class="light-theme">
<a href="#">also plum???</a>
</div>
</div>
/* 当.light-theme和.dark-theme被嵌套时,你可能不会得到预期的结果 */
.light-theme a {
color: purple;
}
.dark-theme a {
color: plum;
}
/* 通过范围划分,我们可以解决这个问题,因为a元素的样式将由其最近的范围来确定 */
@scope (.light-scheme) {
a {
color: darkmagenta;
}
}
@scope (.dark-scheme) {
a {
color: plum;
}
}
@when ... @else 是 CSS Conditional Rules Module Level 5 新增的特性,他们可以分开来单独使用,也可以组合在一起使用。
@when media(width >=400px) and media(pointer: fine) and supports(display: flex) {
/* A */
} @else supports(caret-color: pink) and supports(background: double-rainbow()) {
/* B */
} @else {
/* C */
}
@Stefan Judis 将这个CSS 特性(@when ... @else)有前面提到的 CSS特性,即 CSS 容器查询 和 媒体查询的数学运算表达式组合在一起,重新设计了 @Ahmad Shadeed 的 《Conditional Border Radius In CSS》文章中提到的有条件设置圆角:
@Stefan Judis 重新设计的方案:
有关于有条件设置圆角半径除了这里提到的方案,其实还有其他的方案,你要是想一探究竟的话,可以阅读前几天刚整理的《CSS 中的条件圆角技巧》一文。
这里所说的滚动与动画指 Scroll-linked Animations 模块中提供的 @scroll-timeline规则和 animation-timeline 属性。你可以将 CSS 动画与一个滚动容器的滚动偏移量关联起来。当你向上或向下滚动一个容器时,链接的动画将相应的前进或后退。
使用 @scroll-timeline 规则和 animation-timeline 构建类似上面的效果,要以按下面三步来走:
/* (1) Define Keyframes */
@keyframes adjust-progressbar {
from {
transform: scaleX(0);
}
to {
transform: scaleX(1);
}
}
/* (2) Define a ScrollTimeline */
@scroll-timeline scroll-in-document {
source: auto;
orientation: block;
scroll-offsets: 0, 100%;
}
/* (3) Attach the Animation + set the ScrollTimeline as the driver for the Animation */
#progressbar {
animation: 1s linear forwards adjust-progressbar;
animation-timeline: scroll-in-document;
}
有关于这方面更详细的介绍,可以阅读 @Bramus 提供的系列教程:
@property 是用来注册一个变量的,该变量是一个 CSS Houdini 中的变量,但它的使用和 CSS 中的自定义属性(CSS变量)是一样的,不同的是注册方式:
// Chrome 78+
// 需要在 JavaScript脚本中注册
CSS.registerProperty({
'name': '--custom-property-name',
'syntax': '<color>',
'initialValue': 'black',
'inherits': false
})
// Chrome 85+
// 在CSS文件中注册
@property --custom-property-name {
'syntax': '<color>',
'initialValue': 'black',
'inherits': false
}
他的最大特色之一就是可以指定已注册的 CSS 变量的类型、初始值,是否可继承:
虽然它的使用方式和 CSS 的自定义属性相似,但它要更强大,特别是在动效方面的使用,能增强 CSS 的动效能力,甚至实现一些以前 CSS 无法实现的动效。比如
@property --milliseconds {
syntax: '<integer>';
initial-value: 0;
inherits: false;
}
.counter {
counter-reset: ms var(--milliseconds);
animation: count 1s steps(100) infinite;
}
@keyframes count {
to {
--milliseconds: 100;
}
}
把它和 CSS Houdini 的 Paint API 结合起来,可做的事情更多:
更多这方向的效果可以在 houdini.how 网站上查阅:
CSS Houdini 中的 @property 和 Paint API 是对现在 CSS 能力的扩展,如果你对这方面感兴趣的话,可以阅读:
瀑布流是 Web 中经典布局之一。到目前为止依旧是 JavaScript 实现的瀑布流布局为主要技术方案,虽然使用 CSS 技术在一定条件之下可以完成瀑布流布局,但其局限性也较大。在 CSS Grid 最新模块中提供了原生的 CSS 瀑布流布局方案:
.masonry {
display: grid; gap: 20px;
grid: masonry / repeat(auto-fill, minmax(250px, 1fr));
}
但一直以来他还只是 Firefox 中的一个实验属性,还没有看到其他浏览器有支持,但我期望在 2022 年的某一天能在主流浏览器上都能看到 CSS Grid 实现瀑布流的布局的效果。
上面列出的一些 CSS 新特性(也有新语法),具体有哪些新特性能在 2022 年中出现在浏览器中,还不得而知。上面的提到的一些特性其实已经在一个或多个浏览器中能体验了。感兴趣的可以自己尝试一下。另外要特别提出的是,上面列的 CSS 属性清单来自于社区有同行业专家以及我自己的一些积累和见解,如果有不对之处,欢迎一起探讨。如果所列清单有遗漏,也欢迎大家分享出来。最后,希望上面的内容能帮助大家了解 CSS 的一些新东西,打开一些未知领域!谢谢!(^_^)
*请认真填写需求信息,我们会在24小时内与您取得联系。