Designcember のホリデー カレンダー スタイルのエクスペリエンスを構築するために使用されたプロセスとツールを紹介します。
12 月のホリデー シーズンにちなんで、カウントダウンや祝祭に使われるカレンダーをテーマに、コミュニティと Chrome チームのウェブ コンテンツをご紹介します。毎日、UI 開発とデザイン関連のコンテンツを 1 つずつ紹介し、合計 31 個のハイライトを紹介しました。そのうち 26 個は、新しいデモサイト、ツール、お知らせ、ポッドキャスト、動画、記事、ケーススタディでした。
designcember.web.app で完全なエクスペリエンスをご覧ください。
概要
Google の目標は、できるだけ少ないバイト数で、アクセスしやすく、奇抜で、モダンで、レスポンシブなウェブ エクスペリエンスを提供することでした。コンテナ クエリなどの新しいレスポンシブ API を紹介し、デザイン重視でアセットを多用したウェブサイトでダークモードの美しい例を紹介したいと考えました。この目標を達成するために、ファイルの圧縮、複数の形式の提供、静的サイト生成に最適化されたビルドツールの使用、新しいポリフィルの提供などを行いました。
気まぐれから始まる
Designcember カレンダー サイトのアイデアは、12 月を通してスポットライトを当てたいすべての作業のショーケースとして機能し、デモサイト自体としても機能することでした。そこで、高さを高くしたり低くしたり、幅を広くしたり狭くしたりできる、レスポンシブなアパートを建てることにしました。窓はフレーム内で自動的に配置し直されます。各ウィンドウは 1 日(つまり 1 つのコンテンツ)を表していました。イラストレーターの Alice Lee 氏と協力して、このビジョンを実現しました。
Alice は、初期のコンセプトの段階からワクワクするようなプロセスやスケッチを共有して、私たちを刺激してくれました。彼女がアートに取り組んでいる間、私たちはアーキテクチャをハッキングしました。初期の議論は、マクロ レイアウト、建物、窓についてでした。ビューポートのスペースが広くなったときに、ウィンドウは 1 列、2 列、3 列にどのように適応するでしょうか?どれくらい縮んだり伸びたりするのか?建物の最大サイズはどのくらいになりますか?ウィンドウはどのくらいシフトしますか?
grid-auto-flow: dense
を使用したレスポンシブ プロトタイプのプレビューです。グリッド アルゴリズムでウィンドウを自動的に配置する方法を示しています。アスペクト比のグリッドはアートの表示には適していましたが、ウィンドウを拡大縮小して利用可能なスペースを不均一にしたり、コンテナ クエリの機能を活用したりすることはできませんでした。

