Óra létrehozása az új CSS sin() és cos() trigonometriai függvényekkel

Óra létrehozása az új CSS sin() és cos() trigonometriai függvényekkel

Forrás csomópont: 1999799

Itt vannak a CSS trigonometriai függvények! Nos, akkor azok, ha a Firefox és a Safari legújabb verzióit használja. Az ilyen matematikai erő birtoklása a CSS-ben egy csomó lehetőséget nyit meg. Ebben az oktatóanyagban arra gondoltam, hogy a lábujjainkat a vízbe mártjuk, hogy megérezzük az újabb funkciókat: sin() és a cos().

Vannak más trigonometriai függvények is a folyamatban – többek között tan() – akkor miért csak arra koncentrálsz sin() és a cos()? Történetesen tökéletesen megfelelnek az általam elképzelt ötletnek, vagyis a szövegnek egy kör széle mentén történő elhelyezésére. Erről már itt volt szó a CSS-Tricks-en Chris megosztott egy megközelítést, amely Sass mixint használ. Ez hat évvel ezelőtt volt, szóval adjuk neki a vérzéses kezelést.

Íme, mire gondolok. Ismét csak a Firefox és a Safari támogatja jelenleg:

Tehát ez nem pontosan olyan, mintha a szavak kör alakúak lennének, hanem szövegkaraktereket helyezünk el a kör mentén, hogy óraszámlapot képezzünk. Íme néhány jelölés, amellyel elindíthatjuk a dolgokat:

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

Ezután itt van néhány szuper alapstílus a .clock-face tartály. Úgy döntöttem, hogy a <time> címkével a datetime tulajdonság. 

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

Kicsit feldíszítettem a dolgokat, de csak azért, hogy megkapjuk az alapformát és a háttérszínt, hogy lássuk, mit csinálunk. Figyeljük meg, hogyan mentjük el a width érték a CSS változó. Később ezt használjuk. Egyelőre nem sokat kell nézni:

Paradicsom színű nagy kör, a bal oldalon függőleges számsorral 1-12 között.

Valami modern művészeti kísérletnek tűnik, igaz? Vezessünk be egy új változót, --_r, a körök tárolásához sugár, ami egyenlő a kör szélességének felével. Ily módon, ha a szélesség (--_w) változik, a sugár értéke (--_r) is frissülni fog – egy másik CSS matematikai függvénynek köszönhetően, calc():

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

Most egy kis matek. Egy kör 360 fokos. 12 címkénk van az óránkon, ezért szeretnénk a számokat 30 fokonként elhelyezni (360 / 12). A matekföldön egy kör 3 órakor kezdődik, tehát valójában dél mínusz 90 fok ebből, ami 270 fok (360 - 90).

Adjunk hozzá még egy változót, --_d, amellyel beállíthatjuk a fokozat értéket az óra számlapján lévő egyes számokhoz. Az értékeket 30 fokkal növeljük, hogy teljes legyen a körünk:

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

Rendben, itt az ideje, hogy bemocskoljuk a kezünket sin() és a cos() funkciókat! Azt szeretnénk tenni, hogy ezek segítségével megkapjuk az egyes számok X és Y koordinátáit, hogy megfelelően el tudjuk helyezni őket az óra számlapja körül.

Az X koordináta képlete a következő radius + (radius * cos(degree)). Csatlakoztassuk az újunkhoz --_x változó:

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

Az Y koordináta képlete a következő radius + (radius * sin(degree)). Van mit kiszámolnunk:

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

A számok beállításához el kell végeznünk néhány háztartási dolgot, ezért tegyünk néhány alapvető stílust rajtuk, hogy megbizonyosodjunk arról, hogy pontosan a mi koordinátáinkkal vannak elhelyezve:

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

Közlemény --_sz, amelyet a width és a height a számok egy pillanat alatt. Lássuk, mi van eddig.

Paradicsom színű nagy kör, szélén nem középen óraszámcímkékkel.

Ez határozottan úgy néz ki, mint egy óra! Látja, hogyan helyezkedik el az egyes számok bal felső sarka a megfelelő helyen a kör körül? Az egyes számok pozícióinak kiszámításakor „zsugorítanunk” kell a sugarat. Tudunk levonási egy szám mérete (--_sz) a kör méretétől (--_w), mielőtt kiszámítanánk a sugarat:

--_r: calc((var(--_w) - var(--_sz)) / 2);
Nagy paradicsom színű kör, lekerekített éle mentén óraszámcímkékkel.

Sokkal jobb! Változtassuk meg a színeket, így elegánsabbnak tűnik:

Egy fehér óralap számokkal sötétszürke háttér előtt. Az órának nincsenek karjai.

Itt megállhatnánk! Elértük azt a célt, hogy a szöveget körbe helyezzük, igaz? De mit ér az óra karok nélkül, amelyek órákat, perceket és másodperceket mutatnak?

