box-shadow参数学习及渲染过程研究

news2024/9/22 1:45:48

参数定义

CSS 的 box-shadow 属性用于在元素的框架周围添加阴影效果。它可以接受多个由逗号分隔的阴影效果,每个阴影效果由以下几部分组成:

  • h-offset:水平阴影的位置。正值将阴影向右移动,负值将阴影向左移动。
  • v-offset:垂直阴影的位置。正值将阴影向下移动,负值将阴影向上移动。
  • blur:阴影的模糊距离。值越大,阴影边缘越模糊。如果省略,值为0,即阴影将尖锐清晰。
  • spread:阴影的大小。正值会增加阴影的扩展范围,负值会减小阴影的扩展范围。如果省略,值为0。
  • color:阴影的颜色。如果省略,值为 black。
  • inset:如果指定,阴影将在元素内部(即内阴影)。默认情况下,阴影在元素外部(即外阴影)。

使用示例

以下是一个 box-shadow 的示例:

.box {
  box-shadow: 10px 5px 5px black;
}

在这个示例中,阴影向右移动10px,向下移动5px,模糊距离为5px,颜色为黑色。
其阴影效果如下图所示
在这里插入图片描述
你也可以指定多个阴影,如下所示:

.box {
  box-shadow: 3px 3px 5px #000, -1px -1px 5px red;
}

在这个示例中,定义了两段阴影,一个向下3px,向右3px的黑色阴影;一个向左1px,向上1px的红色阴影。其显示阴影效果如下:
在这里插入图片描述
以上阴影都是向外扩散的外阴影,加上inset属性后,阴影向内扩散。

box-shadow: 3px 3px 5px #000, -1px -1px 5px red inset;

其效果如下:
在这里插入图片描述
在 CSS 的 box-shadow 属性中,除了blur和spread,其他几个参数应该都很容易理解。这里重点研究下blur和spread参数。blur 和 spread 参数分别控制阴影的模糊程度和大小。

  1. blur:这个值定义了阴影的模糊程度。它的值是一个长度,表示模糊半径,即从阴影的边缘开始向外或向内延伸的距离。blur 的值越大,阴影的边缘就越模糊,阴影的扩散面积也就越大。如果 blur 的值为 0,那么阴影就是一个固定大小的矩形,没有模糊效果。

  2. spread:这个值定义了阴影的大小。它的值也是一个长度,表示阴影的扩展范围。正值会增加阴影的扩展范围,负值会减小阴影的扩展范围。如果 spread 的值为 0,那么阴影的大小就等于元素的大小。

以下是一个示例:

.box {
  box-shadow: 10px 10px 5px 3px rgba(0,0,0,0.75);
}

在这个示例中,阴影的模糊半径是 5px,扩展范围是 3px。这意味着阴影从边缘开始向外延伸 5px,过渡到完全透明,同时阴影的大小比元素的大小大 3px。
在这里插入图片描述
从实际展示的效果来看,这俩参数都影响了阴影的大小。但是观察实际的绘制过程,发现blur并不影响阴影矩形的大小,而spread是会实际影响阴影矩形的大小的。为什么这么说,下面可以通过Chrome的devtools中的layers来具体看下实际的绘制过程。

paint profiler

在Chrome中,可以通过"开发者工具"中的"Layers"标签来可视化页面的分层情况,并查看每个图层的clipRect。
具体步骤如下:
在Chrome中任意位置右键点击,选择"检查";
进入到开发者工具后,选择"Layers"标签;
在Layer页面,可以看到每个图层的平移、旋转、复位操作按钮,以及clipRect属性。

在 Google Chrome 开发者工具的 Paint Profiler 中,时间的顺序是由上至下的。也就是说,最早发生的绘制操作在顶部,最后发生的绘制操作在底部。

Paint Profiler 提供了一个详细的视图,显示了浏览器在绘制页面时的每一步操作。这可以帮助你理解页面的渲染过程,以及可能导致性能问题的绘制操作。

在 Paint Profiler 中,每一行代表一个绘制命令,例如填充矩形、绘制文本等。每个命令都有一个颜色条,表示该命令的执行时间。颜色条越长,执行时间就越长。

