Design de edifícios

Uma espiada no processo e nas ferramentas usadas para criar a experiência de estilo de calendário de festas do Designcember.

No espírito de dezembro e nas diversas agendas que as pessoas usam para fazer a contagem regressiva e comemorar, queríamos destacar o conteúdo da Web da comunidade e da equipe do Chrome. Todos os dias, destacamos um conteúdo relacionado ao desenvolvimento de IU e design, totalizando 31 destaques, entre eles 26 novos sites de demonstração, ferramentas, anúncios, podcasts, vídeos, artigos e estudos de caso.

Veja a experiência completa em designcember.com.

O site da Designcember.

Visão geral

Nosso objetivo era oferecer uma experiência na Web acessível, moderna, caprichosa e responsiva com o menor número possível de bytes. Queríamos destacar novas APIs responsivas, como consultas de contêiner, e incluir um belo exemplo de modo escuro em um site focado em design e com muitos recursos. Para isso, compactamos arquivos, oferecemos vários formatos, usamos ferramentas de build otimizadas para a geração de sites estáticos, lançamos um novo polyfill e muito mais.

Começar com a fantasia

A ideia do site do calendário do Designcember era funcionar como um espaço para mostrar todo o trabalho que queríamos destacar durante o mês de dezembro, atuando como um site de demonstração. Decidimos criar um edifício de apartamentos responsivo que pudesse ficar mais alto e estreito ou mais curto e largo, com janelas que se reorganizavam dentro do frame. Cada janela representava um dia (e, portanto, um conteúdo). Trabalhamos com a ilustradora Alice Lee para dar vida à nossa visão.

Esboços do esqueleto da página do Designcember.

Alice foi inspiradora, compartilhando processos e esboços que eram interessantes mesmo nos primeiros conceitos. Enquanto ela trabalhava na arte, nós hackeamos a arquitetura. As primeiras discussões foram sobre o layout macro, o edifício e as janelas. Como as janelas se adaptariam a uma, duas ou três colunas à medida que mais espaço de visualização ficasse disponível? Até onde eles podem encolher ou esticar? Qual seria o tamanho máximo do edifício? Qual seria o deslocamento das janelas?

Confira um exemplo de protótipo responsivo usando grid-auto-flow: dense para mostrar como as janelas podem ser colocadas automaticamente pelo algoritmo de grade. Rapidamente percebemos que, embora as grades de proporção funcionassem perfeitamente para mostrar arte, elas não deram a oportunidade de permitir que as janelas aumentassem e encolhiam para um espaço disponível não uniforme e mostrassem o poder das consultas de contêiner.

Animação que mostra como este wireframe responde a diferentes tamanhos de tela.
Confira esta demonstração no CodePen.

Quando a grade geral ficou relativamente estável e transmitiu um senso de direção para a capacidade de resposta do edifício e das janelas, pudemos nos concentrar em uma única janela. Algumas janelas se esticavam, encolhiam, apertavam, cresciam e se recompunham mais do que outras na grade.

Wireframes mostrando como as janelas são exibidas em diferentes pontos de interrupção.

Cada janela precisaria processar uma certa quantidade de turbulência de redimensionamento. Confira abaixo um protótipo de uma janela que demonstra a resposta dela a turbulências, mostrando o quanto podemos esperar que cada janela interativa se ajuste.

Animação de janela com spritesheets

Algumas janelas têm animações para aumentar a interação com a experiência. As animações são desenhadas à mão, quadro a quadro, no Photoshop. Cada frame é exportado, transformado em uma spritesheet com este gerador de spritesheet e otimizado com o Squoosh. A animação CSS usa background-position-x e animation-timing-function, conforme mostrado no exemplo a seguir.

.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%; }
}

Animação mostrando a janela do primeiro dia.

Algumas animações, como a caixa-dinheiro do dia seis, foram animações CSS baseadas em etapas. Conseguimos esse efeito com uma técnica semelhante, usando steps(), mas os keyframes eram posições de transformação do CSS em vez de posições de plano de fundo.

Mascaramento de CSS

Algumas janelas tinham formas únicas. Usamos máscaras e aspect-ratio para criar uma janela adaptável, com formato exclusivo e escalonável.

Para criar uma máscara, como esta para a janela oito, foram necessárias algumas habilidades clássicas do Photoshop, além de um pouco de conhecimento sobre como as máscaras na Web funcionam. Vamos analisar a janela do dia 8.

A janela do dia 8.

Para se tornar uma máscara, a forma interna do trevo de quatro folhas precisa ser isolada como uma forma e preenchida com a cor branca. O branco diz ao CSS qual conteúdo permanece, e tudo o que estiver fora dele não. No Photoshop, o interior da janela foi selecionado, com borda de 1 pixel (para remover problemas de aliasing), preenchido com branco e exportado com a mesma altura e largura do frame da janela. Dessa forma, o frame e a máscara podem ser sobrepostos diretamente um sobre o outro, mostrando o conteúdo interno dentro do frame como esperado.

