新しい CSS sin() および cos() 三角関数を使用した時計の作成

新しい CSS sin() および cos() 三角関数を使用した時計の作成

ソースノード: 1999799

CSSの三角関数が登場! つまり、最新バージョンの Firefox と Safari を使用している場合です。 CSS にこの種の数学的能力を持たせることで、さまざまな可能性が開かれます。 このチュートリアルでは、つま先を水に浸して、いくつかの新しい機能の感触をつかもうと思いました。 sin() & cos().

パイプラインには他にも三角関数があります。 tan() — では、なぜ焦点を当てるのか sin() & cos()? それらは、円の端に沿ってテキストを配置するという、私が念頭に置いているアイデアにぴったりです。 これについては、CSS-Tricks で説明されています。 Chris は、Sass mixin を使用するアプローチを共有しました. それは XNUMX 年前のことなので、最先端の処理をしましょう。

これが私が考えていることです。 繰り返しますが、現時点では Firefox と Safari でのみサポートされています。

つまり、文字が円形を形成しているわけではありませんが、円に沿って文字を配置して時計の文字盤を形成しています。 物事を開始するために使用できるマークアップを次に示します。

<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>

次に、いくつかの非常に基本的なスタイルを示します。 .clock-face 容器。 を使うことにしました <time> タグには datetime 属性。 

.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);
}

そこに少し装飾を加えましたが、基本的な形状と背景色を取得して、何をしているのかを理解できるようにするためだけです. 保存方法に注意してください width の値 CSS変数. これは後で使用します。 これまでのところ、あまり見るべきことはありません:

左側に 1 ~ 12 の数字が縦に並んだ大きなトマト色の円。

ある種の現代アートの実験のように見えますよね? 新しい変数を導入しましょう。 --_r、サークルの 半径、これは円の幅の半分に相当します。 このように、幅 (--_w) 変更、半径値 (--_r) も更新されます — 別の CSS 数学関数のおかげで、 calc():

.clock { --_w: 300px; --_r: calc(var(--_w) / 2); /* rest of styles */
}

さて、ちょっとした数学。 円は 360 度です。 時計には 12 個のラベルがあるので、数字を 30 度ごとに配置します (360 / 12)。 数学の国では、円は 3 時に始まるので、正午は実際には正午です。 マイナス90度 そこから 270 度 (360 - 90).

別の変数を追加しましょう。 --_dを設定するために使用できます 文字盤の各数字の値。 値を 30 度ずつ増やして円を完成させます。

.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; }

OK、今こそ手を汚す時です 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、これを width & height 一瞬で数字の。 これまでの内容を見てみましょう。

エッジに沿って中心からずれた時間番号ラベルが付いた大きなトマト色の円。

これは間違いなく時計のように見えます! 各数値の左上隅が円の正しい位置に配置されていることがわかりますか? 各数値の位置を計算するときは、半径を「縮小」する必要があります。 我々はできる 差し引く 数値のサイズ (--_sz) 円の大きさから (--_w)、半径を計算する前に:

--_r: calc((var(--_w) - var(--_sz)) / 2);
丸みを帯びたエッジに沿って時間番号ラベルが付いた大きなトマト色の円。

ずっといい! よりエレガントに見えるように、色を変更しましょう。

暗い灰色の背景に数字の付いた白い時計の文字盤。 時計には腕がありません。

ここで止められる! 円の周りにテキストを配置するという目標を達成しましたね。 しかし、時、分、秒を表示する腕のない時計とは何でしょう?

そのために単一の CSS アニメーションを使用しましょう。 まず、マークアップにさらに XNUMX つの要素を追加しましょう。

<div class="clock"> <!-- after <time>-tags --> <span class="arm seconds"></span> <span class="arm minutes"></span> <span class="arm hours"></span> <span class="arm center"></span>
</div>

次に、XNUMX つのアームすべてに共通のマークアップをいくつか示します。 繰り返しますが、これのほとんどは、腕が絶対に配置され、それに応じて配置されていることを確認するだけです:

.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);
}

私たちは 同じアニメーション XNUMX つの腕すべてに:

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

唯一の違いは、個々のアームが XNUMX 回転するのにかかる時間です。 のために 時間アーム、 それはとります 12時間 フルターンする。 の animation-duration プロパティは、ミリ秒と秒単位の値のみを受け入れます。 43,200 秒 (60 seconds * 60 minutes * 12 hours).

animation: turn 43200s infinite;

