热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

理解CSS3transform中的Matrix(矩阵)——张鑫旭

by zhangxinxu from http:www.zhangxinxu.com本文地址:http:www.zhangxinxu.co

四、transform与坐标系统

用过transform旋转的人可以发现了,其默认是绕着中心点旋转的,而这个中心点就是transform-origin属性对应的点,也是所有矩阵计算的一个重要依据点(下图参考自dev.opera.com)。
transform坐标系统

当我们通过transform-origin属性进行设置的时候,矩阵相关计算也随之发生改变。反应到实际图形效果上就是,旋转拉伸的中心点变了!

举例来说,如果偶们设置:

-webkit-transform-origin: bottom left;

则,坐标中心点就是左下角位置。于是动画(例如图片收缩)就是基于图片的左下角这一点了:
动画的起始点 张鑫旭-鑫空间-鑫生活

上图效果可以点击这里查看(Chrome浏览器)。

再举个稍微难理解的例子,我们如果这样设置:

transform-origin: 50px 70px;

则,中心点位置有中间移到了距离左侧50像素,顶部70像素的地方(参见下图),而此时的(30, 30)的坐标为白点所示的位置(这个位置后面会用到)。
中心坐标数值偏移的理解 张鑫旭-鑫空间-鑫生活

仔细看看,是不是很快就理解了哈~~

五、准备好了没?重头戏来了

CSS3 transformmatrix()方法写法如下:

transform: matrix(a,b,c,d,e,f);

吓住了吧,这多参数,一个巴掌都数不过来。好吧,如果你把a~f这6个参数想象成女神的名词,你会觉得,世界不过如此嘛~~

实际上,这6参数,对应的矩阵就是:
矩阵参数与矩阵对应关系 张鑫旭-鑫空间-鑫生活

注意书写方向是竖着的

上面提过,矩阵可以想象成古代的士兵方阵,要让其发生变化,只有与另外一个士兵阵火拼就可以了,即使这是个小阵。

反应在这里就是如下转换公式:
CSS3中矩阵位置计算公式 张鑫旭-鑫空间-鑫生活

其中,xy表示转换元素的所有坐标(变量)了。那后面的ax+cy+e怎么来的呢?
//zxx:大学时候线性代数知识,懂的人这里可以直接跳过

很简单,3*3矩阵每一行的第1个值与后面1*3的第1个值相乘,第2个值与第2个相乘,第3个与第3个,然后相加,如下图同色标注:
矩阵计算的同色标注

ax+cy+e的意义是什么?
记住了,ax+cy+e为变换后的水平坐标,bx+dy+f表示变换后的垂直位置。

又迷糊了?不急,一个简单例子就明白了。

假设矩阵参数如下:

transform: matrix(1, 0, 0, 1, 30, 30); /* a=1, b=0, c=0, d=1, e=30, f=30 */

现在,我们根据这个矩阵偏移元素的中心点,假设是(0, 0),即x=0y=0

于是,变换后的x坐标就是ax+cy+e = 1*0+0*0+30 =30y坐标就是bx+dy+f = 0*0+1*0+30 =30.

于是,中心点坐标从(0, 0)变成了→(30, 30)。对照上面有个(30, 30)的白点图,好好想象下,原来(0,0)的位置,移到了白点的(30, 30)处,怎么样,是不是往右下方同时偏移了30像素哈!!

实际上transform: matrix(1, 0, 0, 1, 30, 30);就等同于transform: translate(30px, 30px);. 注意:translate,rotate等方法都是需要单位的,而matrix方法e, f参数的单位可以省略。

一例胜万语,您可以狠狠地点击这里:matrix(1,0,0,1,30,30)实例demo

在现代浏览器下,会有类似下面动图的效果:
30*30像素偏移示意

效果只是表象的,我想到了一个更好的idea去表现矩阵到底是如何变换的,您可以狠狠地点击这里:matrix分解变换演示

为了提高性能,demo中每个单元分解成了5px * 5px的区域。演示分两步,先是演示每个单元的位置是如何计算的,接着动画表现其位置的偏移。

这个demo所做的工作就是把浏览器瞬间完成的计算和渲染变成了可控的分步显示,这样,大家就可以很直观地看出,这个矩阵计算到底是如何起作用的。下图为正在演示过程中的截图:
矩阵计算分解演示demo截图 张鑫旭-鑫空间-鑫生活

//zxx:由于默认100毫秒间隔不断渲染,因此如果你电脑CPU或是浏览器hold不住,可以取消“自动演示”的勾选,然后,点击左边的按钮手动分步查看。

总结
聪明的你可能以及意识到了,尼玛matrix表现偏移就是:

transform: matrix(与我无关, 哪位, 怎么不去高考, 打麻将去吧, 水平偏移距离, 垂直偏移距离);

你只要关心后面两个参数就可以了,至于前面4个参数,是牛是马,是男是女都没有关系的。

六、transform matrix矩阵与缩放,旋转以及拉伸

偏移是matrix效果中最简单,最容易理解的,因此,上面很详尽地对此进行展开说明。下面,为了进一步加深对matrix的理解,会简单讲下matrix矩阵与缩放,旋转以及拉伸效果。

缩放(scale)
上面的偏移只要关心最后两个参数,这个缩放也是只要关心两个参数。哪两个呢?

如果你足够明察秋毫,应该已经知道了,因为上面多次出现的:

transform: matrix(1, 0, 0, 1, 30, 30);

已经出卖了。

发现没,matrix(1, 0, 0, 1, 30, 30);的元素比例与原来一样,1:1, 而这几个参数中,有两个1, 啊哈哈!没错,这两个1就是缩放相关的参数。

其中,第一个缩放x轴,第二个缩放y轴。

用公式就很明白了,假设比例是s,则有matrix(s, 0, 0, s, 0, 0);,于是,套用公式,就有:
x\' = ax+cy+e = s*x+0*y+0 = s*x;
y\' = bx+dy+f = 0*x+s*y+0 = s*y;

也就是matrix(sx, 0, 0, sy, 0, 0);,等同于scale(sx, sy);

好了,至此,无需多说了……

眼见为实,因此demo还是要滴,您可以狠狠地点击这里:matrix矩阵与缩放demo

为了避免元素比例放大时候遮盖上面的文本框以及描述位子,因此,将元素的坐标原点迁至了左上角。

matrix矩阵缩放demo效果截图

旋转(rotate)
旋转相比前面两个要更高级些,要用到(可能勾起学生时代阴影的)三角函数。

方法以及参数使用如下(假设角度为θ):

matrix(cosθ,sinθ,-sinθ,cosθ,0,0)

结合矩阵公式,就有:

x\' = x*cosθ-y*sinθ+0 = x*cosθ-y*sinθ
y\' = x*sinθ+y*cosθ+0 = x*sinθ+y*cosθ

这个与IEMatrix滤镜中的旋转是有些类似的(M11表示矩阵第1行第1个(参数a),M21表示矩阵第2行第一个(参数b)……):