Imagem da máscara de trevo

Depois de concluído, o conteúdo da janela pode ser modificado e sempre parecer permanecer dentro do frame personalizado. A imagem a seguir mostra a versão do modo escuro da janela, com um gradiente de plano de fundo diferente e um filtro CSS de brilho aplicado à luz.

A janela do oitavo dia no modo escuro.

O mascaramento também oferece suporte a janelas responsivas baseadas em consultas de contêineres. Na janela nove, há um personagem que está oculto atrás de uma máscara até que a janela fique mais estreita. Para garantir que o usuário não pudesse ajustar a imagem fora do frame, Alice completou o personagem inteiro para nós. O personagem é mascarado na janela, mas as plantas não. Por isso, outro desafio enfrentado foi sobrepor elementos mascarados com camadas não mascaradas e garantir que todos eles fiquem bem dimensionados juntos.

A imagem a seguir mostra como ela fica sem a máscara na janela e no caractere.

A imagem da janela nove sem a máscara.

Esmagar a arte

Para manter a fidelidade da ilustração e garantir que as telas de alta definição não tivessem uma experiência do usuário desfocada, Alice trabalhou com uma proporção de 3x pixels. O plano era usar o imgix e exibir imagens e formatos otimizados no servidor, mas descobrimos que os ajustes manuais com a ferramenta Squoosh poderiam economizar 50% ou mais.

Como usar o Squoosh para compactar imagens.

A ilustração tem desafios únicos para compactação, especialmente o estilo de borda áspera e o traço de pincel que Alice usou. Escolhemos usar o Squoosh para cada três imagens png exportadas pelo Photoshop para um png, webp e avif menores. Cada tipo de arquivo possui recursos especiais de compactação, e foi preciso compactar mais de 50 imagens para encontrar configurações de otimização comuns.

A Squoosh CLI se tornou essencial, com mais de 200 imagens para otimizar. Tudo isso levaria dias. Depois de definir as configurações de otimização comuns, as disponibilizamos como instruções de linha de comando e processamos em lote pastas inteiras de imagens PNG em suas contrapartes compactadas WebP e AVIF.

Confira um exemplo de comando squoosh da CLI AVIF usado:

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

Com a arte otimizada verificada no repositório, podemos começar a carregá-la do 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>

Era repetitivo escrever o código-fonte da imagem. Por isso, criamos um componente Astro para incorporar imagens com uma linha de código.

<Pic filename="day1/inner-frame" role="presentation" />

Usuários de leitores de tela e teclados

Grande parte da experiência do Designcember é feita por meio de janelas interativas e de arte. Para nós, era importante que um usuário de teclado pudesse usar o site e conferir as janelas e que os usuários de leitores de tela tivessem uma experiência narrada agradável.

Por exemplo, ao incorporar as imagens, usamos role="presentation" para marcar a imagem como de apresentação para leitores de tela. Achamos que uma experiência do usuário com entre 5 e 12 descrições alt fraturadas seria uma experiência ruim. Então, marcamos as imagens como de apresentação e fornecemos uma narração geral da janela. Percorrer as janelas em um leitor de tela cria uma boa sensação de narrativa, e esperávamos que isso ajudasse a transmitir a magia e a diversão que o site quer compartilhar.

O vídeo a seguir mostra uma demonstração da experiência do teclado. As teclas Tab, Enter, barra de espaço e Escape são usadas para orquestrar o foco nos pop-ups e nas janelas.

A experiência do leitor de tela tem atributos ARIA especiais que esclarecem o conteúdo. Por exemplo, os links para os dias dizem apenas "um" ou "dois", mas com alguns ARIA adicionados, eles são anunciados como "Dia um" e "Dia dois". Além disso, todas as imagens são resumidas em um único rótulo para que cada janela tenha uma descrição.

Astro, gerador de sites estático e orientado a componentes

O Astro facilitou o trabalho em equipe no site. O modelo de componente era familiar para desenvolvedores do Angular e do React, e o sistema de estilo de nome de classe com escopo ajudou cada desenvolvedor a saber que o trabalho deles em uma janela não entraria em conflito com ninguém.

Dias como componentes

Cada dia era um componente que buscava o status em um repositório de dados de tempo de build. Isso nos permite executar a lógica do modelo antes que o HTML chegue ao navegador. A lógica determinaria se o dia precisa mostrar a dica ou não, já que os dias inativos não têm pop-ups.

Os builds são executados a cada hora, e o repositório de dados do tempo de build desbloqueia um novo dia quando o servidor de build passa da meia-noite. Esses pequenos sistemas auto-atualizados e autossuficientes mantêm o site atualizado.

Estilos com escopo e propriedades abertas

