Designcember의 연말연시 달력 스타일 환경을 빌드하는 데 사용된 프로세스와 도구를 살펴봅니다.
Google은 12월의 분위기와 많은 사람들이 카운트다운과 기념을 위해 사용하는 다양한 캘린더에 힘입어 커뮤니티와 Chrome팀의 웹 콘텐츠를 조명하고자 했습니다. 매일 UI 개발 및 디자인 관련 콘텐츠를 하나씩 추천하여 총 31개의 추천 콘텐츠를 제공했으며, 이 중 26개는 새로운 데모 사이트, 도구, 공지사항, 팟캐스트, 동영상, 도움말, 사례 연구였습니다.
designcember.com에서 전체 환경을 확인하세요.
개요
Google의 목표는 최대한 적은 바이트로 접근성이 높고 기발하며 현대적이고 반응이 빠른 웹 환경을 제공하는 것이었습니다. 컨테이너 쿼리와 같은 새로운 반응형 API를 강조하고 디자인 중심의 애셋이 많은 웹사이트에 어두운 모드의 멋진 예시를 포함하고자 했습니다. 이를 위해 파일을 압축하고, 여러 형식을 제공하고, 정적 사이트 생성에 최적화된 빌드 도구를 사용하고, 새로운 폴리필을 제공하는 등 다양한 작업을 수행했습니다.
기발함으로 시작하기
Designcember 캘린더 사이트는 12월 한 달 동안 주목하고 싶은 모든 작품을 보여주는 쇼케이스 역할을 하면서 데모 사이트 자체의 역할을 하도록 고안되었습니다. 프레임 내에서 창문이 자동으로 재정렬되어 더 높고 좁거나 더 짧고 넓어질 수 있는 반응형 아파트 건물을 짓기로 했습니다. 각 기간은 하루 (즉, 하나의 콘텐츠)를 나타냅니다. YouTube는 비전을 실현하기 위해 일러스트레이터 앨리스 리와 협력했습니다.
앨리스는 초기 개념 단계에서도 흥미로운 프로세스와 스케치를 공유하여 영감을 주었습니다. 아트팀에서 아트를 제작하는 동안 저희는 아키텍처를 해킹했습니다. 초기에는 마이크로 레이아웃, 건물, 창문 등에 관해 논의했습니다. 표시 영역 공간을 사용할 수 있게 되면 창이 1개, 2개 또는 3개의 열에 맞춰 어떻게 조정될까요? 얼마나 줄이거나 늘릴 수 있나요? 건물의 최대 크기는 얼마인가요? 창문이 얼마나 이동하나요?
다음은 그리드 알고리즘이 창을 자동으로 배치하는 방법을 보여주는 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%; }
}
6일 차의 저금통과 같은 일부 애니메이션은 단계 기반 CSS 애니메이션이었습니다.
steps()
를 사용하는 유사한 기법으로 이 효과를 얻었으며, keyframe이 배경 위치 대신 CSS 변환 위치라는 점이 다릅니다.
CSS 마스킹
일부 창문은 독특한 모양을 하고 있었습니다. 마스크와 aspect-ratio
를 사용하여 확장 가능하고 고유한 모양을 지니며 적응형인 창을 만들었습니다.
창 8용 마스크와 같은 마스크를 만들려면 기존의 Photoshop 기술과 웹에서 마스크가 작동하는 방식에 관한 약간의 지식이 필요했습니다. 8일 차 기간을 살펴보겠습니다.
마스크가 되려면 안쪽의 네 잎 클로버 유형 도형이 자체 모양으로 격리되고 흰색으로 채워져야 합니다. 흰색은 CSS에 어떤 콘텐츠가 유지되고 흰색 외부의 모든 콘텐츠는 유지되지 않는다고 알려줍니다. Photoshop에서 창 안쪽을 선택하고 1픽셀 페더링(앨리어싱 문제를 제거하기 위해)한 다음 흰색으로 채우고 창 프레임과 동일한 높이와 너비로 내보냈습니다. 이렇게 하면 프레임과 마스크를 서로 직접 겹쳐서 프레임 내의 내부 콘텐츠를 예상대로 표시할 수 있습니다.
완료되면 창의 콘텐츠를 수정할 수 있으며 항상 맞춤 프레임 내에 머무르는 것처럼 보입니다. 다음 이미지는 다른 배경 그라데이션과 조명에 적용된 발광 CSS 필터가 있는 창의 어두운 모드 버전을 보여줍니다.
마스킹은 반응형 컨테이너 쿼리 기반 창도 지원합니다. 창 9에는 창이 더 좁아질 때까지 가면 뒤에 숨겨져 있는 캐릭터가 있습니다. 사용자가 프레임에서 이미지를 조정할 수 없도록 앨리스는 전체 캐릭터를 완성했습니다. 캐릭터는 창 안에서 마스크 처리되지만 식물은 마스크 처리되지 않으므로 마스크 처리된 요소를 마스크 처리되지 않은 레이어와 레이어링하고 모두 함께 잘 확장되도록 하는 것이 또 다른 과제였습니다.
다음 이미지는 창과 캐릭터에 마스크가 적용되지 않은 모습을 보여줍니다.
아트 스크러시
앨리스는 일러스트레이션의 재현성을 유지하고 고화질 화면에서 흐릿한 사용자 환경이 발생하지 않도록 3배 픽셀 비율로 작업했습니다. imgix를 사용하고 최적화된 이미지와 형식을 서버에 제공하겠다는 계획을 세웠지만, Squoosh 툴을 사용해 수동으로 조정하면 비용을 50% 이상 절약할 수 있다는 사실을 알게 되었습니다.
일러스트레이션에는 압축과 관련하여 고유한 문제가 있습니다. 특히 앨리스가 사용한 브러시 획과 투명한 거친 가장자리 스타일이 그렇습니다. Photoshop에서 내보낸 각 3x개의 PNG 이미지를 Squoosh에서 더 작은 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, 스페이스바, Esc 키는 모두 창 팝업과 창 간에 포커스를 조정하는 데 사용됩니다.
스크린 리더 환경에는 콘텐츠를 더 명확하게 파악할 수 있도록 특별한 ARIA 속성이 있습니다. 예를 들어 일일 링크에는 '일' 또는 '둘'로만 표시되지만 일부 ARIA가 추가되어 '1일 차'와 '2일 차'로 발표됩니다. 또한 모든 이미지가 단일 라벨로 요약되므로 각 창에 설명이 있습니다.
Astro: 정적 우선, 구성요소 기반 사이트 생성기
Astro를 사용하면 팀이 사이트에서 쉽게 협업할 수 있었습니다. 구성요소 모델은 Angular와 React 개발자 모두에게 익숙했으며, 범위 지정된 클래스 이름 스타일 시스템은 각 개발자가 창에서의 작업이 다른 사람과 충돌하지 않는다는 것을 알 수 있도록 도와주었습니다.
일 수(구성요소)
각 매일은 빌드 시간 데이터 저장소에서 상태를 가져오는 구성요소였습니다. 이렇게 하면 HTML이 브라우저에 도달하기 전에 템플릿 로직을 실행할 수 있습니다. 비활성 날에는 팝업이 표시되지 않으므로 로직은 해당 날짜에 도움말을 표시할지 여부를 결정합니다.
빌드는 매시간 실행되며 빌드 서버가 자정을 넘으면 빌드 시간 데이터 스토어에서 새 날짜를 잠금 해제합니다. 이러한 자체 업데이트 및 자체 충족형 소형 시스템은 사이트를 최신 상태로 유지합니다.
범위 지정된 스타일 및 공개 속성
Astro는 구성요소 모델 내부에 작성된 스타일을 범위 지정하여 여러 팀원 간에 워크로드를 더 쉽게 분산하고 Open Props를 더 재미있게 사용할 수 있도록 했습니다. Open Props normalize.css 스타일은 적응형(밝은 테마 및 어두운 테마) 테마에 유용했으며, 단락 및 헤더와 같은 콘텐츠를 처리하는 데도 도움이 되었습니다.
Astro를 초기에 도입한 Google에서는 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를 위한 최신 멀티브라우저 환경을 만들려면 우수한 폴리필이 필요합니다. Google이 팀에 요청을 보냈고 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 그라데이션이었으므로 색상 값을 더 쉽게 조정할 수 있습니다. 그런 다음 아트를 위에 레이어링했습니다.
기타 이스터 에그
맞춤설정
사이트에 더 많은 개성을 부여하기 위해 페이지에 몇 가지 개인적인 터치를 추가했습니다. 첫 번째는 우리 팀에서 영감을 받은 캐릭터들입니다. 또한 비활성 상태일 때는 회전식 스타일의 커서를 포함하고 favicon 스타일을 조정했습니다.
기능성
추가된 기능 중 하나는 건물 꼭대기에 새가 있는 '오늘로 이동' 기능입니다. 이 새를 클릭하거나 Enter 키를 누르면 페이지가 현재 날짜로 아래로 이동하므로 최신 출시 소식을 빠르게 확인할 수 있습니다.
Designcember.com에는 특별한 인쇄 스타일시트도 있습니다. 이 스타일시트에서는 8.5인치 x 11인치 종이에 가장 적합한 특정 이미지를 제공하므로 캘린더를 직접 인쇄하여 일 년 내내 연말연시 분위기를 즐길 수 있습니다.
12월 한 달 동안 UI 개발을 기념하기 위해 재미있고 기발한 최신 웹 환경을 만드는 데 많은 노력을 기울였습니다. 유익한 시간이었기를 바랍니다.