CSS 已经能够获取视口长度了,时间可以追溯到……(查看笔记)……2013年!令人惊讶的是,那已经是十多年前的事了。如今,获取视口宽度就像编写 100vw
一样简单,但这在像素中又意味着什么呢?其他属性呢,比如那些采用百分比、角度或整数的属性?
考虑一下根据屏幕大小更改元素的不透明度、旋转它或设置动画进度。首先需要视口作为整数——这在 CSS 中目前是不可能的,对吧?
我接下来要说的并非什么突破性的发现,Jane Oriin 在 2023 年就精彩地描述过。简而言之,我们可以使用一个涉及 tan()
和 atan2()
三角函数的奇特技巧(或特性)来将长度(例如视口)类型转换为整数。这开启了许多新的布局可能性,但我第一次体验是在编写 Almanac 条目时,我只是想让图像的不透明度具有响应性。
调整 CodePen 大小,随着屏幕尺寸变小,图像会变得更透明,当然会有一些边界,因此它不会变得不可见:
这是我们能做的最简单的方法,但还有更多。例如,我尝试组合许多与视口相关的效果所做的这个演示。调整演示大小,页面就会充满活力:对象移动、背景变化,文本平滑地换行到位。
我认为这真的很酷,但我不是设计师,所以这是我大脑所能想到的最好的方法。不过,对于这个类型转换技巧的介绍来说,这可能有点太多了,因此,作为中间地带,我将只关注标题转换以展示其所有工作原理:
其背后的想法是使用 atan2()
将 100vw
转换为弧度(一种编写角度的方式),然后使用 tan()
返回其原始值,其优点是作为整数出现。应该像这样实现:
<code>:root { --int-width: tan(atan2(100vw, 1px)); }</code>
但是!浏览器不太支持这种方法,因此需要更多包装才能使其在所有浏览器中都能工作。以下内容可能看起来像魔法(或无稽之谈),所以我建议阅读 Jane 的文章以更好地理解它,但这样它就能在所有浏览器中工作:
<code>@property --100vw { syntax: "<length>"; initial-value: 0px; inherits: false; } :root { --100vw: 100vw; --int-width: calc(10000 * tan(atan2(var(--100vw), 10000px))); }</length></code>
别太担心。重要的是我们宝贵的 --int-width
变量,它保存视口大小作为整数!
现在我们有了视口作为整数,但这只是第一步。这个整数本身并不是非常有用。我们应该接下来将其转换为其他内容,因为:
考虑一下图像的不透明度从 0 变为 1,对象从 0deg 旋转到 360deg,或者元素的 offset-distance
从 0% 变为 100%。我们希望随着 --int-width
变大而在这些值之间进行插值,但现在它只是一个通常在 0 到 1600 之间变化的整数,这是不灵活的,并且不能轻松转换为任何结束值。
最好的解决方案是将 --int-width
转换为一个从 0 到 1 的数字。因此,随着屏幕变大,我们可以将其乘以所需的结束值。由于缺乏更好的名称,我称这个“0 到 1”的值为 --wideness
。如果我们有 --wideness
,所有最后的示例都成为可能:
<code>:root { --int-width: tan(atan2(100vw, 1px)); }</code>
因此,--wideness
是一个介于 0 到 1 之间的值,表示屏幕的宽度:0 表示屏幕狭窄时,1 表示屏幕宽阔时。但我们仍然必须设置这些值在视口中的含义。例如,我们可能希望 0 为 400px,1 为 1200px,我们的视口转换将在这些值之间运行。低于和高于的值分别被钳位到 0 和 1。
在 CSS 中,我们可以这样编写:
<code>@property --100vw { syntax: "<length>"; initial-value: 0px; inherits: false; } :root { --100vw: 100vw; --int-width: calc(10000 * tan(atan2(var(--100vw), 10000px))); }</length></code>
除了简单的转换之外,--wideness
变量还可以让我们定义转换应该运行的下限和上限。更好的是,我们可以将转换区域设置在中间位置,以便用户可以充分欣赏它。否则,屏幕需要为 0px,以便 --wideness
达到 0,而谁知道要达到 1 需要多宽。
首先,标题的标记被分成 span,因为没有 CSS 方法可以选择句子中的特定单词:
<code>/* 如果 `--wideness` 为 0.5 */ .element { opacity: var(--wideness); /* 为 0.5 */ translate: rotate(calc(wideness(400px, 1200px) * 360deg)); /* 为 180deg */ offset-distance: calc(var(--wideness) * 100%); /* 为 50% */ }</code>
由于我们将自己进行换行,因此取消设置一些默认值非常重要:
<code>:root { /* 两个边界都是无单位的 */ --lower-bound: 400; --upper-bound: 1200; --wideness: calc( (clamp(var(--lower-bound), var(--int-width), var(--upper-bound)) - var(--lower-bound)) / (var(--upper-bound) - var(--lower-bound)) ); }</code>
转换应该可以在没有基本样式的情况下工作,但它看起来太普通了。如果您想将它们复制到您的样式表中,它们如下所示:
最后,我们的当前技巧如下所示:
<code><h1>Resize and enjoy!</h1></code>
好了,设置就到这里。现在是时候使用我们的新值并进行视口转换了。我们首先必须确定标题应该如何重新排列以适应较小的屏幕:正如您在初始演示中看到的,第一个 span
向上和向右移动,而第二个 span
向相反的方向移动,向下和向左移动。因此,两个 span
的最终位置转换为以下值:
<code>h1 { position: absolute; /* 保持文本居中 */ white-space: nowrap; /* 禁用换行 */ }</code>
在继续之前,这两个公式基本上相同,但符号不同。我们可以通过引入一个新变量 --direction
来一次重写它们。它将是 1 或 -1,并定义运行转换的方向:
<code>:root { --int-width: tan(atan2(100vw, 1px)); }</code>
下一步是将 --wideness
引入公式中,以便随着屏幕大小调整而更改值。但是,我们不能只将所有内容乘以 --wideness
。为什么?让我们看看如果我们这样做会发生什么:
<code>@property --100vw { syntax: "<length>"; initial-value: 0px; inherits: false; } :root { --100vw: 100vw; --int-width: calc(10000 * tan(atan2(var(--100vw), 10000px))); }</length></code>
正如您将看到的,一切都反过来了!当屏幕太宽时,单词会换行,当屏幕太窄时,单词会取消换行:
与我们的第一个示例不同,在第一个示例中,转换随着 --wideness
从 0 增加到 1 而结束,我们希望随着 --wideness
从 1 减少到 0 而完成转换,即随着屏幕变小,属性需要达到其最终值。这没什么大不了的,因为我们可以将我们的公式重写为减法,其中减数随着 --wideness
的增加而增加:
<code>/* 如果 `--wideness` 为 0.5 */ .element { opacity: var(--wideness); /* 为 0.5 */ translate: rotate(calc(wideness(400px, 1200px) * 360deg)); /* 为 180deg */ offset-distance: calc(var(--wideness) * 100%); /* 为 50% */ }</code>
现在,调整屏幕大小时,所有内容都将朝正确的方向移动!
但是,您会注意到单词如何直线移动,以及调整大小时某些单词如何重叠。我们不允许这样做,因为具有特定屏幕尺寸的用户可能会在转换中的这一点上卡住。视口转换很酷,但不以破坏某些屏幕尺寸的体验为代价。
单词不应直线移动,而应曲线移动,以便它们绕过中心单词。别担心,在这里制作曲线比看起来容易:只需在 x 轴上使 span 的移动速度是 y 轴的两倍即可。这可以通过将 --wideness
乘以 2 来实现,尽管我们必须将其限制为 1,这样它就不会超过最终值。
<code>:root { /* 两个边界都是无单位的 */ --lower-bound: 400; --upper-bound: 1200; --wideness: calc( (clamp(var(--lower-bound), var(--int-width), var(--upper-bound)) - var(--lower-bound)) / (var(--upper-bound) - var(--lower-bound)) ); }</code>
看看那美丽的曲线,正好避开了中心文本:
令人惊讶的是,将视口作为整数可以有多强大,更疯狂的是,最后一个示例是您可以使用此类型转换技巧进行的最基本转换之一。一旦您完成了初始设置,我可以想象还有更多可能的转换,而 --wideness
非常有用,就像现在拥有一个新的 CSS 功能一样。
我希望将来能看到更多关于“视口转换”的内容,因为它们确实使网站比自适应网站感觉更“生动”。
以上是用tan(atan2())在CSS中的打字和视口转换的详细内容。更多信息请关注PHP中文网其他相关文章!