CSS 转换的世界

2021-08-09 23:06:46

乍一看,这似乎是一件非常小众的事情。毕竟,我们多久需要旋转或倾斜一些东西?然而,我对转换了解得越多,我就越发现自己在利用它。在我博客的代码库中,我使用了 transform 属性超过 350 次!在这篇博文中,我们将深入研究 transform 属性。我会向你展示一些你可以用它做的很酷和意想不到的事情!通过使用诸如 translate 和 skew 之类的变换函数,transform 属性可以做很多不同的事情。我们可以使用 translate 沿任一轴移动项目:x 左右移动,y 上下移动。正值向下和向右移动。负值向上和向左移动。至关重要的是,项目的流入位置不会改变。就我们的布局算法而言,从 Flow 到 Flexbox 再到 Grid,这个属性没有任何作用。例如:在这个可视化中,我们有 3 个使用 Flexbox 对齐的孩子。当我们对中间的孩子应用变换时,Flexbox 算法不会注意到,并将其他孩子保持在同一个位置:这类似于顶部/左侧/右侧/底部在定位布局中的工作方式,具有相对定位的元素.

当我们想沿单个轴移动一个元素时,我们可以使用 translateX 和 translateY:不过,有一件事使 translate 变得非常强大。 CSS 语言中完全独一无二的东西。当我们在 translate 中使用百分比值时,该百分比指的是元素本身的大小,而不是父容器内的可用空间。设置 transform: translateY(-100%) 将框向上移动精确的高度,无论高度是多少,到像素。当我们希望一个元素正好位于另一个元素之外时,这非常方便: <style> .parent { position: relative; } .child { 宽度:50px;高度:50px; /* 把孩子放在右上角... */ position: absolute;顶部:0;右:0; /* ...然后把它移到外面:*/ transform: translateY(-100%); }</style><div class="parent"> <div class="child"></div></div> 这个技巧的一个常见用例是在对话框外添加一个“关闭”按钮:

<style> .dialog-content { 位置:相对; } .close-btn { 位置:绝对;顶部:0;右:0;变换:translateY(-100%); }</style><div class="dialog-wrapper"> <div class="dialog-content"> <button class="close-btn"> <svg xmlns="http://www.w3.org/ 2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"stroke="currentColor"stroke-width="2"stroke-linecap="round"stroke-linejoin= "round" class="feather Feather-x"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6 " x2="18" y2="18"></line></svg> <span class="visually-hidden"> 关闭对话框</span> </button> </div></div> 这允许我们添加一个“缓冲区”,这样我们就可以通过它自己的大小加上一些额外的像素来翻译一些东西。 Scale 使用表示倍数的无单位值,类似于 line-height。 scale(2) 意味着元素应该是通常情况下的 2 倍大。乍一看,这似乎等同于设置宽度和高度,但有一个很大的不同。文本随元素上下缩放。我们不只是改变盒子的大小和形状,我们正在改变整个元素及其所有后代。这揭示了关于变换的一个重要事实:元素被展平为纹理。所有这些变换本质上都将我们的元素视为平面图像,像在 Photoshop 中一样对其进行扭曲和扭曲。想想当我们改变宽度之类的东西时需要做多少工作。所有的布局算法都需要重新运行,找出这个元素及其所有兄弟元素的确切位置。如果元素内部有文本,换行算法需要确定这个新宽度是否影响换行符。然后,绘制算法运行,找出每个像素需要的颜色,并填充它。

在页面加载时执行一次就可以了,但是当我们为某些内容设置动画时,我们需要每秒多次执行所有这些计算。通过转换,我们可以跳过一堆步骤。这意味着计算运行得更快,从而导致更平滑的运动。缩放会拉伸/挤压元素的内容似乎很糟糕,但我们实际上可以利用这种效果来发挥我们的优势。例如,看看这个老式的电视电源动画:而且,如果我们真的不希望我们的文本被挤压,我们可以对孩子应用逆变换。这是一种先进的技术,远远超出了本博客文章的范围,但要知道可以使用缩放来增加元素的大小而不扭曲其子元素。像 Framer Motion 这样的库利用这一事实来构建高性能的动画而无需拉伸或挤压。我们通常使用 deg 单位表示旋转,是度数的缩写。但是我们可以使用另一个方便的单位,一个可能更容易推理的单位:转弯单位表示元素应该转多少圈。 1 转等于 360 度。它晦涩难懂,但得到了很好的支持;转向装置一直回到 IE 9!

Skew 可用于创建对角线装饰元素 (à la Stripe)。在 calc 和一些三角函数的帮助下,它也可以用于元素而不会扭曲文本!在 Nils Binder 的精彩博客文章“像 2020 年一样创建对角线布局”中深入探讨了这种技术。顺序很重要:变换函数将按顺序应用。在上面的例子中,我们将盒子向右平移,然后就地旋转它。旋转功能不仅旋转元素,它还旋转 X 轴和 Y 轴。当我们首先应用 rotate(45deg) 时, translateX 现在将沿对角线移动元素,因为 X 轴旋转了 45 度。 <style> @keyframes 轨道 { from { transform: rotate(0deg) translateX(80px); } to { 变换:旋转(360度)translateX(80px); } } @media (prefers-reduced-motion: no-preference ) { .moon { animation: 轨道 6000ms 线性无限; } }</style><div class="wrapper"> <div class="planet"></div> <div class="moon"></div></div> 旋转然后变换技术允许我们将一个元素设置为围绕其自然的、未转换的位置“运行”。在这个例子中,我们首先将月球定位在行星的死点,让它围绕它旋转一定距离。某些类型的变换具有原点,即变换锚定到的点。

这对某些类型的效果很有用(例如,一个元素“从另一个元素中生长出来”)。转换的一个常见问题是它们不适用于 Flow 布局中的内联元素。 <style> .inline-fella { /* 不起作用 :( */ transform: rotate(-10deg); }</style><p> 为什么 <span class="inline-fella">Hello</span> </p> 内联元素不喜欢被推挤。他们的目标是在尽可能少的中断的情况下环绕一些内容。转换不是他们的一杯茶。最简单的解决方法是将其切换为使用显示: inline-block,或者使用不同的布局模式(例如 Flexbox 或 Grid)。除了我们在本教程中介绍的 2D 转换之外,CSS 还可以在第三维中转换元素!3D 转换有自己的怪癖和特质. 为了公平起见,我将单独写一篇关于 3D 变换的文章。敬请期待!

我必须承认:本教程最初不是作为博客文章编写的。它是从我即将开设的 CSS 课程移植而来的:CSS for JavaScript Developers 是一门综合性的多格式课程,其目标是改变您与 CSS 的关系。该课程是专门为使用 React、Angular 或 Vue 等 JS 框架的人创建的。我们涵盖了 CSS 的基础知识,但在现代 JS 生态系统的背景下。它比我的博客文章更深入。除了数十个练习和项目外,还有 150 多个视频。我已经全职工作一年多了。近 5000 人在早期的众筹中购买了它,他们的反馈使课程变得更好。该课程将于 9 月 27 日发布,您可以在此处了解更多信息:css-for-js.dev。