你可以点击每一行来查看该命令的详细信息,包括命令类型、参数、执行时间等。你还可以使用工具栏上的按钮来放大、缩小、选择和导航视图。

绘制过程

blur参数

不设偏移,也不设spread,查看blur半径对渲染的影响。

.box-shadow {
     position: fixed;
     left: 200px;
     top: 200px;
     width: 100px;
     height: 100px;
     background: yellow;
     box-shadow: 0 0 100px 0 red;
 }

一下是对应的paint profiler调用过程:
在这里插入图片描述

查看profiler,可以发现主要调用了以下4个方法。

drawPaint(paint)	//绘制底部白色画板
translate(150, 150)	//blur属性会影响这个偏移量
clipRect(1,1,99,99, "kDifference_Op",false) // 做差值区域裁剪
drawRect(0,0,100,100, paint) //red 绘制红色阴影矩形
drawRect(0,0,100, 100, paint)	//yellow	//绘制黄色区域

以上几个调用的方法,熟悉canvas的从命名大致能理解是用来干啥的,这里不具体研究每个方法。这些方法是Skia提供的,Skia 是一个开源的 2D 图形处理库,用于Chrome的图形引擎。有兴趣的可以去看Skia的文档,后面会给出具体的链接(估计是需要翻墙的)。
在这里插入图片描述

从绘制阴影矩形的参数可知,绘制的阴影矩形面积和实际的元素尺寸是一样的,都是100px,blur属性不影响阴影矩形的面积。为了有所对比,我们改变一下blur,将blur值设为原来的一般50px,再查看下绘制过程中发生了哪些变化。

.box-shadow {
   position: fixed;
    left: 200px;
    top: 200px;
    width: 100px;
    height: 100px;
    background: yellow;
    box-shadow: 0 0 50px 0 red;
}

在这里插入图片描述
新的绘制调用堆栈如下:

drawPaint(paint)
translate(75, 75)
clipRect(1,1,99,99, "kDifference_Op",false) 
drawRect(0, 0, 100, 100, paint)
drawRect(0, 0, 100, 100, paint)

这里可以看到,在第二行中的translate的入参发生了变化,而第四行绘制阴影矩形的尺寸并没有发生变化。所以我这里推论,blur参数并不影响阴影矩形的面积尺寸,但是会改变阴影开始模糊的位置。在layer中,可以看见图形外围的那个绿色框框。
在这里插入图片描述

spread

在上面的基础上,设置spread参数,查看spread对那些绘制产生印象。

.box-shadow {
    position: fixed;
    left: 200px;
    top: 200px;
    width: 100px;
    height: 100px;
    background: yellow;
    box-shadow: 0 0 50px 10px red;
}

在这里插入图片描述
这里面执行了以下序列函数,从中可以看出在第二步和第四步发生了变化,首先可以肯定的是,第二步translate的变化会对阴影模糊的效果产生影响,第四步对阴影矩形的大小和位置做了改变。对于阴影矩阵,可以很容易看出其相对于内容矩阵而言,分别向4个方向扩展了10px,也就是spread的大小。而translate的偏移量也相对的增加了10px。

drawPaint(paint)
translate(85, 85)//这里的偏移量发生了变化
clipRect(1,1,99,99,"kDifference_Op",false)
drawRect(-10,-10,110,110,paint)//这里阴影rect的尺寸和绘制起点都发生了变化
drawRect(0, 0,100,100, paint)

如果再在此基础上加横向和纵向偏移,会改变哪几行代码的执行呢?其实,根据上面的执行效果来看,可以很容易的推断出,首先阴影的尺寸大小应该不会发生变化,实际显示区域的内容也不会发生变化,也就是最后3行,理论上都不会变化。那么,第二行,变化就可能发生在第二行。

.box-shadow {
    position: fixed;
    left: 200px;
    top: 200px;
    width: 100px;
    height: 100px;
    background: yellow;
    box-shadow: 10px 10px 50px 10px red;//这里增加了x y向的偏移
}

