CSS trigonometriefuncties zijn er! Welnu, dat is het geval als u de nieuwste versies van Firefox en Safari gebruikt. Het hebben van dit soort wiskundige kracht in CSS opent een hele reeks mogelijkheden. In deze tutorial dacht ik dat we onze tenen in het water zouden dopen om een idee te krijgen van een paar van de nieuwere functies: sin()
En cos()
.
Er zitten nog andere trigonometrische functies in de pijplijn, waaronder tan()
– dus waarom alleen focussen op sin()
En cos()
? Ze passen excellent bij het idee dat ik in gedachten heb, namelijk tekst langs de rand van een cirkel plaatsen. Dat is hier behandeld op CSS-Tips wanneer Chris deelde een benadering die een Sass-mix gebruikt. Dat was zes jaar geleden, dus laten we het een bloedstollende behandeling geven.
Dit is wat ik in gedachten heb. Nogmaals, het wordt momenteel alleen ondersteund in Firefox en Safari:
Het is dus niet precies zoals woorden die een cirkelvorm vormen, maar we plaatsen teksttekens langs de cirkel om een wijzerplaat te vormen. Hier is wat opmaak die we kunnen gebruiken om dingen op gang te brengen:
<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>
Vervolgens zijn hier enkele tremendous fundamental stijlen voor de .clock-face
container. Ik besloot om de <time>
label met een datetime
attribuut.
.clock {
--_ow: clamp(5rem, 60vw, 40rem);
--_w: 88cqi;
aspect-ratio: 1;
background-color: tomato;
border-radius: 50%;
container-type: inline;
show: grid;
peak: var(--_ow);
place-content: heart;
place: relative;
width var(--_ow);
}
Ik heb de dingen daar een beetje versierd, maar alleen om de basisvorm en achtergrondkleur te krijgen om ons te helpen zien wat we aan het doen zijn. Let op hoe we de width
waarde in een CSS-variabele. Die gebruiken we later. Tot nu toe niet veel om naar te kijken:

Het lijkt op een soort fashionable kunstexperiment, toch? Laten we een nieuwe variabele introduceren, --_r
om de cirkels op te slaan straal, wat gelijk is aan de helft van de breedte van de cirkel. Op deze manier, als de breedte (--_w
) verandert, verandert de straalwaarde (--_r
) wordt ook bijgewerkt — dankzij een andere CSS-wiskundige functie, calc()
:
.clock {
--_w: 300px;
--_r: calc(var(--_w) / 2);
/* remainder of kinds */
}
Nu een beetje wiskunde. Een cirkel is 360 graden. We hebben 12 labels op onze klok, dus we willen de cijfers elke 30 graden plaatsen (360 / 12
). In wiskundeland begint een cirkel om 3 uur, dus eigenlijk is het middag minus 90 graden daarvan, dat is 270 graden (360 - 90
).
Laten we nog een variabele toevoegen, --_d
die we kunnen gebruiken om a in te stellen rang waarde voor elk nummer op de wijzerplaat. We gaan de waarden met 30 graden verhogen om onze cirkel te voltooien:
.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, nu is het tijd om onze handen vuil te maken met de sin()
En cos()
functies! Wat we willen doen, is ze gebruiken om de X- en Y-coördinaten voor elk getal te krijgen, zodat we ze op de juiste manier rond de wijzerplaat kunnen plaatsen.
De formule voor de X-coördinaat is radius + (radius * cos(diploma))
. Laten we dat aansluiten op onze nieuwe --_x
variabele:
--_x: calc(var(--_r) + (var(--_r) * cos(var(--_d))));
De formule voor de Y-coördinaat is radius + (radius * sin(diploma))
. We hebben wat we nodig hebben om dat te berekenen:
--_y: calc(var(--_r) + (var(--_r) * sin(var(--_d))));
Er zijn een paar huishoudelijke dingen die we moeten doen om de nummers in te stellen, dus laten we ze wat basisstijlen geven om ervoor te zorgen dat ze absoluut gepositioneerd en geplaatst zijn met onze coördinaten:
.clock-face time {
--_x: calc(var(--_r) + (var(--_r) * cos(var(--_d))));
--_y: calc(var(--_r) + (var(--_r) * sin(var(--_d))));
--_sz: 12cqi;
show: grid;
peak: var(--_sz);
left: var(--_x);
place-content: heart;
place: absolute;
prime: var(--_y);
width: var(--_sz);
}
Kennisgeving --_sz
die we zullen gebruiken voor de width
En peak
van de nummers in een oogwenk. Laten we eens kijken wat we tot nu toe hebben.

