Uma visão geral básica sobre como criar uma experiência semelhante aos Stories do Instagram na Web.
Neste post, quero compartilhar ideias sobre como criar um componente de Stories para a Web que seja responsivo, ofereça suporte à navegação por teclado e funcione em todos os navegadores.
Se você preferir uma demonstração prática de como criar esse componente do Stories, confira o codelab do componente do Stories.
Se preferir vídeos, confira a versão desta postagem no YouTube:
Visão geral
Dois exemplos famosos de UX de Stories são o Snapchat e o Instagram Stories, sem falar das frotas. Em termos gerais de UX, as Histórias geralmente são um padrão focado em toques e exclusivo para dispositivos móveis para navegar em várias assinaturas. Por exemplo, no Instagram, os usuários abrem a história de um amigo e conferem as fotos. Eles geralmente fazem isso com vários amigos ao mesmo tempo. Ao tocar no lado direito do dispositivo, o usuário pula para a próxima história do amigo. Ao deslizar para a direita, o usuário pula para um amigo diferente. Um componente Story é bastante semelhante a um carrossel, mas permite navegar em uma matriz multidimensional em vez de em uma matriz unidimensional. É como se houvesse um carrossel dentro de cada carrossel. 🤯
Como escolher as ferramentas certas para o trabalho
No geral, achei esse componente muito simples de criar, graças a alguns recursos importantes da plataforma da Web. Vamos explicar cada uma delas.
Grade CSS
Nosso layout não exigiu muito do CSS Grid, já que ele tem algumas maneiras eficientes de organizar o conteúdo.
Layout de amigos
O wrapper de componente .stories
principal é uma visualização de rolagem horizontal que prioriza dispositivos móveis:
.stories {
inline-size: 100vw;
block-size: 100vh;
display: grid;
grid: 1fr / auto-flow 100%;
gap: 1ch;
overflow-x: auto;
scroll-snap-type: x mandatory;
overscroll-behavior: contain;
touch-action: pan-x;
}
/* desktop constraint */
@media (hover: hover) and (min-width: 480px) {
max-inline-size: 480px;
max-block-size: 848px;
}
Vamos detalhar esse layout de grid
:
- Preenchemos explicitamente a viewport em dispositivos móveis com
100vh
e100vw
e restringimos o tamanho em computadores /
separa nossos modelos de linha e colunaauto-flow
é traduzido paragrid-auto-flow: column
- O modelo de fluxo automático é
100%
, que, neste caso, é a largura da janela de rolagem.
Em um smartphone, pense nisso como o tamanho da linha sendo a altura da janela de visualização e cada coluna sendo a largura da janela de visualização. Continuando com o exemplo do Snapchat e do Instagram, cada coluna será a história de um amigo. Queremos que as histórias de amigos continuem fora da viewport para que possamos rolar para baixo. A grade vai criar quantas colunas forem necessárias para o layout do HTML de cada história de amigo, criando um contêiner de rolagem dinâmico e responsivo para nós. A grade nos permitiu centralizar todo o efeito.
Empilhamento
Precisamos das histórias de cada amigo em um estado pronto para paginação. Para me preparar para a animação e outros desenhos divertidos, escolhi uma pilha. Quando digo "empilhamento", quero dizer que você está olhando para baixo em um sanduíche, não como se estivesse olhando de lado.
Com a grade CSS, podemos definir uma grade de célula única (ou seja, um quadrado), em que as linhas
e colunas compartilham um alias ([story]
), e cada filho é atribuído a esse
espaço de célula única com alias:
.user {
display: grid;
grid: [story] 1fr / [story] 1fr;
scroll-snap-align: start;
scroll-snap-stop: always;
}
.story {
grid-area: story;
background-size: cover;
…
}
Isso coloca nosso HTML no controle da ordem de empilhamento e também mantém todos os elementos
no fluxo. Não foi necessário fazer nada com o posicionamento absolute
ou z-index
e
não foi necessário corrigir a caixa com height: 100%
ou width: 100%
. A grade mãe
já definiu o tamanho da viewport da imagem da história. Portanto, nenhum desses componentes
precisa ser preenchido.
Pontos de quebra de rolagem do CSS
A especificação de pontos de fixação de rolagem do CSS facilita o bloqueio de elementos na janela de visualização durante a rolagem. Antes de existirem essas propriedades CSS, você precisava usar JavaScript, e isso era no mínimo complicado. Confira Introdução aos pontos de ajuste de rolagem do CSS de Sarah Drasner para uma explicação detalhada de como usá-los.
.stories { display: grid; grid: 1fr / auto-flow 100%; gap: 1ch; overflow-x: auto; scroll-snap-type: x mandatory; overscroll-behavior: contain; touch-action: pan-x; }
.user { display: grid; grid: [story] 1fr / [story] 1fr; scroll-snap-align: start; scroll-snap-stop: always; }
Escolhi pontos de ajuste de rolagem por alguns motivos:
- Acessibilidade sem custo financeiro. A especificação dos pontos de ajuste de rolagem indica que, ao pressionar as teclas de seta para a esquerda e seta para a direita, você passa pelos pontos de ajuste por padrão.
- Uma especificação em crescimento. A especificação de pontos de ajuste de rolagem recebe novos recursos e melhorias o tempo todo, o que significa que meu componente de histórias provavelmente vai melhorar cada vez mais.
- Facilidade de implementação. Os pontos de ajuste de rolagem são criados praticamente para o caso de uso de paginação horizontal com foco em toque.
- Inércia livre no estilo de plataforma. Cada plataforma vai rolar e descansar no estilo dela, em vez de inercia normalizada, que pode ter um estilo de rolagem e descanso estranho.
Compatibilidade com vários navegadores
Testamos no Opera, Firefox, Safari e Chrome, além de Android e iOS. Confira um breve resumo dos recursos da Web em que encontramos diferenças nos recursos e no suporte.
No entanto, alguns CSS não se aplicam, então algumas plataformas estão perdendo otimizações de UX. Gostei de não precisar gerenciar esses recursos e tenho certeza de que eles vão chegar a outros navegadores e plataformas.
scroll-snap-stop
Os carrosséis foram um dos principais casos de uso de UX que motivaram a criação da
especificação de pontos de ajuste de rolagem do CSS. Ao contrário das histórias, um carrossel nem sempre precisa parar
em cada imagem depois que um usuário interage com ela. Pode ser aceitável ou encorajado
percorrer rapidamente o carrossel. Já as histórias são melhor navegadas uma por vez,
e é exatamente isso que o scroll-snap-stop
oferece.
.user {
scroll-snap-align: start;
scroll-snap-stop: always;
}
No momento em que este artigo foi escrito, o scroll-snap-stop
só era compatível com navegadores baseados no Chromium. Confira as atualizações em
Compatibilidade com navegadores. No entanto, não é um bloqueador. Isso significa apenas que, em navegadores não compatíveis,
os usuários podem pular um amigo por acidente. Portanto, os usuários terão apenas que ser mais cuidadosos ou
precisaremos programar em JavaScript para garantir que um amigo ignorado não seja marcado como visualizado.
Leia mais na especificação se tiver interesse.
overscroll-behavior
Você já estava rolando uma modal quando, de repente,
começou a rolar o conteúdo por trás dela?
overscroll-behavior
permite que o desenvolvedor prenda essa rolagem e nunca deixe que ela
saia. É legal para todos os tipos de ocasião. O componente "My Stories" o usa
para evitar que outros gestos de deslizar e de rolagem saiam do
componente.
.stories {
overflow-x: auto;
overscroll-behavior: contain;
}
O Safari e o Opera eram os dois navegadores que não oferecevam suporte a isso, e não tem problema. Esses usuários vão ter uma experiência de rolagem excessiva como estão acostumados e talvez nem percebam essa melhoria. Pessoalmente, sou um grande fã e gosto de incluí-lo como parte de quase todos os recursos de rolagem que implemento. É uma adição inofensiva que só pode melhorar a UX.
scrollIntoView({behavior: 'smooth'})
Quando um usuário toca ou clica e chega ao final do conjunto de histórias de um amigo,
é hora de passar para o próximo amigo no conjunto de pontos de ajuste de rolagem. Com
JavaScript, foi possível fazer referência ao próximo amigo e solicitar que ele fosse
exibido. O suporte para o básico é ótimo, porque todos os navegadores
rolaram a tela para visualização. Mas nem todos os navegadores fizeram isso 'smooth'
. Isso significa apenas que
ele foi rolado para aparecer em vez de ser fixado.
element.scrollIntoView({
behavior: 'smooth'
})
O Safari foi o único navegador que não oferece suporte a behavior: 'smooth'
. Confira as atualizações em
Compatibilidade com navegadores.
Prático
Agora que você sabe como eu fiz isso, como faria?! Vamos diversificar nossas abordagens e aprender todas as maneiras de criar na Web. Crie um Glitch, envie um tweet com sua versão e eu vou adicioná-la à seção Remixes da comunidade abaixo.
Remixes da comunidade
- @geoffrich_ com Svelte: demonstração e código
- @GauteMeekOlsen com Vue: demonstração + código
- @AnaestheticsApp com Lit: demonstração e código