文:https://www.smashingmagazine.com/2019/07/margins-in-css/
译者:前端小智
为了保证的可读性,本文采用意译而非直译。
为了回馈读者,《大迁世界》不定期举行(每个月一到三次),现金抽奖活动,保底200,外加用户赞赏,希望你能成为大迁世界的小锦鲤,快来试试吧
当我们学习CSS时,我们大多数人学到的第一件事是CSS中盒子的各个部分的细节,这部分通过叫做 CSS盒、模型。“盒模型”中的元素之一是margin,即盒子周围的透明区域,它会将其他元素从盒子内容中推开。
CSS1中描述了 margin-top、margin-right、margin-bottom和margin-left属性,以及一次设置所有四个属性的简写 margin。
margin看起来是一个相当简单的事情,但是,在本文中,咱们将看一些在使用margin一些让人迷惑有有趣的事情。 特别是,margin之间如何相互作用,以及 margin 重叠效果。
想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!
CSS 盒模型
CSS 盒模型指的是一个盒子的各个部分——content、padding、border和margin,它们各自之前是如何布局及相互作用的, 如下所示:
盒子的的四个margin属性和maring缩写都在CSS1中定义。
CSS2.1规范有一个演示盒模型的插图,还定义了用来描述各种盒子的术语,其中包括 content box、填padding box、border box和 margin box。
现在有一个 Level 3 Box Model specification 的草案。这个规范引用了CSS2作为盒模型和margin的定义,因此我们将在本文的大部分内容中使用CSS2定义。
margin 重叠
CSS1 规范定义了margin,也定义了垂直 margin 重叠。如果考虑到在早期,CSS被用作文档格式语言,那么 margin 重叠是有意义的。 margin 重叠意味着,当一个有底部margin的标题后面跟着一个有顶部 margin 的段落时,它们之间就不会出现较大的空白。
当两个 margin 发生重叠时,它们将组合在一起,两个元素之间的空间取较大的一个。 较小的 margin 在较大的里面。
在以下情况下,margin 会重叠:
依次来看看这些场景。
相邻的兄弟姐妹
对 margin 重叠的最初描述是演示相邻兄弟姐妹之间的 margin 是如何重叠的。除了下面提到的情况之外,如果有两个元素在正常流中依次显示,那么第一个元素的底部 margin 将与下面元素的顶部 margin 一起重叠。
在下面示例中,有三个div元素。第一个 div 的顶部和底部的margin都是50px。第二个 div 的顶部和底部 margin 都是20px。第三个 div 的顶部和底部 margin 都是3em。前两个元素之间的 margin 是50px,因为较小的顶部 margin 与较大的底部 margin 相结合。第二个元素与第三个元素之间的 margin 是 3em,因为3em大于第二个元素底部margin 20px。
html
<div class="wrapper"> <div class="box example1"> margin-top: 50px; margin-bottom: 50px; </div> <div class="box example2"> margin-top: 20px; margin-bottom: 20px; </div> <div class="box example3"> margin-top: 3em; margin-bottom: 3em; </div> </div>
css
.wrapper { border: 5px dotted black; } .example1 { margin: 50px 0 50px 0; } .example2 { margin: 20px 0 20px 0; } .example3 { margin: 3em 0 3em 0; } body { font: 1.4em/1.3 "Gill Sans", "Gill Sans MT", Calibri, sans-serif; margin: 2em 3em; } .box { background-color: rgb(55,55,110); color: white; padding: 20px; border-radius: .5em; }
运行效果:
完全空盒子
如果一个盒子是空的,那么它的顶部和底部 margin 可能会相互重叠。在下面的示例中,class为empty的元素的顶部和底部 margin 各为50px,但是,第一项和第三项之间的 margin不是100px,而是50px。这是由于两个 margin 重叠造成的。如果向空盒子中放入内容就会阻止 margin 合并。
html
div class="wrapper"> <div class="box"> A box </div> <div class="box empty"></div> <div class="box"> Another box </div> </div>
css
.wrapper { border: 5px dotted black; } body { font: 1.4em/1.3 "Gill Sans", "Gill Sans MT", Calibri, sans-serif; margin: 2em 3em; } .box { background-color: rgb(55,55,110); color: white; border-radius: .5em; } .empty { margin: 50px 0 50px 0; }
运行效果:
父元素和第一个或最后一个子元素
margin 重叠让人猝不及防,因为它有时候不是很直观。在下面的示例中,有一个类名为 wrapper 的div,给这个div一个红色的outline,这样就可以看到它在哪里了。
这个div里面的三个子元素的 margin 都是50px。但是你会发现实际的效果是第一项和最后一项与父元素的的margin齐平,好像子元素和父元素之间没有50px的margin一样。
html
<div class="wrapper"> <div class="box"> Item 1 </div> <div class="box"> Item 2 </div> <div class="box"> Item 3 </div> </div>
css
.wrapper { outline: 1px solid red; } .box { margin: 50px; } body { font: 1.4em/1.3 "Gill Sans", "Gill Sans MT", Calibri, sans-serif; margin: 2em 3em; } .box { background-color: rgb(55,55,110); color: white; padding: 20px; border-radius: .5em; }
运行效果:
这是因为子节点上的margin会随着父节点上的任何一边的margin相互重叠,从而最终位于父节点的外部。如果使用DevTools检查第一个子元素,就可以看到这一点,显示的黄色区域就是是 margin。
仅块元素 margin 重叠
在CSS2中,只指定垂直方向的 margin 重叠,即元素的顶部和底部 margin。因此,上面的左右边距不会重叠。
值得注意的,margin 只在块的方向上重叠,比如段落之间。
阻止 margin 重叠
如果一个元素是绝对的定位,或者是浮动的,那么它的margin永远不会重叠。然而,假设你遇到了上面示例中的几种情况,那么如何才能阻止 margin 重叠呢?
例如,一个完全空的盒子,如果它有border或padding,它的上下 margin就不会重叠。在下面的例子中,给这个空盒子添加了1px的padding。现在这个空盒子的的上方和下方都有一个50px的 margin。
html
<div class="wrapper"> <div class="box"> A box </div> <div class="box empty"></div> <div class="box"> Another box </div> </div>
css
.wrapper { border: 5px dotted black; } body { font: 1.4em/1.3 "Gill Sans", "Gill Sans MT", Calibri, sans-serif; margin: 2em 3em; } .box { background-color: rgb(55,55,110); color: white; border-radius: .5em; } .empty { margin: 50px 0 50px 0; padding: 1px; }
运行效果:
这背后是有逻辑,如果盒子是完全空的,没有border或padding,它基本上是不可见的。 它可能是CMS中标记为空的段落元素。 如果你的CMS添加了多余的段落元素,你可能不希望它们在其他段落之间造成较大的空白,这时 margin 重叠就有一定的意义。
对于父元素和第一个或最后一个子元素 margin 重叠,如果我们向父级添加border,则子级上的margin会保留在内部。
... .wrapper { border: 5px dotted black; } ...
同样,这种行为也有一定的逻辑。如果出于语义目的而对元素进行包装,但这些元素不显示在屏幕上,那么你可能不希望它们在显示中引入大的 margin。当web主要是文本时,这很有意义。当我们使用元素来布局设计时,它的重叠行为就没有多大的意义了。
创建格式化上下文(BFC)
BFC(Block Formatting Context)格式化上下文,是Web页面中盒模型布局的CSS渲染模式,指一个独立的渲染区域或者说是一个隔离的独立容器。
BFC 可以阻止边距的重叠。 如果我们再看父元素和第一个或最后一个子元素的示例,可以在 wrapper 元素加上 display: flow-root就会创建一个新的BFC,从而阻止 margin 合并
... .wrapper { outline: 1px solid red; display: flow-root; } ...
display: flow-root 是CSS3新出来的一个属性,用来创建一个无副作用的 BFC。将overflow属性的值设为auto也会产生同样的效果,因为这也创建了一个新的BFC,尽管它也可能创建一些在某些场景中不需要的滚动条。
flex 和 grid 容器
flex 和 grid 容器为其子元素建立flex和grid格式化上下文,因此它们也能阻止 margin 的重叠。
还是以上面的例子为例,将 wrapper 改用 flex 布局:
... .wrapper { outline: 1px solid red; display: flex; flex-direction: column; } ...
网站 margin 策略
由于margin 会重叠,最好能找到一种一致的方法来处理网站的 margin。最简单的方法是只在元素的顶部或底部定义 margin。这样,就很少会遇到 margin 重叠的问题,因为有margin的边总是与没有margin的边相邻。
这个解决方案并不能解决你可能遇到的问题,因为子元素的margin会与父元素相互重叠。这个特定的问题往往不那么常见,但知道它为什么会发生可以帮助你想出一个解决方案。
对此,一个理想的解决方案是给元素设置 display: flow-root,但有的浏览器并不支持,可以使用overflow创建BFC、或将父元素设置成flex容器,当然还可以设置padding来解决。
百分比 margin
当你在CSS中使用百分比的时候,它必须是某个元素的百分比。使用百分比设置的 margin(或 padding)始终是父元素内联大小(水平写入模式下的宽度)的百分比。这意味着在使用百分比时,元素周围的padding大小都是相同的。
在下面的示例中,有一个200px 宽的 d当,里面是一个类名为 box 的div,它的 margin值为10%,也就是 20px (200*10%)。
html
<div class="wrapper"> <div class="box"> I have a margin of 10%. </div> </div>
css
* { box-sizing: border-box; } .wrapper { border: 5px dotted black; width: 200px; } .box { background-color: rgb(55,55,110); color: white; padding: 20px; border-radius: .5em; margin: 10%; } body { font: 1.4em/1.3 "Gill Sans", "Gill Sans MT", Calibri, sans-serif; margin: 2em 3em; }
我们在本文中一直在讨论垂直 margin ,然而,现代CSS倾向于以相对于流的方式而不是物理方式来考虑事情。因此,当我们讨论垂直边距时,我们实际上是在讨论块维度的边距。如果我们在水平写作模式下,这些 margin 将是顶部和底部,但在垂直写作模式下,这些 margin 将是右侧和左侧。
一旦使用逻辑的、流相关的方向,就更容易讨论块的开始和结束,而不是块的顶部和底部。为了简化这一过程,CSS引入了逻辑属性和值规范。这将流的相关属性映射到物理属性上。
还有两个新的快捷键,可以同时设置两个块或者两个内嵌块。
在下面示例中,使用了这些流相关关键字,然后更改了盒子的编写模式,你可以看到 margin 是如何遵循文本方向的:
html
<div class="wrapper horizontal-tb"> <div class="box"> A box with a horizontal-tb writing mode. </div> </div> <div class="wrapper vertical-rl"> <div class="box"> A box with a vertical-rl writing mode. </div> </div>
css
* { box-sizing: border-box; } .wrapper { border: 5px dotted black; inline-size: 200px; } .horizontal-tb { writing-mode: horizontal-tb; margin-bottom: 1em; } .vertical-rl { writing-mode: vertical-rl; } .box { background-color: rgb(55,55,110); color: white; padding: 20px; border-radius: .5em; margin-block-start: 30px; margin-block-end: 10px; margin-inline-start: 2em; margin-inline-end: 5%; } body { font: 1.4em/1.3 "Gill Sans", "Gill Sans MT", Calibri, sans-serif; margin: 2em 3em; }
需要了解更多,可以阅读有关MDN上的逻辑属性和值的更多信息。
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
交流
干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。
https://github.com/qq449245884/xiaozhi
我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!
关注公众号,后台回复福利,即可看到福利,你懂的。
山河依旧,网站、App 从此再无灰色、黑色情况!!!
梦中清醒,哦,又是一个阳光明媚的早上。
致敬英雄,市面上 App、网站等都已置灰。
缅怀的同时,突然冒出一个问题,怎么做到的?难不成一个个调整图片,调整对应的控件色值?
显然不应该。想来想去还不如直接调试一番,找找感觉。
Chrome 打开 B 站,直接打开开发者模式,html 根节点有个 class=“gray”,好奇点点看看有什么反映:
一个 class 搞定吗?抱着怀疑的心态找了掘金:
共同点,都是使用了 filter:grayscale。
filter CSS属性将模糊或颜色偏移等图形效果应用于元素。滤镜通常用于调整图像,背景和边框的渲染。
官方给出一个小例子:
找到对应将图像转为灰色图像属性:
俗话说得好,好记性不如烂笔头,自己亲自动手才是最实际的。
效果很明显,如果想让整个页面图片灰度发生变化,只需要按照前辈们的方案,直接在 html 设置 class 即可,方案采用掘金:
附上对应 CSS 样式:
.mourning {
-webkit-filter: grayscale(100%); /* 兼容 Chrome、Safari 浏览器 */
-moz-filter: grayscale(100%); /* 兼容 FireFox 火狐浏览器 */
-ms-filter: grayscale(100%); /* 兼容 IE 浏览器 */
-o-filter: grayscale(100%); /* 兼容 Opera 浏览器 */
filter: grayscale(100%);
filter: #808080;
}
哪有什么岁月静好,不过是有人替你负重前行。
心怀感恩。
最后,再次希望所有的网站再也不要有变成灰色、黑色的情况!!!
永远也不要有了!!!
/ Google研究院软件工程师,Tingbo Hou & Tyler Mullen
译者 / Alpha
技术审校:斗鱼前端专家,王兴伟
原文 /https://ai.googleblog.com/2020/10/background-features-in-google-meet.html
在人们的工作和生活中,视频会议变得越来越重要。我们可以通过增强隐私保护,或者添加有趣的视觉效果来改善视频体验,同时帮助人们将注意力集中在会议内容上。我们最近宣布的在Google Meet中模糊和替换背景的方法,就是为了实现这一目标而迈出的一小步。
我们利用机器学习(ML)来更好地突出参与者,从而忽略他们周围的背景环境。尽管其他的解决方案需要安装额外的软件,但Meet的功能是由尖端的Web ML技术提供支持的,这些技术是用MediaPipe构建的,可以直接在你的浏览器中工作——不需要额外的步骤。
开发这些功能,有一个关键目标,即它可以给几乎所有现代设备提供实时的浏览器内性能,通过XNNPACK和TFLite,我们将高效的设备上ML模型、基于WebGL的效果渲染,还有基于Web的ML推理结合起来,进而实现了这一目标。
背景模糊和背景替换,由网页端的 MediaPipe 提供支持。
网络Web ML方案概述
Meet中的新功能是与MediaPipe一起开发的,MediaPipe是谷歌的开源框架,用于为直播和流媒体提供跨平台的,可定制的ML解决方案,它还支持设备上实时性的手、虹膜和身体姿势追踪等ML解决方案。
任何设备上解决方案的核心需求,都是实现高性能。为了实现这一点,MediaPipe的Web工作流利用了WebAssembly,这是一种专为网络浏览器设计的底层二进制代码格式,可以提高计算繁重任务的速度。在运行时,浏览器将WebAssembly指令转换为本机代码,执行速度比传统JavaScript代码快很多。此外,Chrome84最近引入了对WebAssembly SIMD的支持,每条指令可以处理多个数据点,性能提升了2倍以上。
首先,我们的解决方案通过将用户,和他们的背景进行分割(稍后将详细介绍我们的分割模型),来处理每个视频帧,使用ML推理来计算出一个低分辨率的蒙版。或者,我们还可以进一步细化蒙版,以使其与图像边界对齐。然后通过WebGL2使用蒙版来渲染视频,实现背景的模糊或替换。
WebML Pipeline:所有计算繁重的操作都是用C++/OpenGL实现的,并通过WebAssembly在浏览器中运行。
在当前版本中,模型推理在客户端的CPU上执行,以实现低功耗和最大的设备覆盖范围。为了达到实时性能,我们设计了高效的ML模型,通过XNNPACK库加速推理,XNNPACK库是第一个专门为新的WebAssembly SIMD规范设计的推理引擎。在XNNPACK和SIMD的加速下,该分割模型可以在Web上以实时速度运行。
在MediaPipe灵活配置的支持下,背景模糊/替换解决方案可根据设备能力,调整其处理过程。在高端设备上,它运行完整的工作流,以提供最佳的视觉质量,而在低端设备上,通过使用轻量级的ML模型进行计算,并且绕过蒙版细化,它仍然可以保持较高的性能。
分割模型细分
设备上的机器学习模型必须是超轻量级的,以实现快速推理、低功耗和较小的下载大小。对于在浏览器中运行的模型,输入分辨率会极大地影响处理的每一帧所需的浮点运算(FLOP)的数量,由此也必须很小。我们将图像下采样,得到较小的尺寸,然后再将其提供给模型。从低分辨率图像中,尽可能精确地恢复分割蒙版,这增加了模型设计的挑战。
整个分割网络具有关于编码和解码的对称结构,而解码器块(浅绿色),也与编码块(浅蓝色)共享对称层结构。具体地说,在编码器和解码器模块中,都采用了应用有全局池化层技术的通道注意力机制,这有利于高效的CPU推理。
采用MobileNetV3编码器(浅蓝色)和对称解码器(浅绿色)的模型架构。
我们修改MobileNetV3-Small为编码器,经过网络结构搜索的优化,以最低的资源需求,获得最佳的性能。为了减少50%的模型尺寸,我们使用Float16量化技术将模型导出到TFLite,仅权重精度略有下降,但对质量没有明显的影响。得到的模型有193K参数,大小只有400KB。
效果渲染
分割完成后,我们使用OpenGL着色器进行视频处理和效果渲染,其中的挑战就是在不引入伪影的情况下进行高效渲染。在细化阶段,我们采用联合双边滤波器对低分辨率蒙版进行平滑处理
渲染效果时会减少瑕疵减少的渲染效果。左:联合双边过滤器平滑分段分割蒙版。中:可分离滤镜移除背景模糊中的光晕瑕疵。右:替换背景中的灯光包裹包装(light wrapping)。
模糊着色器通过与分割蒙版值成比例的方式,调整每个像素的模糊强度,来模拟波克(bokeh)效果,类似于光学中的混淆圆(CoC)。像素按其CoC半径加权,因此前景像素不会渗入背景。我们为加权模糊实现了可分离的过滤器,而不是流行的高斯金字塔,因为它去除了人周围的光晕伪影。为了提高效率,模糊以低分辨率执行,并以原始分辨率与输入帧混合
背景模糊示例
对于背景替换,我们采用了一种称为灯光包裹(Light wrapping)的合成技术,用于混合分割的人物和定制的背景图像。光线包裹允许背景光溢出到前景元素上,从而使合成更具沉浸感,这有助于柔化分割边缘。当前景和替换的背景之间,存在较大的对比度时,它还有助于最大限度地减少光晕伪影
背景替换示例
性能
为了优化不同设备的体验,我们提供多种输入尺寸(即当前版本中的256x144和160x96)的模型变体,根据可用的硬件资源自动选择最佳模型。
我们在两款常见设备上评估了模型推理和端到端传递的速度:搭载2.2 GHz 6核英特尔酷睿i7的MacBook Pro 2018和搭载英特尔赛扬N3060的宏碁Chromebook 11。对于720p的输入,MacBook Pro可以以120 FPS的速度,运行较高质量的模型,以70 FPS的速度运行端到端的传递途径;而Chromebook则以62 FPS的速度运行推理,使用较低质量的模型,端到端运行在33 FPS。
高端(MacBook Pro)和低端(Chromebook)笔记本电脑上的模型型号推断速度和端到端管线传递。
为了定量评估模型的精度,我们采用了目前流行的交集-并集(IOU)和边界F-度量。这两种型号都有不俗的表现,而且还是在这样一个轻量级网络的情况下
模型准确性的评估,通过 IOU 借条和边界 F-分数来衡量。
我们还为我们的分割模型发布了随附的模型卡,其中详细介绍了我们的公平性评估。我们的评估数据包含来自全球17个地理分区的图像,并附有肤色和性别的注释。我们的分析表明,该模型在不同地区、肤色和性别上的表现是一致的,只有很小的IOU指标偏差。
结论
我们推出了一个全新的浏览器端的机器学习解决方案,用于模糊和替换你在Google Meet中的背景。使用这个方案,机器学习模型和OpenGL着色器就可以在Web上高效运行。所开发的功能即使在低功耗设备上也能以低功耗实现实时性能
致谢:特别感谢Meet团队的成员和参与此项目的其他人员,特别是Sebastian Jansson,Rikard Lundmark,Stephan Reiter,Fabian Bergmark,Ben Wagner,Stefan Holmer,Dan Gunnarson,Stéphane Hulaud以及所有与我们一起从事技术工作的团队成员:Siargey Pisarchyk,Karthik Raveendran,Chris McClanahan, Marat Dukhan,Frank Barchard,Ming Guang Yong,Chuo-Ling Chang,Michael Hays,Camillo Lugaresi,Gregory Karpiak,Siarhei Kazakou,Matsvei Zhdanovich,Matthias Grundmann。
*请认真填写需求信息,我们会在24小时内与您取得联系。