Dit lijkt zeker meer op een klok! Zie je hoe de linkerbovenhoek van elk nummer op de juiste plaats rond de cirkel staat? We moeten de straal “verkleinen” bij het berekenen van de posities voor elk nummer. We kunnen aftrekken de grootte van een getal (--_sz
) van de grootte van de cirkel (--_w
), voordat we de straal berekenen:
--_r: calc((var(--_w) - var(--_sz)) / 2);

Veel beter! Laten we de kleuren veranderen, zodat het er eleganter uitziet:

We zouden hier kunnen stoppen! We hebben het doel bereikt om tekst rond een cirkel te plaatsen, toch? Maar wat is een klok zonder armen om uren, minuten en seconden aan te geven?
Laten we daarvoor een enkele CSS-animatie gebruiken. Laten we eerst nog drie elementen aan onze opmaak toevoegen,
<div class="clock">
<!-- after <time>-tags -->
<span class="arm seconds"></span>
<span class="arm minutes"></span>
<span class="arm hours"></span>
<span class="arm heart"></span>
</div>
Dan een gemeenschappelijke opmaak voor alle drie de armen. Nogmaals, het meeste hiervan is om ervoor te zorgen dat de armen absoluut gepositioneerd en dienovereenkomstig geplaatst zijn:
.arm {
background-color: var(--_abg);
border-radius: calc(var(--_aw) * 2);
show: block;
peak: var(--_ah);
left: calc((var(--_w) - var(--_aw)) / 2);
place: absolute;
prime: calc((var(--_w) / 2) - var(--_ah));
remodel: rotate(0deg);
transform-origin: backside;
width: var(--_aw);
}
We gebruiken de dezelfde animatie voor alle drie de armen:
@keyframes flip {
to {
remodel: rotate(1turn);
}
}
Het enige verschil is de tijd die de individuele armen nodig hebben om een volledige draai te maken. Voor de uur armhet duurt 12 uren om een volledige draai te maken. De animation-duration
eigenschap accepteert alleen waarden in milliseconden en seconden. Laten we het bij seconden houden, dat is 43.200 seconden (60 seconds * 60 minutes * 12 hours
).
animation: flip 43200s infinite;
Het duurt 1 uur voor de minuten arm om een volledige draai te maken. Maar we willen dat dit een animatie in meerdere stappen dus de beweging tussen de armen is verspringend in plaats van lineair. We hebben 60 stappen nodig, één voor elke minuut:
animation: flip 3600s steps(60, finish) infinite;
De seconden arm is bijna hetzelfde als de minutenarm, maar de duur is 60 seconden in plaats van 60 minuten:
animation: flip 60s steps(60, finish) infinite;
Laten we de eigenschappen bijwerken die we in de algemene stijlen hebben gemaakt:
.seconds {
--_abg: hsl(0, 5%, 40%);
--_ah: 145px;
--_aw: 2px;
animation: flip 60s steps(60, finish) infinite;
}
.minutes {
--_abg: #333;
--_ah: 145px;
--_aw: 6px;
animation: flip 3600s steps(60, finish) infinite;
}
.hours {
--_abg: #333;
--_ah: 110px;
--_aw: 6px;
animation: flip 43200s linear infinite;
}
Wat als we op het huidige tijdstip willen beginnen? We hebben een klein beetje JavaScript nodig:
const time = new Date();
const hour = -3600 * (time.getHours() % 12);
const minutes = -60 * time.getMinutes();
app.fashion.setProperty('--_dm', `${minutes}s`);
app.fashion.setProperty('--_dh', `${(hour+minutes)}s`);
Ik heb toegevoegd id="app"
naar de wijzerplaat en stel er twee nieuwe aangepaste eigenschappen op in die een negatief instellen animation-delay
zoals Mate Marschalko deed toen hij een klok met alleen CSS deelde. De getHours()
methode van JavaScipt Date
object gebruikt het 24-uurs formaat, dus gebruiken we de remainder
exploitant om het om te zetten in 12-uurs formaat.
In de CSS moeten we de animation-delay
ook:
.minutes {
animation-delay: var(--_dm, 0s);
/* different kinds */
}
.hours {
animation-delay: var(--_dh, 0s);
/* different kinds */
}
Nog een ding. CSS gebruiken @helps
en de eigenschappen die we al hebben gemaakt, kunnen we een terugval bieden naar browsers die dit niet ondersteunen sin()
En cos()
. (Bedankt, Temani Afif!):
@helps not (left: calc(1px * cos(45deg))) {
time {
left: 50% !essential;
prime: 50% !essential;
remodel: translate(-50%,-50%) rotate(var(--_d)) translate(var(--_r)) rotate(calc(-1*var(--_d)))
}
}
En voila! Onze klok is klaar! Hier is de laatste demo nog een keer. Nogmaals, het wordt momenteel alleen ondersteund in Firefox en Safari.
Wat anders kunnen we doen?
Gewoon wat rommelen hier, maar we kunnen onze klok snel veranderen in een cirkelvormige afbeeldingengalerij door de <time>
labels met <img>
vervolgens de breedte bijwerken (--_w
) en straal (--_r
) waarden:
Laten we er nog een proberen. Ik noemde eerder hoe de klok eruitzag als een fashionable kunstexperiment. We kunnen daarop ingaan en een patroon opnieuw creëren dat ik onlangs op een poster zag (die ik helaas niet heb gekocht) in een kunstgalerie. Voor zover ik me herinner, heette het “Maan” en bestond het uit een aantal stippen die een cirkel vormden.