それはとります 1の時間 分アーム フルターンする。 しかし、私たちはこれを マルチステップ アニメーション そのため、腕の間の動きは直線的ではなく、ずらしてあります。 60 分ごとに XNUMX つずつ、XNUMX のステップが必要です。

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

  秒針 is ほぼ同じ 分アームと同じですが、持続時間は 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;
}

現時点で開始したい場合はどうすればよいでしょうか。 JavaScript が少し必要です。

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" 文字盤に XNUMX つの新しいカスタム プロパティを設定して、負の値を設定します。 animation-delay、マテ・マルシャルコがしたように 彼が CSS のみの時計を共有したときを選択します。 getHours() JavaScipt のメソッド Date オブジェクトは 24 時間形式を使用しているため、 remainder オペレータ 12 時間形式に変換します。

CSS では、追加する必要があります。 animation-delay 同じように:

.minutes { animation-delay: var(--_dm, 0s); /* other styles */
} .hours { animation-delay: var(--_dh, 0s); /* other styles */
}

あともう一つだけ。 CSSの使用 @supports すでに作成したプロパティを使用すると、サポートしていないブラウザーにフォールバックを提供できます。 sin() & cos(). (ありがとう、テマニ・アフィフ!):

@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)))
  }
}

そして、ほら! 私たちの時計が完成しました! もう一度最後のデモです。 繰り返しますが、現時点では Firefox と Safari でのみサポートされています。

他に何ができますか?

ここをいじるだけですが、時計を円形の画像ギャラリーに置き換えるには、 <time> タグ付き <img> 次に、幅を更新します(--_w) と半径 (--_r)値:

もうXNUMXつ試してみましょう。 先ほど、時計が現代美術の実験のように見えることを述べました。 それを利用して、先日アート ギャラリーでポスター (残念ながら購入しませんでした) で見たパターンを再現することができます。 思い出すと、それは「月」と呼ばれ、円を形成する点の集まりで構成されていました。

さまざまなアースカラーの小さな塗りつぶされた円の束から形成された大きな円。

円は特定の順序に従っていないため、今回は順序なしリストを使用します。 すべてのリスト項目をマークアップに入れるつもりはありません。 代わりに、JavaScript を挿入して、最終結果を操作するために使用できるいくつかのコントロールを追加しましょう。

コントロールは範囲入力 (<input type="range">) これを <form> を聞いて input イベント。

<form id="controls"> <fieldset> <label>Number of rings <input type="range" min="2" max="12" value="10" id="rings" /> </label> <label>Dots per ring <input type="range" min="5" max="12" value="7" id="dots" /> </label> <label>Spread <input type="range" min="10" max="40" value="40" id="spread" /> </label> </fieldset>
</form>

このメソッドを「入力」で実行します。これにより、一連の <li> 次数を持つ要素 (--_d) 前に使用した変数をそれぞれに適用しました。 radius 変数を再利用することもできます (--_r)。

また、ドットを異なる色にしたいです。 それでは、ランダム化しましょう(まあ、そうではありません 完全に 各リスト項目の HSL カラー値をランダム化して、新しい CSS 変数として保存します。 --_bgc:

const update = () => { let s = ""; for (let i = 1; i <= rings.valueAsNumber; i++) { const r = spread.valueAsNumber * i; const theta = coords(dots.valueAsNumber * i); for (let j = 0; j < theta.length; j++) { s += `<li style="--_d:${theta[j]};--_r:${r}px;--_bgc:hsl(${random( 50, 25 )},${random(90, 50)}%,${random(90, 60)}%)"></li>`; } } app.innerHTML = s;
}

  random() メソッドは、定義された数値範囲内の値を選択します。

const random = (max, min = 0, f = true) => f ? Math.floor(Math.random() * (max - min) + min) : Math.random() * max;

以上です。 JavaScript を使用してマークアップをレンダリングしますが、レンダリングされるとすぐに、JavaScript は必要ありません。 の sin() & cos() 関数は、すべてのドットを適切な場所に配置するのに役立ちます。

最終的な考え

円の周りに物を配置することは、次のような三角関数の機能を示す非常に基本的な例です。 sin() & cos()。 しかし、それは 本当に 古い回避策に新しい解決策を提供する最新の CSS 機能が得られるのは素晴らしいことです。特にブラウザーのサポートが Chrome と Edge に導入されるにつれて、より興味深く、複雑で、創造的なユースケースが見られると確信しています。

タイムスタンプ:

より多くの CSSトリック