Взгляд на процесс и инструменты, используемые для создания праздничного календаря Designcember.
В духе декабря и многочисленных календарей, которые люди используют для обратного отсчета и празднования, мы хотели бы выделить веб-контент от сообщества и команды Chrome. Каждый день мы выделяли один фрагмент контента, связанного с разработкой пользовательского интерфейса и дизайном, в общей сложности 31 выделение, среди которых было 26 новых демонстрационных сайтов, инструментов, объявлений, подкастов, видео, статей и тематических исследований.
Полную версию можно посмотреть на сайте designcember.com .
Обзор
Наша цель состояла в том, чтобы предоставить доступный, причудливый, современный и отзывчивый веб-опыт в как можно меньшем количестве байтов. Мы хотели выделить новые отзывчивые API, такие как запросы контейнеров, и включить прекрасный пример темного режима в ориентированный на дизайн и насыщенный ресурсами веб-сайт. Чтобы добиться этого, мы сжимали файлы, предлагали несколько форматов, использовали инструменты сборки, оптимизированные для генерации статических сайтов, отправили новый полифил и многое другое.
Начиная с прихоти
Идея сайта-календаря Designcember заключалась в том, чтобы он функционировал как витрина для всех работ, которые мы хотели бы выставить напоказ в течение декабря, и при этом сам действовал как демонстрационный сайт. Мы решили построить адаптивный жилой дом, который мог бы становиться выше и уже или короче и шире, с окнами, которые перестраивались бы внутри рамы. Каждое окно представляло один день (и, таким образом, один фрагмент контента). Мы работали с иллюстратором Элис Ли, чтобы воплотить наше видение в жизнь.
Элис вдохновляла, делясь процессами и эскизами, которые были захватывающими даже в своих ранних концепциях. Пока она работала над искусством, мы ломали голову над архитектурой. Ранние обсуждения касались макромакета, здания и его окон. Как окна будут адаптироваться к одной, двум или трем колоннам по мере того, как станет доступно больше места для просмотра? Насколько они могут сжиматься или растягиваться? Каким будет максимальный размер здания? Насколько сместятся окна?
Вот предварительный просмотр адаптивного прототипа с использованием grid-auto-flow: dense
показывающий, как окна могут быть автоматически размещены с помощью алгоритма сетки. Мы быстро поняли, что хотя сетки с соотношением сторон прекрасно справляются с демонстрацией искусства, они не дают возможности окнам расти и сжиматься в неравномерном доступном пространстве и демонстрировать мощь контейнерных запросов.

