Uma visão geral básica de como criar uma experiência semelhante aos Stories do Instagram na Web.
Nesta postagem, quero compartilhar ideias sobre como criar um componente de Stories para a Web que seja responsivo, compatível com navegação por teclado e funcione em vários navegadores.
Se você preferir uma demonstração prática de como criar esse componente de Stories, confira o codelab do componente de Stories.
Se preferir vídeo, confira uma versão desta postagem no YouTube:
Visão geral
Dois exemplos conhecidos da UX das Histórias são as Histórias do Snapchat e do Instagram (sem falar dos fleets). Em termos gerais de UX, as Histórias costumam ser um padrão exclusivo para dispositivos móveis e centrado em toques para navegar por várias assinaturas. Por exemplo, no Instagram, os usuários abrem o story de um amigo e passam pelas fotos nele. Geralmente, eles fazem isso com vários amigos de uma vez. Ao tocar no lado direito do dispositivo, o usuário pula para a próxima história desse amigo. Ao deslizar para a direita, o usuário pula para outro amigo. Um componente de matéria é bastante semelhante a um carrossel, mas permite navegar em uma matriz multidimensional em vez de uma unidimensional. É como se houvesse um carrossel dentro de cada carrossel. 🤯

Segundo carrossel "empilhado" de histórias
👍 Lista em uma lista, também conhecida como matriz multidimensional
Escolher as ferramentas certas para o trabalho
No geral, achei esse componente bem simples de criar, graças a alguns recursos críticos da plataforma da Web. Vamos falar sobre elas!
Grade CSS
Nosso layout não foi difícil para o CSS Grid, já que ele tem algumas maneiras eficientes de organizar o conteúdo.
Layout de amigos
Nosso 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 grid
:
- Preenchemos explicitamente a janela de visualização em dispositivos móveis com
100vh
e100vw
e restringimos o tamanho em computadores. /
separa nossos modelos de linha e coluna.auto-flow
é traduzido paragrid-auto-flow: column
- O modelo de ajuste 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 dos Stories do Snapchat e do Instagram, cada coluna será um Story de um amigo. Queremos que as histórias dos amigos continuem fora da janela de visualização para que tenhamos onde rolar. O Grid vai criar quantas colunas forem necessárias para organizar seu HTML em cada história de amigo, criando um contêiner de rolagem dinâmico e responsivo para nós. O Grid nos permitiu centralizar todo o efeito.
Empilhamento
Para cada amigo, precisamos das histórias em um estado pronto para paginação. Para me preparar para animações e outros padrões divertidos, escolhi uma pilha. Quando digo "pilha", quero dizer como se você estivesse 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
em fluxo. Não foi necessário fazer nada com o posicionamento absolute
ou z-index
. Também não foi necessário corrigir a caixa com height: 100%
ou width: 100%
. A grade principal
já definiu o tamanho da janela de visualização da imagem da matéria. Portanto, nenhum desses componentes
precisou ser informado para preenchê-la.
Pontos de ajuste de rolagem CSS
A especificação de pontos de ajuste de rolagem CSS facilita o bloqueio de elementos na janela de visualização ao rolar. Antes da existência dessas propriedades de CSS, era necessário usar JavaScript, o que era… complicado, para dizer o mínimo. Confira Introducing CSS Scroll Snap Points de Sarah Drasner para uma ótima explicação de como usá-los.
scroll-snap-points
.
Sem ele, os usuários podem rolar livremente como de costume. Com ele, o navegador fica suavemente em cada item.
.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 de pontos de ajuste de rolagem afirma que pressionar as teclas Seta para a esquerda e Seta para a direita deve mover pelos pontos de ajuste por padrão.
- Uma especificação em crescimento. A especificação de pontos de ajuste de rolagem está recebendo novos recursos e melhorias o tempo todo, o que significa que meu componente de Stories provavelmente só vai melhorar daqui para frente.
- Facilidade de implementação. Os pontos de ajuste de rolagem são praticamente criados para o caso de uso de paginação horizontal centrada no toque.
- Inércia livre no estilo de plataforma. Cada plataforma vai rolar e ficar parada no próprio estilo, em vez de uma inércia normalizada, que pode ter um estilo estranho de rolagem e parada.
Compatibilidade entre 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 nas funcionalidades e no suporte.
No entanto, alguns CSS não foram aplicados, 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 CSS. Ao contrário dos Stories, um carrossel nem sempre precisa parar em cada imagem depois que um usuário interage com ela. Pode ser bom ou até recomendado
passar rapidamente pelo carrossel. Já as histórias são melhores para navegar uma por uma, e é exatamente isso que o scroll-snap-stop
oferece.
.user {
scroll-snap-align: start;
scroll-snap-stop: always;
}
No momento em que este post foi escrito, scroll-snap-stop
só era compatível com navegadores baseados no Chromium. Confira as atualizações em
Compatibilidade de navegadores. No entanto, isso não é um bloqueador. Isso significa apenas que, em navegadores não compatíveis, os usuários podem pular um amigo por acidente. Então, os usuários só precisam ter mais cuidado, ou
vamos precisar escrever 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á rolou uma caixa de diálogo modal e, de repente, começou a rolar o conteúdo atrás dela?
overscroll-behavior
permite que o desenvolvedor prenda essa rolagem e nunca a
deixe sair. É bom para todos os tipos de ocasiões. O componente Minhas histórias usa isso
para impedir que outros gestos de deslizar e rolar saiam do
componente.
.stories {
overflow-x: auto;
overscroll-behavior: contain;
}
Safari e Opera foram os dois navegadores que não ofereceram suporte a isso, e não há problema nenhum. Esses usuários terão uma experiência de rolagem em excesso como de costume e talvez nunca percebam essa melhoria. Eu sou muito fã e gosto de incluir esse efeito em quase todos os recursos de rolagem excessiva que implemento. É uma adição inofensiva que só pode melhorar a experiência do usuário.
scrollIntoView({behavior: 'smooth'})
Quando um usuário toca ou clica e chega ao final de um conjunto de stories de um amigo,
é hora de passar para o próximo amigo no conjunto de pontos de ajuste de rolagem. Com
JavaScript, conseguimos referenciar o próximo amigo e pedir que ele seja
rolado para a visualização. O suporte para os conceitos básicos é ótimo. Todos os navegadores
rolaram para mostrar. Mas nem todos os navegadores fizeram isso 'smooth'
. Isso significa apenas que
ele é rolado para a visualização em vez de ser ajustado.
element.scrollIntoView({
behavior: 'smooth'
})
O Safari era o único navegador que não oferecia suporte a behavior: 'smooth'
aqui. Confira as atualizações em
Compatibilidade de navegadores.
Na prática
Agora que você sabe como eu fiz isso, como você 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 adicionar à seção Remixes da comunidade abaixo.
Remixes da comunidade
- @geoffrich_ com Svelte: demo e code
- @GauteMeekOlsen com Vue: demonstração + código
- @AnaestheticsApp com Lit: demo e code