Uma visão geral básica de como criar uma experiência semelhante às Histórias 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 conhecidos da UX das histórias são as Histórias do Snapchat e do Instagram (sem mencionar as 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 navegam pelas imagens dela. Eles geralmente fazem isso com muitos 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 de história é bastante semelhante a um carrossel, mas permite navegar em uma matriz multidimensional em vez de 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 falar sobre isso.
Grade CSS
Nosso layout não foi difícil para o CSS Grid, porque 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 analisar o layout 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
Para cada amigo, precisamos das histórias em um estado pronto para paginação. Para preparar a animação e outros padrões 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 da existência dessas propriedades CSS, era necessário usar JavaScript, e isso era... complicado, para dizer o mínimo. 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 os pontos de ajuste de rolagem por alguns motivos:
- Acessibilidade sem custo financeiro. A especificação dos pontos de ajuste de rolagem indica 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 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 as 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 até mesmo recomendado
navegar rapidamente pelo 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ó tinha suporte em navegadores baseados no
Chromium. Confira as atualizações em
Compatibilidade com navegadores. No entanto, não é um bloqueador. Isso significa apenas que, em navegadores sem suporte,
os usuários podem pular um amigo acidentalmente. Portanto, os usuários precisam ter mais cuidado ou
precisamos escrever JavaScript para garantir que um amigo pulado 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 esse rolagem e nunca deixe
que ela saia. É bom para todos os tipos de ocasiões. O componente "Minhas histórias" usa essa função
para evitar que outros gestos de deslizar e rolar saiam do
componente.
.stories {
overflow-x: auto;
overscroll-behavior: contain;
}
O Safari e o Opera foram os dois navegadores que não ofereciam esse recurso, e isso é totalmente normal. Esses usuários vão ter uma experiência de rolagem excessiva como estão acostumados e talvez nem percebam essa melhoria. Sou fã desse recurso e gosto de incluí-lo em 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 os conceitos básicos é ótimo. Todos os navegadores
exibem o conteúdo. Mas nem todos os navegadores fizeram isso 'smooth'
. Isso significa apenas que
ele é 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, 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 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