Как только общая сетка стала относительно стабильной и передала чувство направления для отзывчивости здания и его окон, мы смогли сосредоточиться на одном окне. Некоторые окна растягивались, сжимались, сжимались, росли и перестраивались больше, чем другие в сетке.
Каждое окно должно было бы обрабатывать определенное количество турбулентности изменения размера. Ниже представлен прототип окна, демонстрирующий его реакцию на турбулентность, показывающий, насколько мы можем ожидать, что каждое интерактивное окно будет корректироваться.
Анимация окон с помощью спрайт-листов
В некоторых окнах есть анимация, которая добавляет дополнительное взаимодействие к опыту. Анимация рисуется вручную, кадр за кадром, в 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%; }
}
Некоторые анимации, такие как свинья-банк шестого дня , были пошаговыми CSS-анимациями. Мы достигли этого эффекта с помощью похожей техники, используя steps()
, с той разницей, что ключевые кадры были позициями преобразования CSS, а не позициями фона.
CSS-маскировка
Некоторые окна имели уникальные формы. Мы использовали маски и aspect-ratio
, чтобы сделать масштабируемое, уникальной формы и адаптивное окно.
Чтобы создать маску, например, для восьмого окна, нужны были некоторые классические навыки работы с Photoshop, а также немного знаний о том, как работают маски в Интернете. Давайте рассмотрим окно восьмого дня.
Чтобы стать маской, внутренняя форма типа четырехлистного клевера должна быть изолирована как собственная форма и заполнена белым цветом. Белый цвет сообщает CSS, какой контент останется, а все, что находится за пределами белого цвета, не останется. В Photoshop внутренняя часть окна была выбрана, растушевана на 1 пиксель (чтобы устранить проблемы со сглаживанием), затем заполнена белым цветом и экспортирована на той же высоте и ширине, что и рамка окна. Таким образом, рамка и маска могли быть наложены друг на друга, показывая внутреннее содержимое внутри рамки, как и ожидалось.
После завершения содержимое окна можно было бы изменить, и оно всегда оставалось бы в пределах пользовательской рамки. На следующем изображении показана версия окна в темном режиме с другим фоновым градиентом и CSS-фильтром свечения, примененным к свету.
Маскирование также поддерживает адаптивные окна на основе контейнерных запросов. В окне девять есть персонаж, который скрыт за маской, пока окно не станет более узким. Чтобы убедиться, что пользователь не сможет вывести изображение за рамки, Элис завершила для нас полного персонажа. Персонаж замаскирован в окне, но растения — нет, поэтому еще одной проблемой, с которой мы столкнулись, было наложение замаскированных элементов на незамаскированные слои и обеспечение того, чтобы все они хорошо масштабировались вместе.
На следующем изображении показано, как это выглядит без маски на окне и персонаже.
Сплющивание искусства
Чтобы сохранить точность иллюстрации и гарантировать, что экраны высокой четкости не будут размытыми для пользователей, Alice работала с соотношением пикселей 3x. План состоял в том, чтобы использовать imgix и обслуживать оптимизированные изображения и форматы на их сервере, но мы обнаружили, что ручная настройка с помощью инструмента Squoosh может сэкономить нам 50% или больше.
Иллюстрация имеет уникальные проблемы со сжатием, особенно мазок кисти и прозрачный грубый край, которые использовала Элис. Мы решили преобразовать каждое 3x Photoshop экспортированное изображение png в меньшие png, webp и avif. Каждый тип файла имеет свои собственные особые возможности сжатия, и потребовалось сжать более 50 изображений, чтобы найти некоторые общие настройки оптимизации.
Squoosh CLI стал критически важным, когда нужно было оптимизировать более 200 изображений — выполнение всех этих действий вручную заняло бы несколько дней. Как только у нас появились общие параметры оптимизации, мы предоставили их в виде инструкций командной строки и пакетно обработали целые папки изображений 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>
Писать исходный код изображения было однообразно, поэтому мы создали компонент Astro для встраивания изображений с помощью одной строки кода.
<Pic filename="day1/inner-frame" role="presentation" />
Пользователи экранного диктора и клавиатуры
Значительная часть опыта Designcember осуществляется через искусство и интерактивные окна. Для нас было важно, чтобы пользователь клавиатуры мог пользоваться сайтом и заглядывать в окна, а пользователи экранных дикторов получали приятный озвученный опыт.
Например, при встраивании изображений мы использовали role="presentation"
, чтобы пометить изображение как презентационное для экранных дикторов. Мы чувствовали, что пользовательский опыт от 5 до 12 фрагментированных alt
описаний будет плохим опытом. Поэтому мы пометили изображения как презентационные и предоставили общее оконное повествование. Перемещение по окнам в экранном дикторе затем имеет приятное повествовательное чувство, которое, как мы надеялись, поможет передать причудливость и веселье, которыми хочет поделиться сайт.
В следующем видео показана демонстрация работы с клавиатурой. Клавиши Tab, Enter, Spacebar и Escape используются для управления фокусом между всплывающими окнами и окнами.
Опыт чтения с экрана имеет специальные атрибуты ARIA, которые придают ясность содержанию. Например, ссылки на дни говорят только «один» или «два», но с добавлением ARIA они объявляются как «День первый» и «День второй». Кроме того, все изображения суммируются в одной метке, поэтому каждое окно имеет описание.
Astro, статический первый, компонентно-управляемый генератор сайтов
Astro облегчила совместную работу команды над сайтом. Модель компонентов была знакома разработчикам Angular и React, а система стилей имен классов с ограниченной областью действия помогала каждому разработчику знать, что его работа над окном не будет конфликтовать с чьей-либо еще.
Дни как компоненты
Каждый день был компонентом , который извлекал статус из хранилища данных времени сборки . Это позволяло нам запускать логику шаблона до того, как HTML достигал браузера. Логика определяла, должен ли день показывать свою подсказку или нет, поскольку неактивные дни не имеют всплывающих окон.
Сборки запускаются каждый час, а хранилище данных времени сборки разблокирует новый день, когда сервер сборки перевалит за полночь. Эти самообновляющиеся и самодостаточные маленькие системы поддерживают сайт в актуальном состоянии.
Ограниченные стили и открытые свойства
Стили Astroscopes, написанные внутри его компонентной модели , что облегчило распределение рабочей нагрузки среди многих членов команды, а также сделало использование 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);
}
}
Мы также использовали запросы контейнеров, чтобы показывать и скрывать детали, поскольку искусство становилось все более переполненным при меньших размерах и все более пустым при более широких размерах. Окно девять — отличный пример того, где это вступило в игру:
Кроссбраузерная поддержка
Чтобы создать отличный современный кросс-браузерный опыт, особенно для экспериментальных API, таких как запросы контейнеров, нам нужен отличный полифилл. Мы отправили вызов нашей команде, и Сурма возглавил сборку для нового полифилла запроса контейнера . Полифилл опирается на 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, чтобы было проще настраивать их цветовые значения. Затем мы наложили на них искусство.
Другие пасхальные яйца
Личные штрихи
Мы добавили несколько личных штрихов на страницу, чтобы придать сайту больше индивидуальности. Первым был набор персонажей, вдохновленный нашей командой. Мы также добавили курсор в стиле ретро для неактивных дней и поиграли со стилем фавикона.
Функциональные штрихи
Одним из дополнительных функциональных штрихов является функция «Перейти к сегодняшнему дню» с птицей, сидящей на крыше здания. Щелчок или нажатие Enter на этой птице переместит вас вниз по странице к текущему дню месяца, так что вы сможете быстро перейти к последним запускам.
На сайте Designcember.com также есть специальная таблица стилей печати, в которой мы по сути предлагаем определенное изображение, которое лучше всего смотрится на бумаге размером 8,5" x 11", чтобы вы могли распечатать календарь самостоятельно и сохранять праздничную атмосферу круглый год.

В общем, тонна работы ушла на создание веселого, причудливого современного веб-опыта, чтобы отпраздновать разработку пользовательского интерфейса в течение всего месяца декабря. Надеемся, вам понравилось!