修改成上面的代码,运行一下,实际的效果如下。可以很明显的看到,整体阴影向右下偏移。
在这里插入图片描述
外层绿色框框的区域是整个阴影绘制画板区域,横向纵向偏移可以理解为移动该区域。如何计算外层区域绘制的大小呢?
先忽略x轴和y轴偏移,计算外层矩形的位置。以下图为例,需计算出N点的位置。

 .box-shadow {
   position: fixed;
    left: 200px;
    top: 200px;
    width: 100px;
    height: 100px;
    background: yellow;
    box-shadow: 0 0 50px 10px red;
}

在上面这段代码中,可以看出,内层显示区域大小ABCD为100X100;由于有spread:10px,所以一外层HGFE的尺寸为110X110;blur半径为50px,所以从外层阴影边缘向外扩展50,此处为模糊区域;从模糊边缘在向外扩展模糊半径的一般即25,即是最外层边框的位置,整体距离内层显示区域距离85。左上角横向85,纵向85,即是外层画布的起点,由此可以确定整个外层边框区域。计算公式大致为:spreadWidth + blurWidth + blurWidth/2。
计算出外层区域后,之后的横向纵向偏移,在保持内部显示区域不懂,只需对整个大的外层进行平移即可。
在这里插入图片描述
以上都是针对外阴影的计算与绘制,内阴影则不适用。接下来可以看下内阴影的绘制过程

内阴影

设置以下内阴影,查看绘制过程如下

 .box-shadow {
   position: fixed;
    left: 200px;
    top: 200px;
    width: 100px;
    height: 100px;
    background: yellow;
    box-shadow: 0 0 50px 0 red inset;
}

从下面图中右侧顶部的绘制图层可以看出,最外层的绿色大边框画布与元素大小重叠。在整个的绘制过程中,执行了以下几个函数:

drawPaint(paint)
drawRect(0, 0, 100, 100, paint)	//黄色矩形框
clipRect(0,0,100,100, "kIntersect_Op", false)
drawDRRect(outer, inner, paint)

在这里插入图片描述
这里与外阴影不同的是,外阴影先绘制了阴影rect,后绘制的显示rect,内阴影则相反。模糊半径影响了哪里?毫无疑问,肯定是最后一个函数了。查看最后一个函数的入参可以看见,这里有些变化。
在这里插入图片描述
改变blur的大小,会影响outer的位置和大小;改变spread的大小,会影响inner的尺寸和位置。

.box {
	width: 100px;
	height: 100px;
	box-shadow: 0 0 50px 10px inset;
}

如上面的例子,元素大小100,设置spread为10。则inner的大小为90X90,由于内阴影向内扩展,所以inner的rect为{top: 10,left: 10,right: 90,bottom:90}
如果设置blur为50,则outer为元素向外扩展50,对应的rect为{top: -50,left: -50,right: 100+50,bottom: 100+50}
内阴影的x轴y轴偏移:

.box-shadow {
    position: fixed;
    left: 200px;
    top: 200px;
    width: 100px;
    height: 100px;
    background: yellow;
    box-shadow: 10px 10px 20px 10px red inset;
}

在这里插入图片描述

Skia

Skia是一个开源的2D图形库,它提供了可以在各种硬件和软件平台上工作的通用api。它是Google Chrome和ChromeOS、Android、Flutter、Mozilla Firefox和Firefox OS以及许多其他产品的图形引擎。官方地址:https://skia.org/docs/。这里只是简单列举了下渲染过程中出现的几个函数,有兴趣的再继续研究吧。

drawRect 绘制矩形函数
void SkCanvas::drawRect(const SkRect &rect,const SkPaint &paint )	
clipRect 矩形裁剪函数

在Chrome中,clipRect方法通常用于定义一个矩形区域,该区域将被裁剪或剪切,以只显示该区域内的内容。这个方法通常与Canvas API或SVG等图形绘制技术一起使用。

例如,在Canvas API中,clipRect方法可以用于裁剪一个矩形区域,以便在绘制其他图形或文本时只显示该区域内的内容。

clipRect(1,1,99,99,"kDifference_Op",false)

在这里插入图片描述