We gebruiken deze keer een ongeordende lijst omdat de cirkels geen bepaalde volgorde volgen. We gaan niet eens alle lijstitems in de opmaak plaatsen. Laten we ze in plaats daarvan injecteren met JavaScript en een paar bedieningselementen toevoegen die we kunnen gebruiken om het eindresultaat te manipuleren.
De bedieningselementen zijn bereikingangen (<enter sort="vary">)
die we inpakken in een <type>
en luister naar de enter
evenement.
<type id="controls">
<fieldset>
<label>Variety of rings
<enter sort="vary" min="2" max="12" worth="10" id="rings" />
</label>
<label>Dots per ring
<enter sort="vary" min="5" max="12" worth="7" id="dots" />
</label>
<label>Unfold
<enter sort="vary" min="10" max="40" worth="40" id="unfold" />
</label>
</fieldset>
</type>
We zullen deze methode uitvoeren op “enter”, wat een heleboel zal creëren <li>
elementen met de graad (--_d
) variabele die we eerder gebruikten toegepast op elke variabele. We kunnen ook onze radiusvariabele hergebruiken (--_r
) .
Ik wil ook dat de stippen verschillende kleuren hebben. Dus laten we randomiseren (nou ja, niet volledig gerandomiseerd) de HSL-kleurwaarde voor elk lijstitem en sla deze op als een nieuwe CSS-variabele, --_bgc
:
const replace = () => {
let s = "";
for (let i = 1; i <= rings.valueAsNumber; i++) {
const r = unfold.valueAsNumber * i;
const theta = coords(dots.valueAsNumber * i);
for (let j = 0; j < theta.size; j++) {
s += `<li fashion="--_d:${theta(j)};--_r:${r}px;--_bgc:hsl(${random(
50,
25
)},${random(90, 50)}%,${random(90, 60)}%)"></li>`;
}
}
app.innerHTML = s;
}
De random()
methode kiest een waarde binnen een gedefinieerd bereik van getallen:
const random = (max, min = 0, f = true) => f ? Math.ground(Math.random() * (max - min) + min) : Math.random() * max;
En dat is het. We gebruiken JavaScript om de markup weer te geven, maar zodra het wordt weergegeven, hebben we het niet echt nodig. De sin()
En cos()
functies helpen ons alle stippen op de juiste plek te plaatsen.
Laatste gedachten
Dingen rond een cirkel plaatsen is een vrij eenvoudig voorbeeld om de krachten van trigonometrische functies zoals te demonstreren sin()
En cos()
. Maar het is Echt cool dat we moderne CSS-functies krijgen die nieuwe oplossingen bieden voor oude tijdelijke oplossingen. Ik weet zeker dat we veel interessantere, complexere en creatievere use-cases zullen zien, vooral omdat browserondersteuning naar Chrome en Edge komt.