【CSS】使用新版 CSS sin() 和 cos() 三角函数创建简约时钟和图片库

CSS三角函数来了!好吧,如果您使用的是最新版本的 Firefox 和 Safari,那就是这样。CSS 中拥有这种数学能力开启了一大堆可能性。在本教程中,我们应该好好来感受一下几个新函数:sin()cos()

目前还有其他三角函数,比如tan(),为什么只关注sin()cos()? 那是因为它非常适合我想要实现的想法,就是沿着圆的边缘放置文本。在CSS-Tricks上,Chris分享了一种使用Sass mixin的方法来实现这一点。那是六年前的事情了,所以让我们来尝试一下最新的技术。

以下是简单的效果。再次强调,目前只在Firefox和Safari浏览器中支持:

如何实现

所以,它并不完全像单词形成一个圆形,而是我们将字符沿着圆形排列,形成一个时钟的面板。下面我们就来使用html逐步分分析时钟结构:

<div class="clock">

  <div class="clock-face">
    <time datetime="12:00">12</time>
    <time datetime="1:00">1</time>
    <time datetime="2:00">2</time>
    <time datetime="3:00">3</time>
    <time datetime="4:00">4</time>
    <time datetime="5:00">5</time>
    <time datetime="6:00">6</time>
    <time datetime="7:00">7</time>
    <time datetime="8:00">8</time>
    <time datetime="9:00">9</time>
    <time datetime="10:00">10</time>
    <time datetime="11:00">11</time>
  </div>
</div>

这段CSS样式主要是用于给.clock-face设置一个容器的基本属性和样式,记住嗷,要考的:

  • --_ow: clamp(5rem, 60vw, 40rem);:这是一个CSS变量,用于设置容器的宽度。它使用了clamp函数,其中第一个参数表示最小宽度(5rem),第二个参数表示视窗宽度的百分比(60vw),第三个参数表示最大宽度(40rem)。

  • --_w: 88cqi;:这是另一个CSS变量,用于设置容器的宽度。

  • aspect-ratio: 1;:设置容器的宽高比为1,即正圆形。

  • background-color: tomato;:设置容器的背景颜色为番茄红。

  • border-radius: 50%;:设置容器的圆角半径为50%,使其呈现圆形。

  • container-type: inline;:设置容器的类型为内联元素,即与其他元素在一行上显示。

  • display: grid;:将容器的显示模式设置为网格布局。

  • height: var(--_ow);:设置容器的高度为之前定义的变量--_ow的值。

  • place-content: center;:将容器内容在网格布局中居中对齐。

  • position: relative;:设置容器的定位方式为相对定位。

  • width: var(--_ow);:设置容器的宽度为之前定义的变量--_ow的值。

这些样式通过定义CSS变量和一些基本属性来创建一个圆形的容器,并使其在网格布局中居中显示。

.clock {

  --_ow: clamp(5rem, 60vw, 40rem);
  --_w: 88cqi;
  aspect-ratio: 1;
  background-color: tomato;
  border-radius: 50%;
  container-type: inline;
  display: grid;
  height: var(--_ow);
  place-content: center;
  position: relative;
  width var(--_ow);
}

这一步呢,我们把轮廓画出来,给它稍微装饰下,以至于让我们知道大概思路。并且我们存入了css变量。

Large tomato colored circle with a vertical list of numbers 1-12 on the left.

看起来像不像一个艺术品…好了,现在引入一个新的变量 --_r,用于存储圆的半径,该半径等于圆的宽度的一半。这样,如果宽度 --_w 发生变化,半径值 --_r 也会更新,这要归功于另一个 CSS 数学函数 calc()

.clock {

  --_w: 300px;
  --_r: calc(var(--_w) / 2);
  /* 其他样式 */
}

现在需要用到一些数学知识。一个圆有 360 度。时钟上有 12 个标签,所以我们希望每 30 度(360 / 12)放置一个数字。在数学上,圆开始于 3 点钟位置,所以正午实际上是从那个位置减去 90 度,即 270 度(360 – 90)。

让我们再添加一个变量 --_d,可以用来为时钟面上的每个数字设置一个角度值。我们将递增这些值以完成整个圆:

.clock time:nth-child(1) { --_d: 270deg; }
.clock time:nth-child(2) { --_d: 300deg; }
.clock time:nth-child(3) { --_d: 330deg; }
.clock time:nth-child(4) { --_d: 0deg; }
.clock time:nth-child(5) { --_d: 30deg; }
.clock time:nth-child(6) { --_d: 60deg; }
.clock time:nth-child(7) { --_d: 90deg; }
.clock time:nth-child(8) { --_d: 120deg; }
.clock time:nth-child(9) { --_d: 150deg; }
.clock time:nth-child(10) { --_d: 180deg; }
.clock time:nth-child(11) { --_d: 210deg; }
.clock time:nth-child(12) { --_d: 240deg; }

通过以上代码,我们为时钟的每个数字设置了相应的角度值。这些角度值按照每次递增 30 度来完成整个圆的布局。

好的,现在是时候动手使用 sin()cos() 函数了!我们想要使用它们来获取每个数字的 X 和 Y 坐标,以便将它们正确地放置在时钟面上。

X 坐标的公式是 radius + (radius * cos(degree))。让我们将其插入到我们的新变量 --_x 中:

--_x: calc(var(--_r) + (var(--_r) * cos(var(--_d))));

Y 坐标的公式是 radius + (radius * sin(degree))。我们已经掌握了计算它所需的内容:

--_y: calc(var(--_r) + (var(--_r) * sin(var(--_d))));

还有一些基础设置,让我们对数字进行一些基本样式设置,以确保它们绝对定位并根据我们的坐标放置:

.clock-face time {
  --_x: calc(var(--_r) + (var(--_r) * cos(var(--_d))));
  --_y: calc(var(--_r) + (var(--_r) * sin(var(--_d))));
  --_sz: 12cqi;
  display: grid;
  height: var(--_sz);
  left: var(--_x);
  place-content: center;
  position: absolute;
  top: var(--_y);
  width: var(--_sz);
}

注意到 --_sz 这个变量,我们将在稍后用它来设置数字的宽度和高度。让我们看看目前为止我们得到了什么结果。

image.png

不错…这看起来更像是一个时钟了,大家要注意每个数字的左上角都正确地位于圆周上的相应位置。在计算每个数字的位置时,我们需要“缩小”半径。在计算半径之前,我们可以从圆的大小(–_w)中减去数字的大小(–_sz):

--_r: calc((var(--_w) - var(--_sz)) / 2);

这样,我们可以将数字的大小考虑在内,确保它们在正确的位置上放置。继续下一步操作~


A white clock face with numbers against a dark gray background. The clock has no arms.

想要达到这种效果,我们需要给它优化下外观就可以了。

我们已经实现了在圆圈周围放置文本的目标,对吧?但是没有指针来显示小时、分钟和秒钟的时钟算什么呢?

使用一个CSS动画来完成。首先,在我们的标记中添加三个额外的元素:

<div class="clock">

  <!-- 在 <time> 标签之后 -->
  <span class="arm seconds"></span>
  <span class="arm minutes"></span>
  <span class="arm hours"></span>
  <span class="arm center"></span>
</div>

然后为所有三个指针添加一些常见的标记。同样,大部分内容只是确保指针被绝对定位并相应地放置:

.arm {
  background-color: var(--_abg);
  border-radius: calc(var(--_aw) * 2);
  display: block;
  height: var(--_ah);
  left: calc((var(--_w) - var(--_aw)) / 2);
  position: absolute;
  top: calc((var(--_w) / 2) - var(--_ah));
  transform: rotate(0deg);
  transform-origin: bottom;
  width: var(--_aw);
}

我们将为所有三个指针使用相同的动画:

@keyframes turn {
  to {
    transform: rotate(1turn);
  }
}

唯一的区别在于各个指针完成一次完整旋转所需的时间。对于小时指针,需要12小时完成一次完整旋转。animation-duration 属性只接受毫秒和秒的值。让我们选择秒,也就是43,200秒(60秒 * 60分钟 * 12小时)。

animation: turn 43200s infinite;

分钟指针需要1小时完成一次完整旋转。但是我们希望这是一个多步动画,所以指针之间的移动是交错的,而不是线性的。我们需要60个步骤,对应每一分钟:

animation: turn 3600s steps(60, end) infinite;

秒钟指针与分钟指针几乎相同,只是持续时间为60秒而不是60分钟:

animation: turn 60s steps(60, end) infinite;

然后更新一下我们在公共样式中创建的属性:

.seconds {
  --_abg: hsl(0, 5%, 40%);
  --_ah: 145px;
  --_aw: 2px;
  animation: turn 60s steps(60, end) infinite;
}

.minutes {
  --_abg: #333;
  --_ah: 145px;
  --_aw: 6px;
  animation: turn 3600s steps(60, end) infinite;
}


.hours {
  --_abg: #333;
  --_ah: 110px;
  --_aw: 6px;
  animation: turn 43200s linear infinite;
}

如果我们想要从当前时间开始呢?可以用过JS来实现:

const time = new Date();
const hour = -3600 * (time.getHours() % 12);
const mins = -60 * time.getMinutes();
app.style.setProperty('--_dm', `${mins}s`);
app.style.setProperty('--_dh', `${(hour+mins)}s`);

我在时钟面上添加了 id="app",并在其上设置了两个新的自定义属性,用于设置负数的动画延迟,就像 Mate Marschalko 在共享纯CSS时钟时所做的那样。JavaScript 的 Date 对象的 getHours() 方法使用的是24小时制,因此我们使用余数运算符将其转换为12小时制。

在CSS中,我们还需要添加 animation-delay

.minutes {
  animation-delay: var(--_dm, 0s);
  /* 其他样式 */
}

.hours {
  animation-delay: var(--_dh, 0s);
  /* 其他样式 */
}

只剩下最后一件事。使用 CSS 的 @supports 和我们已经创建的属性,我们可以为不支持 sin() 和 cos() 的浏览器提供回退方案。(感谢 Temani Afif!)

@supports not (left: calc(1px * cos(45deg))) {
  time {
    left: 50% !important;
    top: 50% !important;
    transform: translate(-50%,-50%) rotate(var(--_d)) translate(var(--_r)) rotate(calc(-1*var(--_d)))
  }
}

图片库

好了,你不会以为我们时钟只能拿来当钟用吧???当然不是!!!

可以通过替换标签 <time> 然后 <img>更新宽度 ( --_w) 和半径 ( --_r) 值来快速将时钟变成圆形图像库。

OK!!结束了,注意,注意!注意!它只在 Firefox 和 Safari 中支持。

OK!!结束了,注意,注意!注意!它只在 Firefox 和 Safari 中支持。

OK!!结束了,注意,注意!注意!它只在 Firefox 和 Safari 中支持。

本文同步我的技术文档

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYGdbpJE' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片