SkRegion::Op 是 Skia 中用于定义区域操作(例如合并、差集等)的枚举。kDifference_Op 是这个枚举的一个值,表示执行差集操作。

差集操作意味着从一个区域中减去另一个区域。如果两个区域有重叠的部分,那么重叠的部分将从结果区域中被移除。

简单地说,如果你有两个区域 A 和 B,并且对它们执行差集操作,那么结果区域将只包含那些在 A 中但不在 B 中的点。

drawDRRect

drawDRRect的作用有点类似于canvas中的drawDRRect方法,用于在画布上绘制一个带有圆角的矩形,并在其内部挖出一个小的带有圆角的矩形,形成一个“圆角矩形环”,在box-shadow绘制内阴影时会调用该函数。

以下是 drawDRRect 方法的基本用法:

void SkCanvas::drawDRRect(const SkRRect &outer,const SkRRect &inner,const SkPaint &paint)

总结

通过查看图层渲染的过程,可以很好的帮助我们理解box-shadow的绘制,以及如何设置blur和spread参数的值来达到想要的阴影效果。本文主要是想研究blur和spread在阴影绘制过程中如何影响最终的渲染效果的,只有知道这些,你才能知道如何合理的设置对应的值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1361187.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue-video-player播放hls视频流

需求 最近需要接入海康视频摄像头,然后把视频的画面接入到自己的网站系统中。以前对接过rtsp固定IP的显示视频,这次的不一样,没有了固定IP。海康的解决办法是,摄像头通过配置服务器到萤石云平台,然后购买企业版账号和…

【unity小技巧】实现没有动画的FPS武器摇摆和摆动效果

文章目录 前言开始完结 前言 添加程序摇摆和摆动是为任何FPS游戏添加一些细节的非常简单的方法。但是并不是所以的模型动画都会配有武器摆动动画效果,在本文中,将实现如何使用一些简单的代码实现武器摇摆和摆动效果,这比设置动画来尝试实现类…

调整几行代码,接口吞吐提升 10 倍,性能调优妙啊!

景 分析过程 总结 背景 公司的一个ToB系统,因为客户使用的也不多,没啥并发要求,就一直没有经过压测。这两天来了一个“大客户”,对并发量提出了要求:核心接口与几个重点使用场景单节点吞吐量要满足最低500/s的要求。 当时一想,500/s吞吐量还不简单。Tomcat按照100个线程…

小心JDK20 ZipOutputStream

