ここで CSS-Tricks を簡単に検索すると、カレンダーにアプローチするさまざまな方法があることがわかります。 いくつかの方法を示します レイアウトを効率的に作成できるCSS Grid. いくつかの試み 実際のデータをミックスに取り入れる。 いくつかの フレームワークに頼る 状態管理に役立ちます。
カレンダー コンポーネントを作成する際には、私がリンクした記事でカバーされているよりもはるかに多くの考慮事項があります。 考えてみれば、タイムゾーンや日付形式の処理からローカリゼーション、さらにはある月から次の月への日付の流れの確認まで、カレンダーにはニュアンスがたくさんあります…そしてそれは、カレンダーがどこにあるかに応じたアクセシビリティと追加のレイアウトの考慮事項に入る前です.などが表示されます。
多くの開発者は、 Date()
オブジェクト のような古いライブラリに固執する moment.js
. 日付や書式設定に関しては多くの「落とし穴」がありますが、JavaScript には便利な API や機能がたくさんあります。
ここでホイールを再作成するつもりはありませんが、標準の JavaScript を使用して非常に優れたカレンダーを作成する方法を紹介します。 調べてみます 接近性、セマンティック マークアップとスクリーン リーダー対応の使用 <time>
-タグ — および internationalization および 書式設定、使用して Intl.Locale
, Intl.DateTimeFormat
および Intl.NumberFormat
-API。
言い換えれば、私たちはカレンダーを作成しています... ただし、このようなチュートリアルで通常使用される追加の依存関係がなく、通常は見られないニュアンスがいくつかあります。 そして、その過程で、このようなものを組み立てているときに私の頭をよぎる種類のアイデアを得ながら、JavaScript でできる新しいことに対する新たな評価を得ていただければ幸いです。
まずはネーミングから
カレンダー コンポーネントを何と呼べばよいでしょうか。 私の母国語では「カレンダ要素」と呼ばれるので、それを使用して「Kal-El」と短縮してみましょう。 惑星クリプトンでのスーパーマンの名前.
物事を進めるための関数を作成しましょう:
function kalEl(settings = {}) { ... }
このメソッドはレンダリングします ひと月. 後でこのメソッドを呼び出します [...Array(12).keys()]
XNUMX年全体をレンダリングします。
初期データと国際化
典型的なオンライン カレンダーでよく行われることの XNUMX つは、現在の日付を強調表示することです。 それでは、そのための参照を作成しましょう。
const today = new Date();
次に、オプションのオブジェクトとマージする「構成オブジェクト」を作成します。 settings
主なメソッドのオブジェクト:
const config = Object.assign( { locale: (document.documentElement.getAttribute('lang') || 'en-US'), today: { day: today.getDate(), month: today.getMonth(), year: today.getFullYear() } }, settings
);
ルート要素 (<html>
)を含む lang
-属性 ローカル 情報; それ以外の場合は、使用にフォールバックします en-US
. これがそのための第一歩です カレンダーの国際化.
また、カレンダーがレンダリングされるときに最初に表示する月を決定する必要があります。 そのため、 config
プライマリを持つオブジェクト date
. このように、日付が指定されていない場合 settings
オブジェクト、使用します today
代わりに参照してください:
const date = config.date ? new Date(config.date) : today;
ロケールに基づいてカレンダーを適切にフォーマットするには、もう少し情報が必要です。 たとえば、ロケールによっては、週の最初の日が日曜日か月曜日かがわからない場合があります。 情報があれば、素晴らしいです! そうでない場合は、 Intl.Locale
API. API には weekInfo
オブジェクト それは返す firstDay
手間をかけずに探しているものを正確に提供してくれるプロパティ。 に割り当てられている曜日を取得することもできます。 weekend
:
if (!config.info) config.info = new Intl.Locale(config.locale).weekInfo || { firstDay: 7, weekend: [6, 7] };
ここでも、フォールバックを作成します。 週の「最初の日」 en-US
は日曜日なので、デフォルトの値は 7
. これは少し混乱します。 getDay
方法 JavaScript では、日数を次のように返します [0-6]
ここで、 0
は日曜日です…理由は聞かないでください。 週末は土・日なので、 [6, 7]
.
私たちが持っていた前に Intl.Locale
APIとその weekInfo
多くの**オブジェクトと、各ロケールまたは地域に関する情報を含む配列なしで、国際カレンダーを作成するのは非常に困難でした。 最近では、簡単です。 私たちが通過する場合 en-GB
、メソッドは次を返します。
// en-GB
{ firstDay: 1, weekend: [6, 7], minimalDays: 4
}
ブルネイのような国で(ms-BN
)、週末は金曜と日曜です。
// ms-BN
{ firstDay: 7, weekend: [5, 7], minimalDays: 1
}
あなたはそれが何であるか疑問に思うかもしれません minimalDays
プロパティは。 それは 月の第 XNUMX 週に XNUMX 週間としてカウントされるのに必要な最小日数. 一部の地域では、XNUMX 日だけの場合もあります。 他の人にとっては、丸 XNUMX 日間かもしれません。
次に、 render
弊社内の方法 kalEl
-方法:
const render = (date, locale) => { ... }
何かをレンダリングする前に、さらにデータを処理する必要があります。
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);
最後のものは Boolean
かどうかをチェックする today
レンダリングしようとしている月に存在します。
セマンティックマークアップ
すぐにレンダリングについて詳しく説明します。 しかし、最初に、設定した詳細にセマンティック HTML タグが関連付けられていることを確認したいと思います。 すぐに使えるように設定すると、最初からアクセシビリティのメリットが得られます。
カレンダー ラッパー
まず、非セマンティック ラッパーがあります。 <kal-el>
. セマンティックがないから大丈夫 <calendar>
タグとか。 カスタム要素を作成していなければ、 <article>
カレンダーは独自のページに立つことができるので、最も適切な要素かもしれません。
月の名前
<time>
要素は、スクリーンリーダーや検索エンジンがより正確かつ一貫して解析できる形式に日付を変換するのに役立つため、私たちにとって大きなものになるでしょう. たとえば、マークアップで「2023 年 XNUMX 月」を伝える方法は次のとおりです。
<time datetime="2023-01">January <i>2023</i></time>
曜日名
曜日の名前を含むカレンダーの日付の上の行は扱いにくい場合があります。 日曜、月曜、火曜など、曜日ごとに完全な名前を書き出すことができれば理想的ですが、それでは多くのスペースが必要になる可能性があります。 というわけで、今のところ名前を短縮しましょう。 <ol>
毎日がどこにあるか <li>
:
<ol> <li><abbr title="Sunday">Sun</abbr></li> <li><abbr title="Monday">Mon</abbr></li> <!-- etc. -->
</ol>
両方の長所を活かすために、CSS を巧妙に扱うことができます。 たとえば、次のようにマークアップを少し変更したとします。
<ol> <li> <abbr title="S">Sunday</abbr> </li>
</ol>
…デフォルトでフルネームを取得します。 スペースがなくなったときにフルネームを「非表示」にして、 title
代わりに属性:
@media all and (max-width: 800px) { li abbr::after { content: attr(title); }
}
しかし、私たちはそのようには行きません。なぜなら、 Intl.DateTimeFormat
ここでも API が役立ちます。 これについては、レンダリングについて説明する次のセクションで説明します。
曜日番号
カレンダー グリッドの各日付は数値を取得します。 各番号はリスト項目です (<li>
)順序付きリスト(<ol>
)、およびインライン <time>
タグは実際の番号をラップします。
<li> <time datetime="2023-01-01">1</time>
</li>
まだスタイリングを行う予定はありませんが、日付番号のスタイルを設定する何らかの方法が必要になることはわかっています。 それはそのままで可能ですが、必要に応じて、平日の数字と週末の数字を異なるスタイルにできるようにしたいと考えています。 だから、私は含めるつもりです data-*
属性 特にそのために: data-weekend
および data-today
.
週番号
52 年は 53 週で、時には XNUMX 週もあります。あまり一般的ではありませんが、カレンダーに特定の週の数を表示すると、追加のコンテキストが得られます。 使わなくなることはなくても、今は持っているのが好きです。 しかし、このチュートリアルでは完全に使用します。
を使用します data-weeknumber
属性をスタイリング フックとして使用し、週の最初の日付である各日付のマークアップに含めます。
<li data-day="7" data-weeknumber="1" data-weekend=""> <time datetime="2023-01-08">8</time>
</li>
レンダリング
ページにカレンダーを表示しよう! 私たちはすでにそれを知っています <kal-el>
カスタム要素の名前です。 最初に設定する必要があるのは、 firstDay
その上にプロパティがあるため、カレンダーは日曜日か他の日が週の最初の日かを認識します。
<kal-el data-firstday="${ config.info.firstDay }">
私たちは使っているよ テンプレートリテラル マークアップをレンダリングします。 世界中の視聴者向けに日付をフォーマットするには、 Intl.DateTimeFormat
API、再び locale
先に指定しました。
月と年
私たちが呼ぶとき month
、使用するかどうかを設定できます long
名前(例:February)または short
名前 (例: Feb.)。 を使いましょう long
カレンダーの上のタイトルなので名前:
<time datetime="${year}-${(pad(month))}"> ${new Intl.DateTimeFormat( locale, { month:'long'}).format(date)} <i>${year}</i>
</time>
曜日名
日付のグリッドの上に表示される平日については、 long
(例: 「日曜日」) および short
(省略、つまり「太陽」) 名。 このようにして、カレンダーのスペースが不足している場合に「短い」名前を使用できます。
Intl.DateTimeFormat([locale], { weekday: 'long' })
Intl.DateTimeFormat([locale], { weekday: 'short' })
それぞれの呼び出しを少し簡単にする小さなヘルパー メソッドを作成しましょう。
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;
}
テンプレートでそれを呼び出す方法は次のとおりです。
<ol> ${weekdays(config.info.firstDay,locale).map(name => ` <li> <abbr title="${name.long}">${name.short}</abbr> </li>`).join('') }
</ol>
曜日番号
そして最後に、 <ol>
素子:
${[...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('')}
それを分解しましょう:
- 「日数」変数に基づいて「ダミー」配列を作成し、反復に使用します。
- 作成します
day
反復における現在の日の変数。 - 間の不一致を修正します
Intl.Locale
APIおよびgetDay()
. - Status
day
等しいtoday
、追加しますdata-*
属性。 - 最後に、
<li>
マージされたデータを含む文字列としての要素。 tabindex="0"
キーボード ナビゲーションを使用する場合、正の tabindex 値の後で要素をフォーカス可能にします (注: 決して 加えます 正の タブインデックス値)
に 数字を「パディング」する セクションに datetime
属性には、小さなヘルパー メソッドを使用します。
const pad = (val) => (val + 1).toString().padStart(2, '0');
週番号
繰り返しますが、「週番号」は、52 週のカレンダーで週が位置する場所です。 そのためにも、小さなヘルパー メソッドを使用します。
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);
}
私はこれを書いていません getWeek
-方法。 のクリーンアップ版です このスクリプト.
以上です! おかげ Intl.Locale
, Intl.DateTimeFormat
および Intl.NumberFormat
API を変更するだけで、 lang
-の属性 <html>
現在の地域に基づいてカレンダーのコンテキストを変更する要素:
カレンダーのスタイリング
すべての日がたった XNUMX 日であることを思い出すかもしれません。 <ol>
リストアイテム付き。 これらを読みやすいカレンダーにスタイル設定するために、CSS Grid のすばらしい世界に飛び込みます。 実際、同じグリッドを次のように再利用できます。 CSS-Tricks のスターター カレンダー テンプレート、しかし、で少し更新しました :is()
コードを最適化するリレーショナル疑似。
途中で構成可能な CSS 変数を定義していることに注意してください (そして、それらにプレフィックスを付けます)。 ---kalel-
競合を避けるため)。
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;
}
視覚的に区別できるように、日付番号の周りに境界線を引きましょう。
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); }
月の最初の日が また 選択したロケールの週の最初の曜日)。 しかし、それはルールではなく例外です。 ほとんどの場合、月の最初の日を別の曜日にずらす必要があります。
余分なことをすべて覚えておいてください data-*
マークアップを書くときに定義した属性? それらにフックして、どのグリッド列を更新できます(--kalel-li-gc
) 月の最初の日付番号は次の場所に配置されます。
[data-firstday="1"] [data-day="3"]:first-child { --kalel-li-gc: 1 / 4;
}
この場合、最初のグリッド列から 2 番目のグリッド列にまたがっています。これにより、次のアイテム (XNUMX 日目) が XNUMX 番目のグリッド列に自動的に「プッシュ」されます。
「現在」の日付に少しスタイルを追加して、目立つようにしましょう。 これらは私のスタイルです。 ここでやりたいことを完全に行うことができます。
[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;
}
週末の日付番号を平日とは異なるスタイルにするというアイデアが気に入っています。 それらをスタイリングするために赤みがかった色を使用します。 に到達できることに注意してください :not()
現在の日付をそのままにしてそれらを選択する疑似クラス:
[data-weekend]:not([data-today]) { --kalel-day-c: var(--kalel-weekend-c, hsl(0, 86%, 46%));
}
ああ、各週の最初の日付番号の前にある週番号を忘れないようにしましょう。 私たちは data-weeknumber
そのためのマークアップの属性ですが、数値は CSS で明らかにしない限り実際には表示されません。 ::before
疑似要素:
[data-weeknumber]::before { display: var(--kalel-weeknumber-d, inline-block); content: attr(data-weeknumber); position: absolute; inset-inline-start: 0; /* additional styles */
}
この時点で技術的には完了です。 現在の月の日付を表示するカレンダー グリッドをレンダリングし、ロケールごとにデータをローカライズするための考慮事項を完備し、カレンダーが適切なセマンティクスを使用するようにします。 そして、使用したのはごく普通の JavaScript と CSS だけでした!
しかし、これを取りましょう もう一つのステップ...
XNUMX 年全体をレンダリングする
XNUMX 年分の日付を表示する必要があるかもしれません。 そのため、現在の月をレンダリングするのではなく、現在の年のすべての月のグリッドを表示したい場合があります。
さて、私たちが使用しているアプローチの良い点は、 render
メソッドを必要な回数だけ実行し、各インスタンスで月を識別する整数を変更するだけです。 現在の年に基づいて 12 回呼び出してみましょう。
を呼び出すのと同じくらい簡単です。 render
-method を 12 回実行し、整数を変更するだけです month
- i
:
[...Array(12).keys()].map(i => render( new Date(date.getFullYear(), i, date.getDate()), config.locale, date.getMonth() )
).join('')
レンダリングされた年の新しい親ラッパーを作成することをお勧めします。 各カレンダー グリッドは、 <kal-el>
エレメント。 新しい親ラッパーを呼び出しましょう <jor-el>
ここで、 Jor-El は Kal-El の父親の名前です。.
<jor-el id="app" data-year="true"> <kal-el data-firstday="7"> <!-- etc. --> </kal-el> <!-- other months -->
</jor-el>
我々は使用することができます <jor-el>
グリッドのグリッドを作成します。 だからメタ!
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);
}
最終デモ
おまけ:紙吹雪カレンダー
という素晴らしい本を読んだ グリッドの作成と解除 先日、この美しい「新年のポスター」に出くわしました。
HTML や JavaScript を何も変更せずに、同様のことができると考えました。 読みやすくするために、自由に月の完全な名前と、日の名前の代わりに数字を含めました。 楽しみ!
- SEO を活用したコンテンツと PR 配信。 今日増幅されます。
- Platoblockchain。 Web3メタバースインテリジェンス。 知識の増幅。 こちらからアクセスしてください。
- 情報源: https://css-tricks.com/making-calendars-with-accessibility-and-internationalization-in-mind/
- :は
- $UP
- 1
- 11
- 2023
- 7
- 8
- 9
- 98
- a
- できる
- 私たちについて
- それについて
- 上記の.
- 絶対の
- 接近性
- 正確にデジタル化
- 実際に
- NEW
- 後
- すべて
- 一人で
- 既に
- および
- API
- API
- アプリ
- 感謝
- アプローチ
- 適切な
- です
- 周りに
- 配列
- 物品
- AS
- 割り当てられた
- 関連する
- At
- 属性
- 聴衆
- 自動的に
- 背景
- ベース
- BE
- 美しい
- なぜなら
- 利点
- BEST
- の間に
- ビッグ
- ビット
- 本
- ボックス
- ブレーク
- 破壊
- 建物
- by
- カレンダー
- コール
- 呼ばれます
- 呼び出し
- 缶
- 取得することができます
- 場合
- 変化する
- 変化
- チェック
- 小切手
- コード
- カラー
- コラム
- COM
- コマンドと
- コンプリート
- コンポーネント
- 紛らわしい
- 検討事項
- 含まれています
- コンテンツ
- コンテキスト
- クール
- 可能性
- 国
- カバー
- カバー
- 作ります
- Cross
- CSS
- 電流プローブ
- カスタム
- データ
- 日付
- 試合日
- 中
- 日
- より深い
- デフォルト
- デフォルト
- 定義済みの
- 定義
- によっては
- 細部
- 決定する
- 開発者
- 異なります
- 不一致
- ディスプレイ
- ドキュメント
- ドント
- ダウン
- ドロー
- e
- 各
- 前
- 容易
- エディション
- 素子
- エンジン
- 確保する
- 全体
- 等
- さらに
- 正確に
- 例
- 優れた
- 例外
- 存在
- 余分な
- 落下
- フォールズ
- 恐怖
- 2月
- 2月
- 考え出した
- 最後に
- 終わり
- 名
- 修正する
- フロー
- 形式でアーカイブしたプロジェクトを保存します.
- 第4
- 金曜日
- から
- フル
- function
- 利得
- ギャップ
- 取得する
- 受け
- 与えられた
- 与える
- Go
- 行く
- 良い
- グリッド
- グリッド テンプレート列
- ハンドリング
- ハード
- 持ってる
- 持って
- 助けます
- ことができます
- こちら
- 特徴
- 希望
- 認定条件
- HTML
- HTTPS
- i
- アイデア
- 理想
- 識別する
- in
- include
- info
- 情報
- 初期
- 当初
- を取得する必要がある者
- 世界全体
- IT
- リーディングシート
- 繰り返し
- ITS
- 1月
- JavaScriptを
- 一つだけ
- 知っている
- 既知の
- 言語
- 言語
- 姓
- レイアウト
- 残す
- Li
- 自由
- ライブラリ
- ような
- ライン
- リンク
- リスト
- 少し
- ローカライゼーション
- 長い
- 見て
- 探して
- たくさん
- make
- 作る
- 作成
- 管理
- 多くの
- マージン
- math
- 最大幅
- 単に
- マージ
- 方法
- かもしれない
- マインド
- 修正されました
- 瞬間
- 月曜日
- 月
- ヶ月
- 他には?
- 最も
- モジラ
- 名
- 名
- ネイティブ
- ナビゲーション
- 必要
- 新作
- 次の
- ニュアンス
- 数
- 番号
- オブジェクト
- of
- on
- ONE
- オンライン
- 最適化
- その他
- その他
- さもないと
- 自分の
- パッド
- ページ
- 惑星
- 計画
- プラトン
- プラトンデータインテリジェンス
- プラトデータ
- 位置
- 正の
- 可能
- かなり
- 主要な
- 多分
- プロセス
- 適切な
- 正しく
- 財産
- 提供
- パッティング
- クイック
- むしろ
- リーチ
- 読む
- 赤みがかった
- 地域
- 地域
- レンダリング
- の提出が必要です
- return
- 収益
- 明らかにする
- ルート
- 行
- ルール
- s
- 同じ
- を検索
- 検索エンジン
- セクション
- 選択
- 意味論
- 別
- セッションに
- 設定
- 設定
- セブン
- シフト
- ショート
- すべき
- 表示する
- 示す
- 作品
- 同様の
- 簡単な拡張で
- 単に
- から
- 小さい
- So
- 固体
- 一部
- 何か
- スペース
- 特に
- 指定の
- スタンド
- スタンド
- start
- 都道府県
- 手順
- まだ
- スーパー
- TAG
- 取る
- template
- 感謝
- それ
- それら
- ボーマン
- もの
- 物事
- 時間
- <font style="vertical-align: inherit;">回数</font>
- 役職
- 〜へ
- 今日
- 一緒に
- 完全に
- に向かって
- 翻訳する
- true
- 火曜日
- チュートリアル
- 典型的な
- 一般的に
- アップデイト
- 更新しました
- us
- つかいます
- 値
- 価値観
- バージョン
- W3
- 仕方..
- 方法
- 週間
- 週末
- ウィークス
- WELL
- この試験は
- 何ですか
- ホイール
- かどうか
- which
- while
- 意志
- 風
- 以内
- 無し
- 素晴らしい
- 言葉
- 仕事
- 作品
- 世界
- 世界の
- でしょう
- 包まれました
- 書きます
- 書き込み
- 年
- You
- ゼファーネット