filter:progid:DXImageTransform.Microsoft.Matrix(M11=cosθ,M21=sinθ,M12=-sinθ,M22=cosθ\');

哎呀呀,四个参数,我记不住啊!莫慌,我们可以这样子记忆:
CS-SC:初三-上床,对称结构,这下忘不了了吧~~

您可以狠狠地点击这里:transform matrix矩阵与旋转demo

matrix矩阵旋转效果demo页面截图 张鑫旭-鑫空间-鑫生活

不过,说句老实话,就旋转而言,rotate(θdeg)这种书写形式要比matrix简单多了,首先记忆简单,其次,无需计算。例如,旋转30°,前者直接:

transform:rotate(30deg);

而使用matrix表示则还要计算cossin值:

transform: matrix(0.866025,0.500000,-0.500000,0.866025,0,0);

拉伸(skew)
拉伸也用到了三角函数,不过是tanθ,而且,其至于b, c两个参数相关,书写如下(注意y轴倾斜角度在前):

matrix(1,tan(θy),tan(θx),1,0,0)

套用矩阵公式计算结果为:

x\' = x+y*tan(θx)+0 = x+y*tan(θx) 
y\' = x*tan(θy)+y+0 = x*tan(θy)+y

对应于skew(θx + "deg",θy+ "deg")这种写法。

其中,θx表示x轴倾斜的角度,θy表示y轴,两者并无关联。

还是靠实例说话吧,您可以狠狠地点击这里:matrix矩阵与拉伸demo

在Chrome下可以很动态地查看不同倾斜角度对应的拉伸的效果:
拉伸效果demo页面截图

七、既然有简单的skew, rotate..,那matrix有何用?

我想有人会奇怪,既然CSS3 transform中提供了像skewrotate效果,那还需要掌握和熟悉让人头大的矩阵方法干嘛呢?

好问题,确实,对于一般地交互应用,transform属性默认提供的些方法是足够了,但是,一些其他的效果,如果transform属性没有提供接口方法,那你又该怎么办呢?比方说,“镜像对称效果”!

没辙了吧,这是,就只能靠matrix矩阵了。要知道,matrix矩阵是transform变换的基础,可以应付很多高端的效果,算是一种高级应用技巧吧。掌握了基础,才能兵来将挡水来土掩啊。

OK,这里就演示下,如何使用CSS3 transform matrix矩阵实现镜像效果。

这个有点难度,因此,我们先看demo,您可以狠狠地点击这里:matrix与镜像对称效果demo

框框中输入旋转的角度值(用来确定镜像的对称轴),然后失去焦点,就会呈现出对应的镜像对称效果了:
镜像对称效果操作示意 张鑫旭-鑫空间-鑫生活
镜像对称效果截图

您可以在FireFox或是Chrome等浏览器上体验下matrix实现的镜像渐变效果。

demo页面中的一个轴是为了便于理解我加上的效果,实际上,在镜像对称的时候轴是看不见的。

轴围绕的那个点就是CSS3中transform变换的中心点,自然,镜像对称也不例外。因为该轴永远经过原点,因此,任意对称轴都可以用y = k * x表示。则matrix表示就是:

matrix((1-k*k) / (1+k*k), 2k / (1 + k*k), 2k / (1 + k*k), (k*k - 1) / (1+k*k), 0, 0)

这个如何得到的呢?
啊,高中数学来了,就当再高考一次吧,如下图,已经y=kx,并且知道点(x, y)坐标,求其对称点(x’, y’)的坐标?
镜像渐变题目 张鑫旭-鑫空间-鑫生活

很简单,一是垂直,二是中心点在轴线上,因此有:

(y-y\') / (x - x\') = -1/ k → ky-ky\' = -x+x\'
(x + x\') / 2 * k = (y + y\')/2 → kx+kx\' = y+y\'

很简单的,把x\'y\'提出来,就有:

x\' = (1-k*k)/(k*k+1) *x + 2k/(k*k+1) *y;
y\' = 2k/(k*k+1) *x + (k*k-1)/(k*k+1) *y;

再结合矩阵公式:
x\' = ax+cy+e;
y\' = bx+dy+f;

我们就可以得到:
a = (1-k*k)/(k*k+1);
b = 2k/(k*k+1);
c = 2k/(k*k+1);
d = (k*k-1)/(k*k+1);

也就是上面matrix方法中的参数值啦!

下图为自己计算的草稿:
镜像矩阵参数计算草稿

八、3D变换中的矩阵

3D变换虽然只比2D多了一个D,但是复杂程度不只多了一个。从二维到三维,是从4到9;而在矩阵里头是从3*3变成4*4, 9到16了。

其实,本质上很多东西都与2D一致的,只是复杂度不一样而已。这里就举一个简单的3D缩放变换的例子。

对于3D缩放效果,其矩阵如下:
3D比例变换矩阵图 张鑫旭-鑫空间-鑫生活

代码表示就是:

transform: matrix3d(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1)

您可以狠狠地点击这里:matrix3d下的3D比例变换demo

补充于2013-04-24
关于3D变换,可以参见邪恶的这篇文章:“CSS3 3D transform变换,不过如此!”

九、结束语

想了想,没什么要唠叨的。文中观点若是存在疑问或不准确的,欢迎指正。感谢阅读!

参考文章:
Understanding the CSS Transforms Matrix
CSS3前端开发中需要用到的变换矩阵

原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活[http://www.zhangxinxu.com]
本文地址:http://www.zhangxinxu.com/wordpress/?p=2427

(本篇完)


推荐阅读
  • 在前文探讨了Spring如何为特定的bean选择合适的通知器后,本文将进一步深入分析Spring AOP框架中代理对象的生成机制。具体而言,我们将详细解析如何通过代理技术将通知器(Advisor)中包含的通知(Advice)应用到目标bean上,以实现切面编程的核心功能。 ... [详细]
  • CSS中的pointer-events属性详解与应用
    在CSS中,`pointer-events`属性是一个非常实用但常被忽视的功能。它主要用于控制元素是否响应鼠标事件。当一个元素覆盖在其他元素之上时,通过设置`pointer-events`属性,可以决定该元素是否能够接收鼠标点击、悬停等交互操作,从而实现更灵活的用户界面设计。例如,将`pointer-events`设置为`none`可以使元素透明地传递鼠标事件,方便实现复杂的叠加效果和交互逻辑。 ... [详细]
  • 如何使用 `org.apache.tomcat.websocket.server.WsServerContainer.findMapping()` 方法及其代码示例解析 ... [详细]
  • 为了优化用户体验,本文探讨了如何调整下拉菜单的宽度。通过合理设置宽度,可以提升界面的美观性和易用性。文章提供了具体的代码示例,帮助开发者实现这一目标。例如,可以通过 CSS 或 JavaScript 来动态调整下拉菜单的宽度,确保其在不同设备和屏幕尺寸上都能保持良好的显示效果。 ... [详细]
  • C++ 开发实战:实用技巧与经验分享
    C++ 开发实战:实用技巧与经验分享 ... [详细]
  • 本文介绍了 Vue 开发的入门指南,重点讲解了开发环境的配置与项目的基本搭建。推荐使用 WebStorm 作为 IDE,其下载地址为 。安装时请选择适合您操作系统的版本,并通过 获取激活码。WebStorm 是前端开发者的理想选择,提供了丰富的功能和强大的代码编辑能力。 ... [详细]
  • 本文深入探讨了Ajax的工作机制及其在现代Web开发中的应用。Ajax作为一种异步通信技术,改变了传统的客户端与服务器直接交互的模式。通过引入Ajax,客户端与服务器之间的通信变得更加高效和灵活。文章详细分析了Ajax的核心原理,包括XMLHttpRequest对象的使用、数据传输格式(如JSON和XML)以及事件处理机制。此外,还介绍了Ajax在提升用户体验、实现动态页面更新等方面的具体应用,并讨论了其在当前Web开发中的重要性和未来发展趋势。 ... [详细]
  • 在需要将网页内容保存为图片时,通常可以使用系统自带的截图工具。然而,对于较长的页面,尤其是带有滚动条的情况,操作起来较为不便。为此,推荐一款功能强大的Chrome浏览器插件——FireShot。该插件不仅支持区域截图,还能实现整页长截图和视频录制,极大地提升了网页内容的捕捉效率和质量。此外,FireShot还提供了丰富的编辑和分享选项,方便用户进行后续处理和分发。 ... [详细]
  • 本文介绍了如何在iOS平台上使用GLSL着色器将YV12格式的视频帧数据转换为RGB格式,并展示了转换后的图像效果。通过详细的技术实现步骤和代码示例,读者可以轻松掌握这一过程,适用于需要进行视频处理的应用开发。 ... [详细]
  • 在Android 4.4系统中,通过使用 `Intent` 对象并设置动作 `ACTION_GET_CONTENT` 或 `ACTION_OPEN_DOCUMENT`,可以从相册中选择图片并获取其路径。具体实现时,需要为 `Intent` 添加相应的类别,并处理返回的 Uri 以提取图片的文件路径。此方法适用于需要从用户相册中选择图片的应用场景,能够确保兼容性和用户体验。 ... [详细]
  • 软件测试工程师必备:全面解析Web应用的浏览器兼容性测试方法与工具
    随着市场上浏览器种类的不断增多,特别是在平板和移动设备上的普及,确保网站在各种浏览器中都能正常运行变得尤为重要。本文将深入探讨Web应用的浏览器兼容性测试方法与工具,帮助软件测试工程师全面掌握这一关键技能,以提高应用的用户体验和可靠性。 ... [详细]
  • 本文深入探讨了 HTML 中的 `margin` 属性,详细解析了其基本特性和应用场景。文章不仅介绍了 `margin` 的基本概念,还重点讨论了垂直外边距合并现象,并分析了 `margin` 在块级元素与内联元素中的不同表现。通过实例和代码示例,帮助读者全面理解 `margin` 的使用技巧和常见问题。 ... [详细]
  • 2019年斯坦福大学CS224n课程笔记:深度学习在自然语言处理中的应用——Word2Vec与GloVe模型解析
    本文详细解析了2019年斯坦福大学CS224n课程中关于深度学习在自然语言处理(NLP)领域的应用,重点探讨了Word2Vec和GloVe两种词嵌入模型的原理与实现方法。通过具体案例分析,深入阐述了这两种模型在提升NLP任务性能方面的优势与应用场景。 ... [详细]
  • 在Android平台上利用FFmpeg的Swscale组件实现YUV与RGB格式互转
    本文探讨了在Android平台上利用FFmpeg的Swscale组件实现YUV与RGB格式互转的技术细节。通过详细分析Swscale的工作原理和实际应用,展示了如何在Android环境中高效地进行图像格式转换。此外,还介绍了FFmpeg的全平台编译过程,包括x264和fdk-aac的集成,并在Ubuntu系统中配置Nginx和Nginx-RTMP-Module以支持直播推流服务。这些技术的结合为音视频处理提供了强大的支持。 ... [详细]
  • 在Java中,一个类可以实现多个接口,但是否能够继承多个类则存在限制。本文探讨了Java中实现多继承的方法及其局限性,详细分析了通过接口、抽象类和组合等技术手段来模拟多继承的策略,并讨论了这些方法的优势和潜在问题。 ... [详细]
author-avatar
元辉5678_915
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有