Oracle 團隊竟然這麽粗心,編譯JDK 20 時ZipOutputStream沒有編譯成功就發佈了。 所以這個20版本不可以使用ZipOutputStream。 GZIPInputStream 只能做最後的壓縮,不能添加多個附件ZipEntry。 下一個版本21不存在這個問題。 try(var zipOut new ZipOu…

C++之STL库简介

目录 一、STL(Standard Template Library,标准模板库) 二、容器(Containers) 1.vector(动态数组) 2.list(双向链表) 3.deque(双端队列) 4.st…

怎么做表单二维码来获取用户数据?扫码填表的制作方法

​怎么用二维码来收集其他人的信息,比如用户反馈、信息采集、问卷调查等等,都是现在表单二维码的常见应用方式。那么如果我们想制作一个表单二维码用来采集其他人员的反馈信息,用二维码生成器来制作的步骤有哪些呢?下面来教大家在…

Redis高级特性和应用(慢查询、Pipeline、事务、Lua)

Redis的慢查询 许多存储系统(例如 MySQL)提供慢查询日志帮助开发和运维人员定位系统存在的慢操作。所谓慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设阀值,就将这条命令的相关信息(例如:发生时间,耗时,命令的详细信息)记录下来,Redis也提供了类似…

高压放大器输出接法及其注意事项

高压放大器应用场景非常广泛,非常适用于半导体高压驱动、TFT产业高压驱动、各种高压工程等应用;也很适用当作音频信号产生器或函数波形产生器的波形放大使用。使用场景广泛,放大器的输出接法也多种,对于不同的放大器也有对应的输出…

Linux vi/vim 教程

文章目录 【 1. vi/vim 的三种模式 】1.1 命令模式1.2 输入模式1.3 底线命令模式 【 2. 实例 】【 3. vim 的其他命令 】 所有的 Unix Like 系统都会内建 vi 文本编辑器,其他的文本编辑器则不一定会存在。目前我们使用比较多的是 vim 编辑器。vim 从 vi 发展出来&am…

Leetcode 剑指 Offer II 060. 前 K 个高频元素

题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer(专项突击版)系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给定一个整数数组 nums 和一个整数 k ,请返回其中出现…

【Java集合篇】接上篇博文--为什么在JDK8中HashMap要转成红黑树

为什么在JDK8中HashMap要转成红黑树 ✔️为什么不继续使用链表✔️为什么是红黑树✔️红黑树的性能优势 ✔️ 拓展知识仓✔️为什么是链表长度达到8的时候转✔️为什么不在冲突的时候立刻转✔️关于为什么长度为8的时候转(源码注释解读)✔️为什么长度为6的时候转回来?✔️双向…

使用jmeter从0开始完成性能测试

使用JMeter从0开始完成性能测试 介绍 在软件开发过程中,性能测试是一项关键任务,它可以帮助我们评估系统在不同负载条件下的性能表现,发现潜在的性能瓶颈。JMeter是一款功能强大且易于使用的性能测试工具,它可以帮助我们完成各种…

iec104和iec61850

iec104和iec61850 IEC104 规约详细解读(一) 协议结构 IEC104 规约详细解读(二)交互流程以及协议解析 61850开发知识总结与分享【1】 Get the necesarry projects next to each other in the same directory; $ git clone https://github.com/robidev/iec61850_open_server.g…

NGUI基础-Widget

目录 Widget是什么 Widget组件包含的属性 Pivot Depth Size snap Aspect Free Based on Width Based on Height Widget是什么 在Unity UI系统中,"Widget"是指UI元素的基类,它为UI元素提供了位置、大小和锚点等基本属性。通过使用&qu…

VINS-MONO拓展2----更快地makeHessian矩阵

1. 目标 完成大作业T2 作业提示: 多线程方法主要包括以下几种(参考博客): MPI(多主机多线程开发),OpenMP(为单主机多线程开发而设计)SSE(主要增强CPU浮点运算的能力)CUDAStream processing, 之前已经了解过std::thread和pthread,拓展1…

冠军团队!第二届百度搜索创新大赛AI方案

Datawhale干货 作者:李柯辰,Datawhale成员 写在前面 大家好,我们是2023年第二届百度搜索创新大赛 赛道三——AI应用设计赛道的冠军团队——“肝到凌晨”,很高兴能与大家分享我们这次比赛的经验,同时也希望以后有机会可…

【机器学习:欧氏距离 】机器学习中欧氏距离的理解和应用

【机器学习:欧氏距离 】机器学习中欧氏距离的理解和应用 距离公式二维更高的维度点以外的物体属性欧几里得距离的平方概括历史 在数学中,欧氏距离’是指欧氏空间中任意两点之间的直线距离。这种距离可以通过应用勾股定理来计算,利用两点的笛卡…

【userfaultfd 条件竞争】starCTF2019 - hackme

前言 呜呜呜,这题不难,但是差不多一个多月没碰我的女朋友 kernel pwn 了,对我的 root 宝宝也是非常想念,可惜这题没有找到我的 root 宝宝,就偷了她的 flag。 哎有点生疏了,这题没看出来堆溢出&#xff0c…

【漏洞复现】ActiveMQ反序列化漏洞(CVE-2015-5254)

Nx01 产品简介 Apache ActiveMQ是Apache软件基金会所研发的开放源代码消息中间件。ActiveMQ是消息队列服务,是面向消息中间件(MOM)的最终实现,它为企业消息传递提供高可用、出色性能、可扩展、稳定和安全保障。 Nx02 漏洞描述 Re…

漫谈大模型的[幻觉]问题

# 如何解决大模型的幻觉问题?# 🎬个人简介:一个全栈工程师的升级之路! 📋个人专栏:漫谈LLMs带来的AIGC浪潮​​​​​​​ 🎀CSDN主页 发狂的小花 🌄人生秘诀:学习的本质…