Designcember のホリデー カレンダー スタイルのエクスペリエンスを構築するプロセスとツールをご紹介します。
12 月の精神と、多くの人がカウントダウンやお祝いの手段として使っているカレンダーに基づき、コミュニティや Chrome チームからのウェブ コンテンツを紹介したいと考えました。毎日、UI 開発とデザインに関連するコンテンツを 1 つ紹介し、合計 31 件のハイライトを掲載しました。そのうち、26 件は新しいデモサイト、ツール、お知らせ、ポッドキャスト、動画、記事、ケーススタディでした。
詳細については、designcember.com をご覧ください。
概要
目標は、できるだけ少ないバイト数で、アクセスしやすく、風変わりで、モダンで、レスポンシブなウェブ エクスペリエンスを提供することでした。コンテナ クエリなどの新しいレスポンシブ API を強調し、デザイン重視でアセットが多いウェブサイトにダークモードの美しい例を掲載したいと考えました。そのために、ファイルの圧縮、複数形式の提供、静的サイト生成に最適化されたビルドツールの使用、新しいポリフィルの提供などを行いました。
風変わりなことから始める
Designcember カレンダー サイトのアイデアは、12 月中に取り上げたかったすべての作品を紹介しつつ、それ自体のデモサイトとして機能することでした。私たちは、窓をフレーム内に再配置して、背が高く、幅が狭く、幅が広くなるようなレスポンシブなアパートを建てることにしました。各ウィンドウは 1 日(つまり 1 つのコンテンツ)を表します。このビジョンを実現するため、イラストレーターの Alice Lee に協力を依頼しました。
アリスは、初期のコンセプトでもワクワクするプロセスとスケッチを共有し、インスピレーションを与えてくれました。彼女がアート制作に取り組んでいる間、私たちはアーキテクチャをハックしました。初期の議論では、マクロ レイアウト、建物、窓について話し合いました。ビューポートのスペースが広がると、ウィンドウは 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 アニメーションでした。Google は、steps()
を使用して同様の手法でこの効果を実現しました。ただし、キーフレームは背景の位置ではなく CSS 変換位置でした。
CSS マスク
窓の形状が独特なものもありました。マスクと aspect-ratio
を使用して、スケーラブルで独自の形状のアダプティブ ウィンドウを作成しました。
このウィンドウ 8 用のマスクを作成するには、Photoshop の古典的なスキルに加えて、ウェブ上のマスクの仕組みに関する若干の知識が必要でした。8 日目のウィンドウを見てみましょう。
マスクにするには、内側の四葉のクローバー型の図形を独自の図形として分離し、白色で塗りつぶす必要があります。白は残すコンテンツを CSS に指示し、白以外のコンテンツはすべて残さないことを指定します。Photoshop でウィンドウの内側を選択し、1 ピクセル幅を広げ(エイリアシングの問題を解消)、白く塗りつぶし、ウィンドウ フレームと同じ高さと幅でエクスポートしました。これにより、フレームとマスクを直接重ねて、フレーム内の内部コンテンツを想定どおりに表示できます。
完了すると、ウィンドウの内容を変更でき、カスタム フレーム内に常に表示されます。次の画像は、背景のグラデーションを変更し、ライトにグロー CSS フィルタを適用した、ダークモード版のウィンドウを示しています。
マスキングは、レスポンシブなコンテナ クエリベースのウィンドウもサポートしています。ウィンドウ 9 では、ウィンドウのサイズが狭くなるまで、マスクの背後に隠れているキャラクターがいます。ユーザーがフレーム外で画像を調整できないように、Alice はキャラクター全体を完成させました。キャラクターはウィンドウ内でマスクされていますが、植物はマスクされていないため、マスクされた要素をマスクされていないレイヤと重ねて、すべてが一緒に適切にスケーリングされるようにするという課題もありました。
次の画像は、窓と文字にマスクを適用していない状態を示しています。
アートを圧縮する
イラストの忠実度を維持し、高解像度画面でぼやけたユーザー エクスペリエンスにならないようにするため、アリスは 3x ピクセル比で作業しました。当初は imgix を使用して、最適化された画像とフォーマットをサーバーで提供する予定でしたが、Squoosh ツールで手動で調整することで 50% 以上削減できることがわかりました。
イラストには、特にアリスが使用したブラシストロークのスタイルや透明な粗いエッジのスタイルなど、圧縮に関する独自の課題があります。Photoshop でエクスポートされた 3x の 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 つ目は、チームからインスピレーションを得たキャラクター キャストです。また、非アクティブな日には懐かしいスタイルのカーソルを追加し、ファビコンのスタイルを変更しました。
機能的なタップ
追加された機能のひとつが、建物の上に鳥が止まっている「今日にジャンプ」機能です。この鳥をクリックするか、Enter キーを押すと、ページがその月の現在の日付まで下に移動し、最新のリリースにすぐにアクセスできます。
Designcember.com には、特別な印刷用スタイルシートもあります。8.5 x 11 インチの紙に最適な特定の画像が提供されるため、カレンダーを自分で印刷して、1 年中クリスマス気分を味わうことができます。
12 月の 1 か月間の UI 開発を祝うために、多くの労力が、楽しくて風変わりなモダンなウェブ エクスペリエンスの作成に費やされました。ご視聴いただきありがとうございました。