一般的なグリッドが比較的安定し、建物の応答性と窓の方向性が伝わるようになったら、1 つの窓に焦点を当てることができます。一部のウィンドウは、グリッド内の他のウィンドウよりも拡大、縮小、圧縮、拡大、再構成されました。
各ウィンドウは、一定量のサイズ変更の乱れを処理する必要があります。以下は、乱気流に対するウィンドウの応答性を実証するプロトタイプです。各インタラクティブ ウィンドウがどの程度調整されるかを示しています。
スプライトシートを使用したウィンドウ アニメーション
一部のウィンドウには、エクスペリエンスにインタラクションを追加するためのアニメーションがあります。アニメーションは Photoshop で手描きでフレームごとに作成されています。各フレームはエクスポートされ、このスプライトシート ジェネレータでスプライトシートに変換されてから、Squoosh で最適化されます。次の例に示すように、CSS アニメーションで background-position-x
と animation-timing-function
を使用します。
.una
background: url("/day1/una_sprite.webp") 0% 0%;
background-size: 400% auto;
}
.day:is(:hover, :focus-within) .una {
animation: una-wave .5s steps(1) alternate infinite;
}
@keyframes una-wave {
0% { background-position-x: 0%; }
25% { background-position-x: 300%; }
50% { background-position-x: 200%; }
75% { background-position-x: 100%; }
}
6 日目の貯金箱などの一部のアニメーションは、ステップベースの CSS アニメーションでした。この効果は、同様の手法で steps()
を使用して実現しました。ただし、キーフレームは背景の位置ではなく CSS 変換の位置でした。
CSS マスク
窓の形状が独特なものもありました。マスクと aspect-ratio
を使用して、スケーラブルでユニークな形状の適応型ウィンドウを実現しました。
8 番目のウィンドウのマスクを作成するには、Photoshop の基本的なスキルと、ウェブ上のマスクの仕組みに関する知識が少し必要でした。8 日目のウィンドウを見てみましょう。
マスクにするには、内側の四つ葉のクローバー型の図形を独自の図形として分離し、白で塗りつぶす必要があります。白は、CSS に残すコンテンツを指示し、白以外のコンテンツは残しません。Photoshop で、ウィンドウの内側を選択し、1 ピクセルぼかして(エイリアシングの問題を解消するため)、白で塗りつぶし、ウィンドウ フレームと同じ高さと幅で書き出しました。これにより、フレームとマスクを直接重ねて、フレーム内のコンテンツを期待どおりに表示できます。
完了すると、ウィンドウの内容が変更され、常にカスタム フレーム内に表示されるようになります。次の画像は、ウィンドウのダークモード バージョンを示しています。背景のグラデーションが異なり、ライトにグロー CSS フィルタが適用されています。
マスキングは、レスポンシブなコンテナクエリ ベースのウィンドウもサポートしています。ウィンドウ 9 では、ウィンドウが狭くなるまでマスクで隠されているキャラクターがいます。ユーザーが画像をフレーム外に調整できないように、アリスがキャラクター全体を完成させてくれました。キャラクターはウィンドウ内でマスクされますが、植物はマスクされません。そのため、マスクされた要素とマスクされていないレイヤを重ねて、それらがすべてうまくスケーリングされるようにする必要がありました。
次の画像は、ウィンドウと文字にマスクを適用していない状態を示しています。
アートを潰す
イラストの忠実度を維持し、高解像度画面でユーザー エクスペリエンスがぼやけないようにするため、Alice は 3 倍のピクセル比率で作業しました。imgix を使用して、最適化された画像と形式をサーバーで提供する予定でしたが、Squoosh ツールで手動で調整することで、50% 以上の節約になることがわかりました。
イラストには、特にアリスが使用したブラシストロークと透明な粗いエッジのスタイルで、圧縮に関する独自の課題があります。3x Photoshop で書き出した各 PNG 画像を、より小さい PNG、WebP、AVIF に Squoosh することにしました。ファイル形式ごとに独自の圧縮機能があり、50 枚以上の画像を圧縮して、一般的な最適化設定を見つけました。
最適化する画像が 200 枚以上あったため、Squoosh CLI が不可欠になりました。手動で処理していたら、数日かかっていたでしょう。共通の最適化設定が完了したら、コマンドライン手順として提供し、PNG 画像のフォルダ全体を WebP と AVIF の圧縮版にバッチ処理しました。
使用した AVIF CLI squoosh コマンドの例を次に示します。
npx @squoosh/cli --quant '{"enabled":true,"zx":0,"maxNumColors":256,"dither":1}' --avif '{"cqLevel":19,"cqAlphaLevel":17,"subsample":1,"tileColsLog2":0,"tileRowsLog2":0,"speed":6,"chromaDeltaQ":false,"sharpness":5,"denoiseLevel":0,"tune":0}' image-1.png image-2.png image-3.png
最適化されたアートワークがリポジトリにチェックインされたら、HTML からの読み込みを開始できます。
<picture>
<source srcset="/day1/inner-frame.avif" type="image/avif">
<source srcset="/day1/inner-frame.webp" type="image/webp">
<img alt="" decoding="async" role="presentation" src="/day1/inner-frame.png">
</picture>
画像のソースコードを繰り返し記述するのは面倒なので、1 行のコードで画像を埋め込む Astro コンポーネントを作成しました。
<Pic filename="day1/inner-frame" role="presentation" />
スクリーン リーダーとキーボードのユーザー
Designcember の体験の多くは、アートとインタラクティブなウィンドウを通じて行われます。キーボード ユーザーがサイトを利用してウィンドウを覗き見ることができ、スクリーン リーダー ユーザーが快適なナレーション体験を得られるようにすることが重要でした。
たとえば、画像を埋め込む際に、スクリーン リーダー用に画像をプレゼンテーションとしてマークするために role="presentation"
を使用しました。5 ~ 12 個の断片的な alt
説明文で構成されるユーザー エクスペリエンスは、好ましくないものになると考えました。そこで、画像をプレゼンテーション用としてマークし、ウィンドウ全体のナレーションを提供しました。スクリーン リーダーでウィンドウを移動すると、物語のような感覚が得られます。これは、サイトが伝えたい気まぐれさや楽しさを伝えるのに役立つことを期待したものです。
次の動画は、キーボード エクスペリエンスのデモを示しています。Tab キー、Enter キー、Space キー、Esc キーはすべて、ウィンドウ ポップアップとウィンドウ間のフォーカスを調整するために使用されます。
スクリーン リーダーの操作性を向上させるために、コンテンツを明確にする特別な ARIA 属性が用意されています。たとえば、日付のリンクは「1」や「2」としか表示されませんが、ARIA を追加すると「1 日目」や「2 日目」と読み上げられます。また、すべての画像が 1 つのラベルにまとめられているため、各ウィンドウには説明が表示されます。
Astro、静的ファースト、コンポーネント駆動型サイト ジェネレータ
Astro を使用することで、チームがサイトで共同作業を簡単に行えるようになりました。コンポーネント モデルは Angular と React の両方のデベロッパーにとって使い慣れたものであり、スコープ付きクラス名スタイル システムにより、各デベロッパーはウィンドウでの作業が他のデベロッパーと競合しないことを確認できました。
コンポーネントとしての「日」
各日は、ビルド時のデータストアからステータスを取得するコンポーネントでした。これにより、HTML がブラウザに到達する前にテンプレート ロジックを実行できました。このロジックにより、ツールチップを表示するかどうかが判断されます。無効な日にはポップアップが表示されません。
ビルドは 1 時間ごとに実行され、ビルド サーバーが午前 0 時を過ぎると、ビルド時間のデータストアで新しい日がロック解除されます。これらの自己更新型で自律型の小さなシステムにより、サイトは常に最新の状態に保たれます。
スコープ付きスタイルと Open Props
Astro はコンポーネント モデル内に記述されたスタイルをスコープするため、多くのチームメンバー間でワークロードを分散しやすくなり、Open Props を楽しく使用できるようになりました。Open Props normalize.css のスタイルは、アダプティブ(ライトとダーク)テーマで役立ちました。また、段落や見出しなどのコンテンツの管理にも役立ちました。
Astro のアーリー アダプターとして、PostCSS でいくつかの問題に直面しました。たとえば、ビルドの問題が多すぎるため、最新の Astro バージョンに更新できませんでした。ビルドとデベロッパーのワークフローを最適化するのに、より多くの時間を費やすことができます。
柔軟なコンテナ
一部のウィンドウは、アートを維持するためにアスペクト比を維持しながら拡大縮小します。コンテナクエリを使用したコンポーネント ベースのアーキテクチャの威力を示すために、他のウィンドウも使用しました。コンテナクエリにより、ウィンドウは個々のレスポンシブ スタイリング情報を所有し、独自のサイズに基づいて再調整できるようになりました。一部のウィンドウは狭いものから広いものに変わり、その中のメディアのサイズと配置を調整する必要がありました。
ウィンドウで使用できるスペースが増えたら、ウィンドウのサイズや子要素を調整して、そのスペースに合わせることができます。アダプティブ ウィンドウを実現するには、コンテナ クエリは単にデモとして面白いだけでなく、必須であり、特定のレイアウトのオーケストレーションを大幅に簡素化することがわかりました。
.day {
container: inline-size;
}
.day > .pane {
min-block-size: 250px;
@container (min-width: 220px) {
min-block-size: 300px;
}
@container (min-width: 260px) {
min-block-size: 310px;
}
@container (min-width: 360px) {
min-block-size: 450px;
}
}
このアプローチは、アスペクト比を維持するアプローチとは異なります。より細かく管理でき、より多くの機会を得ることができます。ある程度のサイズになると、多くのお子様は新しいレイアウトに適応するために移動します。
コンテナ クエリでは、ブロック方向(縦)のコンテインメントもサポートできるため、ウィンドウの長さが長くなっても、スタイルを適切に調整できます。これは、高さベースのクエリ(単独で使用)と幅ベースのクエリの両方で確認できます。
.person {
place-self: flex-end;
margin-block: 25% 50%;
margin-inline-start: -15%;
z-index: var(--layer-1);
@container (max-height: 350px) and (max-width: 425px) {
place-self: center flex-end;
inline-size: 50%;
inset-block-end: -15%;
margin-block-start: -2%;
margin-block-end: -25%;
z-index: var(--layer-2);
}
}
また、コンテナ クエリを使用して、アートが小さくなると詳細を表示し、アートが大きくなると詳細を非表示にしました。この例として、ウィンドウ 9 をご覧ください。
クロスブラウザのサポート
優れた最新のクロスブラウザ エクスペリエンス、特にコンテナ クエリなどの試験運用版 API を作成するには、優れたポリフィルが必要です。チームに呼びかけ、Surma が新しいコンテナ クエリ ポリフィルのビルドを主導しました。このポリフィルは、ResizeObserver、MutationObserver、CSS の :is() 関数に依存しています。そのため、すべての最新ブラウザがポリフィルをサポートしています。具体的には、Chrome と Edge はバージョン 88 以降、Firefox はバージョン 78 以降、Safari はバージョン 14 以降です。ポリフィルを使用すると、次の構文を使用できます。
/* These are all equivalent */
@container (min-width: 200px) {
/* ... */
}
@container (width >= 200px) {
/* ... */
}
@container size(width >= 200px) {
/* ... */
}
ダークモード
Designcember ウェブサイトに不可欠な最後の仕上げは、美しいダークモードでした。アート自体を積極的に活用して、優れたダークモード エクスペリエンスを実現する方法をご紹介します。このため、各ウィンドウの背景スタイルをプログラムで調整し、ウィンドウ アートを作成する際に意味のある CSS をできるだけ多く使用しました。背景のほとんどは CSS グラデーションで、色の値を簡単に調整できるようにしました。その上にアートを重ねました。
その他のイースター エッグ
パーソナル タッチ
サイトに個性を出すために、ページにいくつかのパーソナライズされた要素を追加しました。1 つ目は、チームのメンバーをモデルにしたキャラクターのキャストです。また、非アクティブな日には昔風のカーソルを表示したり、ファビコンのスタイルを試したりしました。
機能的なタッチ
追加機能の 1 つに、建物の屋上に鳥が止まっている「今日に移動」機能があります。この鳥をクリックするか、Enter キーを押すと、ページ内の当月の日にジャンプし、最新のリリースにすばやくアクセスできます。
Designcember のウェブサイトには、特別な印刷用スタイルシートもあります。これは、8.5 インチ x 11 インチの用紙に最適に印刷できる特定の画像を提供するもので、ご自身でカレンダーを印刷して、一年中お祝い気分を味わうことができます。

全体として、12 月に 1 か月間 UI 開発を祝う、楽しくて奇抜な最新のウェブ エクスペリエンスの作成には、多くの労力が費やされました。お楽しみいただけましたでしょうか。