Ehhez használjunk egyetlen CSS-animációt. Először adjunk hozzá három további elemet a jelölésünkhöz,

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

Aztán néhány közös jelölés mindhárom karra. Ennek nagy része ismét csak arról szól, hogy a karok pontosan legyenek elhelyezve és megfelelően helyezkedjenek el:

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

Használjuk a ugyanaz az animáció mindhárom karra:

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

Az egyetlen különbség az az idő, amikor az egyes karok teljes fordulatot tesznek. A óra kar, kell 12 óra teljes fordulatot tenni. A animation-duration tulajdonság csak ezredmásodpercben és másodpercben fogadja el az értékeket. Maradjunk a másodperceknél, ami 43,200 XNUMX másodperc (60 seconds * 60 minutes * 12 hours).

animation: turn 43200s infinite;

Szükség van 1 óra az perc kar teljes fordulatot tenni. De szeretnénk, ha ez a többlépcsős animáció tehát a karok közötti mozgás inkább lépcsőzetes, mint lineáris. 60 lépésre lesz szükségünk, percenként egyet:

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

A másodperc kar is közel azonos mint a perc kar, de az időtartam 60 perc helyett 60 másodperc:

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

Frissítsük a közös stílusokban létrehozott tulajdonságokat:

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

Mi van, ha a jelenlegi időpontban szeretnénk kezdeni? Szükségünk van egy kis JavaScriptre:

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`);

Hozzáadtam id="app" az óra számlapjára, és állítson be rajta két új egyéni tulajdonságot, amelyek negatívot állítanak be animation-delay, ahogy Mate Marschalko tette amikor megosztott egy csak CSS-órát Az getHours() a JavaScipt módszere Date objektum a 24 órás formátumot használja, ezért használjuk a remainder operátor 12 órás formátumra konvertálni.

A CSS-ben hozzá kell adnunk a animation-delay is:

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

Csak még egy dolog. CSS használata @supports és a már létrehozott tulajdonságokat, tartalékot tudunk biztosítani azon böngészőknek, amelyek nem támogatják sin() és a cos(). (Köszönöm, 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)))
  }
}

És íme! Elkészült az óránk! Itt az utolsó demó még egyszer. Megint csak a Firefox és a Safari támogatja jelenleg.

Mit tehetnénk még?

Csak vacakolok itt, de gyorsan kör alakú képgalériává alakíthatjuk óránkat, ha lecseréljük a <time> címkékkel <img> majd a szélesség frissítése (--_w) és sugár (--_r) értékek:

Próbáljunk még egyet. Korábban említettem, hogy az óra úgy nézett ki, mint egy modern művészeti kísérlet. Ebbe belehajolhatunk, és újraalkothatunk egy mintát, amit a minap egy művészeti galériában egy plakáton láttam (amit sajnos nem vettem meg). Emlékeim szerint „Holdnak” hívták, és egy csomó pontból állt, amelyek kört alkottak.

Egy nagy kör egy csomó kisebb töltött körből alakult ki különböző földtónus színű.

Ezúttal egy rendezetlen listát fogunk használni, mivel a körök nem követnek bizonyos sorrendet. Nem is fogjuk az összes listaelemet a jelölésbe helyezni. Ehelyett illesszük be őket JavaScripttel, és adjunk hozzá néhány vezérlőt, amellyel manipulálhatjuk a végeredményt.

A vezérlők tartomány bemenetek (<input type="range">) amelyet becsomagolunk a <form> és hallgasd meg a input esemény.

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

Ezt a metódust a „bemeneten” fogjuk futtatni, ami egy csomót hoz létre <li> fokozatú elemek (--_d) változó, amelyet korábban használtunk mindegyikre alkalmazva. A sugárváltozónkat (--_r).

Azt is szeretném, hogy a pontok különböző színűek legyenek. Tehát véletlenszerűvé tesszük (na jó, nem teljesen véletlenszerű) a HSL színértéket minden listaelemhez, és tárolja azt új CSS-változóként, --_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;
}

A random() metódus egy meghatározott számtartományon belül választ ki egy értéket:

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

És ez az. A jelölés megjelenítéséhez JavaScriptet használunk, de amint megjelenik, már nincs rá szükségünk. A sin() és a cos() A funkciók segítenek abban, hogy az összes pontot a megfelelő helyre helyezzük.

Záró gondolatok

A dolgok kör körüli elhelyezése egy nagyon egyszerű példa a trigonometriai függvények, például a képességek bemutatására sin() és a cos(). De ez tényleg jó, hogy olyan modern CSS-funkciókat kapunk, amelyek új megoldásokat kínálnak a régi megoldásokra. Biztos vagyok benne, hogy sokkal érdekesebb, összetettebb és kreatívabb felhasználási eseteket fogunk látni, különösen, ha a böngésző támogatása érkezik a Chrome-hoz és az Edge-hez.

Időbélyeg:

Még több CSS trükkök