Estilos de escopo do Astro escritos dentro do modelo de componente, o que facilitou a distribuição da carga de trabalho entre muitos membros da equipe e também deixou os Props abertos divertidos. Os estilos Open Props normalize.css foram úteis com o tema adaptável (claro e escuro) e ajudaram a organizar conteúdo como parágrafos e cabeçalhos.

Como adotantes iniciais do Astro, enfrentamos alguns problemas com o PostCSS. Por exemplo, não foi possível atualizar para a versão mais recente do Astro devido a muitos problemas de build. É possível gastar mais tempo aqui, otimizando os fluxos de trabalho de criação e do desenvolvedor.

Contêineres flexíveis

Algumas janelas aumentam e diminuem, mantendo a proporção para preservar a arte. Usamos outras janelas para mostrar o poder da arquitetura baseada em componentes com consultas de contêiner. As consultas de contêiner significam que as janelas podem ter informações de estilo responsivo individuais e se ajustar com base nos próprios tamanhos. Algumas janelas passaram de estreitas para largas e precisaram ajustar o tamanho e a posição da mídia.

Uma demonstração de como as janelas mudam conforme elas têm mais espaço.

À medida que mais espaço fica disponível para uma janela, podemos adaptar o tamanho ou os elementos filhos da janela para caber. Para atender às janelas adaptativas, as consultas de contêiner não seriam apenas divertidas de mostrar, mas também seriam necessárias e simplificariam drasticamente a orquestração de determinados layouts.

.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;
  }
}

Essa abordagem é diferente de manter uma proporção. Ele oferece mais controle e mais oportunidades. Com um determinado tamanho, muitos filhos mudam para se adaptar a um novo layout.

As consultas em contêineres também nos permitiram oferecer suporte à contenção de direção de bloco (vertical). Assim, à medida que uma janela aumentava de tamanho, pudemos ajustar seus estilos para se ajustarem adequadamente. Isso pode ser visto nas consultas baseadas em altura, que usamos de forma independente, e nas consultas baseadas em largura:

.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);
  }
}

Também usamos consultas de contêiner para mostrar e ocultar detalhes, já que a arte ficava cada vez mais cheia em tamanhos menores e mais vazia em tamanhos maiores. A janela 9 é um ótimo exemplo de como isso funciona:

Suporte a vários navegadores

Para criar uma ótima experiência moderna em vários navegadores, especialmente para APIs experimentais, como consultas de contêiner, precisamos de um ótimo polyfill. Enviamos uma chamada à nossa equipe, e Surma liderou o desenvolvimento de um novo polyfill de consulta de contêiner. O polyfill depende de ResizeObserver, MutationObserver e da função CSS :is(). Portanto, todos os navegadores modernos são compatíveis com o polyfill, especificamente o Chrome e o Edge a partir da versão 88, o Firefox a partir da versão 78 e o Safari a partir da versão 14. O uso do polyfill permite qualquer uma das seguintes sintaxes:

/* These are all equivalent */
@container (min-width: 200px) {
  /* ... */
}
@container (width >= 200px) {
  /* ... */
}
@container size(width >= 200px) {
  /* ... */
}

Modo escuro

Versões claras e escuras do site Designcember, lado a lado.

Um último toque essencial para o site do Designcember foi um lindo tema escuro. Queríamos mostrar como você pode usar a arte para participar ativamente da criação de uma ótima experiência no modo escuro. Para isso, ajustamos os estilos de plano de fundo de cada janela de forma programática e usamos o máximo de CSS possível ao criar a arte da janela. A maioria dos planos de fundo eram gradientes CSS para facilitar o ajuste dos valores de cor. Em seguida, colocamos a arte sobre elas.

Outros easter eggs

Toques pessoais

Adicionamos alguns toques pessoais à página para dar mais personalidade ao site. O primeiro foi o elenco de personagens, inspirado na nossa equipe. Também incluímos um cursor em estilo antigo sobre dias inativos e testamos o estilo favicon.

Estilos de cursor personalizados e opções de favicon

Toques funcionais

Um dos toques funcionais adicionais é a funcionalidade "Ir para hoje", com um pássaro sentado no topo do edifício. Clicar ou pressionar Enter no pássaro leva você para o dia atual do mês, para que você possa acessar rapidamente os lançamentos mais recentes.

O Designcember.com também tem uma folha de estilo de impressão especial, em que exibimos uma imagem específica que funciona melhor em papel de 21,5 x 28 cm para que você possa imprimir o calendário e comemorar o ano todo.

Impressão em tamanho de pôster do design do calendário.
Una segurando uma impressão grande do calendário.

No geral, foi necessário muito trabalho para criar uma experiência da Web moderna, divertida e inusitada para comemorar o desenvolvimento da interface durante todo o mês de dezembro. Esperamos que você tenha gostado!

Partes do calendário com anotações e observações visuais