Hitro iskanje tukaj na CSS-Tricks pokaže, na koliko različnih načinov lahko pristopite k koledarjem. Nekateri kažejo, kako CSS Grid lahko učinkovito ustvari postavitev. Nekateri poskusi vključite dejanske podatke v mešanico. Nekatere zanašati se na okvir pomagati pri upravljanju države.
Pri izdelavi komponente koledarja je veliko premislekov - veliko več kot je zajeto v člankih, ki sem jih povezal. Če dobro pomislite, so koledarji polni nians, od upravljanja časovnih pasov in formatov datumov do lokalizacije in celo zagotavljanja, da datumi tečejo iz enega meseca v drugega ... in to še preden se sploh lotimo dostopnosti in dodatnih pomislekov o postavitvi, odvisno od tega, kje je koledar se prikaže in še kaj.
Mnogi razvijalci se bojijo Date()
predmet in se držite starejših knjižnic, kot je moment.js
. Toda čeprav je veliko "gotcha", ko gre za datume in oblikovanje, ima JavaScript veliko kul API-jev in stvari, ki vam lahko pomagajo!
Tukaj ne želim ponovno ustvariti kolesa, vendar vam bom pokazal, kako lahko dobimo prekleto dober koledar z vanilijevim JavaScriptom. Preučili bomo dostopnost, ki uporablja pomensko oznako in je prijazen bralniku zaslona <time>
-oznake — kot tudi internacionalizacija in Oblikovanje, uporabljati Intl.Locale
, Intl.DateTimeFormat
in Intl.NumberFormat
-API.
Z drugimi besedami, izdelujemo koledar ... samo brez dodatnih odvisnosti, ki jih običajno vidite v vadnici, kot je ta, in z nekaterimi niansami, ki jih običajno ne vidite. In upam, da boste med tem procesom pridobili novo vrednost za novejše stvari, ki jih lahko naredi JavaScript, hkrati pa boste dobili idejo o vrstah stvari, ki mi pridejo na misel, ko sestavljam nekaj takega.
Najprej poimenovanje
Kako naj imenujemo našo komponento koledarja? V mojem maternem jeziku bi se temu reklo »kalender element«, zato ga uporabimo in skrajšajmo na »Kal-El« — znan tudi kot Supermanovo ime na planetu Krypton.
Ustvarimo funkcijo, ki bo zagnala stvari:
function kalEl(settings = {}) { ... }
Ta metoda bo upodobila en sam mesec. Kasneje bomo to metodo poklicali iz [...Array(12).keys()]
upodabljati celo leto.
Začetni podatki in internacionalizacija
Ena od pogostih stvari, ki jih običajni spletni koledar počne, je, da poudari trenutni datum. Torej ustvarimo referenco za to:
const today = new Date();
Nato bomo ustvarili »konfiguracijski objekt«, ki ga bomo združili z neobveznim settings
predmet primarne metode:
const config = Object.assign( { locale: (document.documentElement.getAttribute('lang') || 'en-US'), today: { day: today.getDate(), month: today.getMonth(), year: today.getFullYear() } }, settings
);
Preverimo, ali je korenski element (<html>
) vsebuje a lang
-atribut z locale informacije; sicer se bomo vrnili k uporabi en-US
. To je prvi korak k internacionalizacijo koledarja.
Prav tako moramo določiti, kateri mesec naj bo prvotno prikazan, ko je koledar upodobljen. Zato smo podaljšali config
objekt s primarnim date
. Na ta način, če datum ni naveden v settings
predmet, bomo uporabili today
namesto tega referenca:
const date = config.date ? new Date(config.date) : today;
Potrebujemo malo več informacij za pravilno oblikovanje koledarja glede na lokalne nastavitve. Na primer, morda ne vemo, ali je prvi dan v tednu nedelja ali ponedeljek, odvisno od kraja. Če imamo informacije, super! Če pa ne, ga bomo posodobili z uporabo Intl.Locale
API. API ima a weekInfo
predmet ki vrne a firstDay
lastnina, ki nam brez kakršnih koli težav nudi točno to, kar iščemo. Prav tako lahko ugotovimo, kateri dnevi v tednu so dodeljeni weekend
:
if (!config.info) config.info = new Intl.Locale(config.locale).weekInfo || { firstDay: 7, weekend: [6, 7] };
Spet ustvarjamo rezerve. “Prvi dan” v tednu za en-US
je nedelja, zato je privzeta vrednost 7
. To je nekoliko zmedeno, saj getDay
Metoda v JavaScript vrne dneve kot [0-6]
, Kjer 0
je nedelja… ne sprašuj me zakaj. Konci tedna so torej sobota in nedelja [6, 7]
.
Preden smo imeli Intl.Locale
API in njegov weekInfo
po metodi je bilo precej težko ustvariti mednarodni koledar brez številnih **predmetov in nizov z informacijami o vsakem jeziku ali regiji. Dandanes je enostavno. Če vstopimo en-GB
, metoda vrne:
// en-GB
{ firstDay: 1, weekend: [6, 7], minimalDays: 4
}
V državi, kot je Brunej (ms-BN
), vikend je petek in nedelja:
// ms-BN
{ firstDay: 7, weekend: [5, 7], minimalDays: 1
}
Morda se sprašujete, kaj to minimalDays
lastnina je. To je tisto najmanj potrebnih dni v prvem tednu v mesecu, da se šteje kot polni teden. V nekaterih regijah je lahko samo en dan. Za druge lahko traja celih sedem dni.
Nato bomo ustvarili a render
metoda znotraj našega kalEl
-metoda:
const render = (date, locale) => { ... }
Še vedno potrebujemo nekaj več podatkov, s katerimi lahko delamo, preden karkoli upodabljamo:
const month = date.getMonth();
const year = date.getFullYear();
const numOfDays = new Date(year, month + 1, 0).getDate();
const renderToday = (year === config.today.year) && (month === config.today.month);
Zadnji je a Boolean
ki preverja, ali today
obstaja v mesecu, ki ga bomo upodobili.
Semantična oznaka
Čez trenutek se bomo poglobili v upodabljanje. Najprej pa se želim prepričati, da imajo podrobnosti, ki jih nastavimo, povezane semantične oznake HTML. Nastavitev tega takoj po izdelavi nam že na začetku omogoča prednosti dostopnosti.
Ovoj koledarja
Najprej imamo nesemantični ovoj: <kal-el>
. To je v redu, ker ni semantike <calendar>
oznako ali kaj podobnega. Če ne bi izdelovali elementa po meri, <article>
morda najbolj primeren element, saj bi koledar lahko stal na svoji strani.
Imena mesecev
O <time>
element bo za nas velik, saj pomaga prevesti datume v obliko, ki jo lahko bralniki zaslona in iskalniki natančneje in dosledneje razčlenijo. Na primer, tukaj je opisano, kako lahko prenesemo »januar 2023« v našo oznako:
<time datetime="2023-01">January <i>2023</i></time>
Imena dni
Vrstica nad datumi koledarja, ki vsebuje imena dni v tednu, je lahko težavna. Idealno je, če lahko napišemo polna imena za vsak dan – npr. nedelja, ponedeljek, torek itd. – vendar to lahko zavzame veliko prostora. Torej, skrajšajmo imena za zdaj znotraj <ol>
kjer je vsak dan a <li>
:
<ol> <li><abbr title="Sunday">Sun</abbr></li> <li><abbr title="Monday">Mon</abbr></li> <!-- etc. -->
</ol>
S CSS bi se lahko zapletli, da bi dobili najboljše iz obeh svetov. Na primer, če smo oznako spremenili nekoliko takole:
<ol> <li> <abbr title="S">Sunday</abbr> </li>
</ol>
...privzeto dobimo polna imena. Nato lahko polno ime »skrijemo«, ko zmanjka prostora, in prikažemo title
namesto tega atribut:
@media all and (max-width: 800px) { li abbr::after { content: attr(title); }
}
Vendar ne gremo tako, ker Intl.DateTimeFormat
API lahko pomaga tudi tukaj. To bomo obravnavali v naslednjem razdelku, ko bomo obravnavali upodabljanje.
Številke dni
Vsak datum v mreži koledarja dobi številko. Vsaka številka je postavka seznama (<li>
) na urejenem seznamu (<ol>
), in inline <time>
oznaka ovije dejansko številko.
<li> <time datetime="2023-01-01">1</time>
</li>
In čeprav še ne nameravam oblikovati stilov, vem, da bom želela nekako stilizirati datumske številke. To je možno, kot je, vendar želim tudi, da bi lahko številke delovnih dni oblikoval drugače kot številke ob koncu tedna, če bi bilo treba. Torej, bom vključil data-*
lastnosti posebej za to: data-weekend
in data-today
.
Številke tedna
V letu je 52 tednov, včasih 53. Čeprav ni zelo pogosto, je lahko lepo prikazati številko za določen teden v koledarju za dodaten kontekst. Všeč mi je, da ga imam zdaj, čeprav ga ne preneham uporabljati. Vendar ga bomo popolnoma uporabili v tej vadnici.
Uporabili bomo a data-weeknumber
kot slogovni kavelj in ga vključite v oznako za vsak datum, ki je prvi datum v tednu.
<li data-day="7" data-weeknumber="1" data-weekend=""> <time datetime="2023-01-08">8</time>
</li>
Rendering
Dajmo koledar na stran! To že vemo <kal-el>
je ime našega elementa po meri. Prva stvar, ki jo moramo konfigurirati, je nastaviti firstDay
lastnino na njem, tako da koledar ve, ali je prvi dan v tednu nedelja ali kateri drug dan.
<kal-el data-firstday="${ config.info.firstDay }">
Uporabili bomo predlogi literal predloge za upodobitev oznake. Za oblikovanje datumov za mednarodno občinstvo bomo uporabili Intl.DateTimeFormat
API, spet z uporabo locale
smo določili prej.
Mesec in leto
Ko pokličemo month
, lahko nastavimo, ali želimo uporabiti long
ime (npr. februar) ali short
ime (npr. feb.). Uporabimo long
ime, ker je to naslov nad koledarjem:
<time datetime="${year}-${(pad(month))}"> ${new Intl.DateTimeFormat( locale, { month:'long'}).format(date)} <i>${year}</i>
</time>
Imena delovnih dni
Za dneve v tednu, prikazane nad mrežo datumov, potrebujemo oba long
(npr. »nedelja«) in short
(skrajšana, tj. »Sonce«) imena. Tako lahko uporabimo »kratko« ime, ko koledarju primanjkuje prostora:
Intl.DateTimeFormat([locale], { weekday: 'long' })
Intl.DateTimeFormat([locale], { weekday: 'short' })
Ustvarimo majhno pomožno metodo, ki olajša klic vsakega od njih:
const weekdays = (firstDay, locale) => { const date = new Date(0); const arr = [...Array(7).keys()].map(i => { date.setDate(5 + i) return { long: new Intl.DateTimeFormat([locale], { weekday: 'long'}).format(date), short: new Intl.DateTimeFormat([locale], { weekday: 'short'}).format(date) } }) for (let i = 0; i < 8 - firstDay; i++) arr.splice(0, 0, arr.pop()); return arr;
}
Tukaj je opisano, kako to prikličemo v predlogi:
<ol> ${weekdays(config.info.firstDay,locale).map(name => ` <li> <abbr title="${name.long}">${name.short}</abbr> </li>`).join('') }
</ol>
Številke dni
In končno dnevi, zaviti v <ol>
Element:
${[...Array(numOfDays).keys()].map(i => { const cur = new Date(year, month, i + 1); let day = cur.getDay(); if (day === 0) day = 7; const today = renderToday && (config.today.day === i + 1) ? ' data-today':''; return ` <li data-day="${day}"${today}${i === 0 || day === config.info.firstDay ? ` data-weeknumber="${new Intl.NumberFormat(locale).format(getWeek(cur))}"`:''}${config.info.weekend.includes(day) ? ` data-weekend`:''}> <time datetime="${year}-${(pad(month))}-${pad(i)}" tabindex="0"> ${new Intl.NumberFormat(locale).format(i + 1)} </time> </li>`
}).join('')}
Razčlenimo to:
- Ustvarimo "navidezno" matriko, ki temelji na spremenljivki "število dni", ki jo bomo uporabili za ponavljanje.
- Ustvarimo a
day
spremenljivka za trenutni dan v ponovitvi. - Odpravimo neskladje med
Intl.Locale
API ingetDay()
. - Če
day
je enakotoday
, dodamo adata-*
atribut. - Na koncu vrnemo
<li>
element kot niz z združenimi podatki. tabindex="0"
pri uporabi navigacije s tipkovnico naredi element osredotočen po vseh pozitivnih vrednostih tabindex (Opomba: morali bi nikoli dodajte pozitiven tabindex-values)
Da »podbijajte« številke v datetime
atribut, uporabljamo majhno pomožno metodo:
const pad = (val) => (val + 1).toString().padStart(2, '0');
Številka tedna
Še enkrat, "številka tedna" je mesto, kjer teden pade v 52-tedenskem koledarju. Tudi za to uporabljamo majhno pomožno metodo:
function getWeek(cur) { const date = new Date(cur.getTime()); date.setHours(0, 0, 0, 0); date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7); const week = new Date(date.getFullYear(), 0, 4); return 1 + Math.round(((date.getTime() - week.getTime()) / 86400000 - 3 + (week.getDay() + 6) % 7) / 7);
}
Tega nisem jaz napisal getWeek
-metoda. Gre za prečiščeno različico ta scenarij.
In to je to! Hvala za Intl.Locale
, Intl.DateTimeFormat
in Intl.NumberFormat
API-jev, lahko zdaj preprosto spremenimo lang
-atribut <html>
element za spreminjanje konteksta koledarja glede na trenutno regijo:
Oblikovanje koledarja
Morda se spomnite, kako so vsi dnevi samo en <ol>
z elementi seznama. Da bi jih oblikovali v berljiv koledar, se potopimo v čudoviti svet mreže CSS. Pravzaprav lahko isto mrežo preoblikujemo iz začetno predlogo koledarja tukaj na CSS-Tricks, vendar je nekoliko posodobil z :is()
relacijski psevdo za optimizacijo kode.
Upoštevajte, da na poti definiram nastavljive spremenljivke CSS (in jim dodam predpono ---kalel-
da bi se izognili konfliktom).
kal-el :is(ol, ul) { display: grid; font-size: var(--kalel-fz, small); grid-row-gap: var(--kalel-row-gap, .33em); grid-template-columns: var(--kalel-gtc, repeat(7, 1fr)); list-style: none; margin: unset; padding: unset; position: relative;
}
Narišimo obrobe okrog datumskih številk, da jih vizualno ločimo:
kal-el :is(ol, ul) li { border-color: var(--kalel-li-bdc, hsl(0, 0%, 80%)); border-style: var(--kalel-li-bds, solid); border-width: var(--kalel-li-bdw, 0 0 1px 0); grid-column: var(--kalel-li-gc, initial); text-align: var(--kalel-li-tal, end); }
Mreža s sedmimi stolpci deluje dobro, ko je prvi dan v mesecu Prav tako prvi dan v tednu za izbrano lokacijo). Ampak to je prej izjema kot pravilo. Največkrat bomo morali prvi dan v mesecu premakniti na drug dan v tednu.
Zapomnite si vse dodatke data-*
atributov, ki smo jih definirali pri pisanju naše oznake? Te lahko zaskočimo, da posodobimo kateri stolpec mreže (--kalel-li-gc
) prva številka meseca je postavljena na:
[data-firstday="1"] [data-day="3"]:first-child { --kalel-li-gc: 1 / 4;
}
V tem primeru se raztezamo od prvega stolpca mreže do četrtega stolpca mreže – kar bo samodejno »potisnilo« naslednji element (2. dan) v peti stolpec mreže in tako naprej.
Dodajmo malo stila "trenutnemu" datumu, da bo izstopal. To so samo moji stili. Tukaj lahko počneš, kar hočeš.
[data-today] { --kalel-day-bdrs: 50%; --kalel-day-bg: hsl(0, 86%, 40%); --kalel-day-hover-bgc: hsl(0, 86%, 70%); --kalel-day-c: #fff;
}
Všeč mi je zamisel, da bi številke datumov za vikende oblikovali drugače kot za delavnike. Za oblikovanje teh bom uporabil rdečkasto barvo. Upoštevajte, da lahko dosežemo :not()
psevdorazred, da jih izberete, trenutni datum pa pustite pri miru:
[data-weekend]:not([data-today]) { --kalel-day-c: var(--kalel-weekend-c, hsl(0, 86%, 46%));
}
Oh, in ne pozabimo na številke tednov, ki so pred številko prvega datuma vsakega tedna. Uporabili smo a data-weeknumber
v oznaki za to, vendar številke dejansko ne bodo prikazane, razen če jih razkrijemo s CSS, kar lahko storimo na ::before
psevdoelement:
[data-weeknumber]::before { display: var(--kalel-weeknumber-d, inline-block); content: attr(data-weeknumber); position: absolute; inset-inline-start: 0; /* additional styles */
}
Na tej točki smo tehnično končali! Upodobimo lahko koledarsko mrežo, ki prikazuje datume za trenutni mesec, skupaj s premisleki o lokalizaciji podatkov po področnih nastavitvah in zagotavljanju, da koledar uporablja pravilno semantiko. In vse, kar smo uporabili, je bil JavaScript in CSS!
Ampak vzemimo to še en korak...
Upodabljanje celega leta
Morda morate prikazati celotno leto datumov! Torej, namesto upodabljanja trenutnega meseca, boste morda želeli prikazati vse mesečne mreže za tekoče leto.
No, dobra stvar pri pristopu, ki ga uporabljamo, je, da lahko pokličemo render
metodo tolikokrat, kot želimo, in samo spremenimo celo število, ki identificira mesec na vsaki instanci. Pokličimo ga 12-krat glede na tekoče leto.
tako preprosto kot klicanje render
-metoda 12-krat in samo spremenite celo število za month
- i
:
[...Array(12).keys()].map(i => render( new Date(date.getFullYear(), i, date.getDate()), config.locale, date.getMonth() )
).join('')
Verjetno je dobra ideja ustvariti nov nadrejeni ovoj za upodobljeno leto. Vsaka koledarska mreža je a <kal-el>
element. Pokličimo nov nadrejeni ovoj <jor-el>
, Kjer Jor-El je ime Kal-Elovega očeta.
<jor-el id="app" data-year="true"> <kal-el data-firstday="7"> <!-- etc. --> </kal-el> <!-- other months -->
</jor-el>
Lahko uporabimo <jor-el>
ustvariti mrežo za naše mreže. Torej meta!
jor-el { background: var(--jorel-bg, none); display: var(--jorel-d, grid); gap: var(--jorel-gap, 2.5rem); grid-template-columns: var(--jorel-gtc, repeat(auto-fill, minmax(320px, 1fr))); padding: var(--jorel-p, 0);
}
Končni demo
Bonus: Koledar konfetov
Prebral sem odlično knjigo z naslovom Izdelava in razbijanje mreže prejšnji dan in naletel na ta čudovit "novoletni plakat":
Mislil sem, da bi lahko naredili nekaj podobnega, ne da bi spremenili karkoli v HTML ali JavaScript. Vzel sem si svobodo vključiti polna imena mesecev in številke namesto imen dni, da bo bolj berljivo. Uživajte!
- Distribucija vsebine in PR s pomočjo SEO. Okrepite se še danes.
- Platoblockchain. Web3 Metaverse Intelligence. Razširjeno znanje. Dostopite tukaj.
- vir: https://css-tricks.com/making-calendars-with-accessibility-and-internationalization-in-mind/
- : je
- $GOR
- 1
- 11
- 2023
- 7
- 8
- 9
- 98
- a
- Sposobna
- O meni
- o IT
- nad
- absolutna
- dostopnost
- natančno
- dejansko
- Dodatne
- po
- vsi
- sam
- že
- in
- API
- API-ji
- aplikacija
- apreciacija
- pristop
- primerno
- SE
- okoli
- Array
- članki
- AS
- dodeljena
- povezan
- At
- lastnosti
- Občinstvo
- samodejno
- izogniti
- ozadje
- temeljijo
- BE
- lepa
- ker
- pred
- Prednosti
- BEST
- med
- Big
- Bit
- Knjiga
- Pasovi
- Break
- Breaking
- Building
- by
- Koledar
- klic
- se imenuje
- kliče
- CAN
- Lahko dobiš
- primeru
- spremenite
- spreminjanje
- preveriti
- Pregledi
- Koda
- barva
- Stolpec
- COM
- Skupno
- dokončanje
- komponenta
- zmedeno
- premislekov
- Vsebuje
- vsebina
- ozadje
- Cool
- bi
- država
- pokrov
- zajeti
- ustvarjajo
- Cross
- CSS
- Trenutna
- po meri
- datum
- Datum
- Termini
- dan
- Dnevi
- globlje
- privzeto
- privzeto
- opredeljen
- definiranje
- Odvisno
- Podrobnosti
- Ugotovite,
- Razvijalci
- drugačen
- neskladje
- zaslon
- dokument
- dont
- navzdol
- e
- vsak
- prej
- lažje
- izdaja
- element
- Motorji
- zagotoviti
- Celotna
- itd
- Eter (ETH)
- Tudi
- točno
- Primer
- odlično
- izjema
- obstaja
- dodatna
- Falling
- Falls
- daleč
- strah
- februar
- februar
- ugotovil
- končno
- konec
- prva
- fiksna
- Pretok
- za
- format
- Četrti
- Petek
- iz
- polno
- funkcija
- Gain
- vrzel
- dobili
- pridobivanje
- dana
- daje
- Go
- dogaja
- dobro
- Mreža
- mreža-predloga-stolpci
- Ravnanje
- Trdi
- Imajo
- ob
- pomoč
- Pomaga
- tukaj
- Označite
- upam,
- Kako
- HTML
- HTTPS
- i
- Ideja
- idealen
- identificira
- in
- vključujejo
- info
- Podatki
- začetna
- na začetku
- primer
- Namesto
- Facebook Global
- IT
- Izdelkov
- ponovitev
- ITS
- januar
- JavaScript
- samo en
- Vedite
- znano
- JEZIK
- jezik
- Zadnja
- postavitev
- odhodu
- Liberty
- knjižnice
- kot
- linije
- povezane
- Seznam
- malo
- Lokalizacija
- Long
- Poglej
- si
- Sklop
- Znamka
- IZDELA
- Izdelava
- upravljanje
- več
- Marža
- math
- max širine
- zgolj
- Spoji
- Metoda
- morda
- moti
- spremembe
- Trenutek
- Ponedeljek
- mesec
- mesecev
- več
- Najbolj
- Mozilla
- Ime
- Imena
- materni
- ostalo
- Nimate
- Novo
- Naslednja
- Nuance
- Številka
- številke
- predmet
- of
- on
- ONE
- na spletu
- Optimizirajte
- Ostalo
- drugi
- drugače
- lastne
- pad
- Stran
- planet
- načrtovanje
- platon
- Platonova podatkovna inteligenca
- PlatoData
- Stališče
- pozitiven
- mogoče
- precej
- primarni
- verjetno
- Postopek
- pravilno
- pravilno
- nepremičnine
- če
- Dajanje
- Hitri
- precej
- dosežejo
- Preberi
- rdečkasto
- okolica
- regije
- upodabljanje
- obvezna
- vrnitev
- vrne
- razkrivajo
- koren
- ROW
- Pravilo
- s
- Enako
- Iskalnik
- Iskalniki
- Oddelek
- izbran
- semantika
- ločena
- nastavite
- nastavitev
- nastavitve
- sedem
- premik
- Kratke Hlače
- shouldnt
- Prikaži
- pokazale
- Razstave
- Podoben
- Enostavno
- preprosto
- saj
- sam
- majhna
- So
- trdna
- nekaj
- Nekaj
- Vesolje
- posebej
- določeno
- stati
- stojala
- Začetek
- Država
- Korak
- Držijo
- Še vedno
- slog
- Super
- TAG
- Bodite
- Predloga
- da
- O
- Njih
- te
- stvar
- stvari
- Pomislite
- čas
- krat
- Naslov
- do
- danes
- skupaj
- POPOLNOMA
- proti
- prevesti
- Res
- Torek
- Navodila
- tipičen
- tipično
- unicode
- Nadgradnja
- posodobljeno
- us
- uporaba
- VAL
- vrednost
- Vrednote
- spremenljivke
- različica
- W3
- način..
- načini
- teden
- vikend
- Weeks
- Dobro
- Kaj
- Kaj je
- Kolo
- ali
- ki
- medtem
- bo
- veter
- z
- v
- brez
- Čudovit
- besede
- delo
- deluje
- svet
- svetu
- bi
- Zavito
- pisati
- pisanje
- leto
- zefirnet