Animações em página inteira usando CSS
O Internet Explorer 9 introduziu o suporte ao CSS 2D Transforms. O Internet Explorer 10 Developer Preview adicionou suporte ao CSS 3D Transforms e ao CSS Animations. Ao ligar a sua GPU e executar assincronamente de um JavaScript comum, esses recursos do IE10 fornecem uma alternativa mais segura e flexível do que as animações tradicionais baseadas em script para um conteúdo Web.
Em postagens anteriores do blog, falamos de CSS 3D Transforms e também de CSS Animations e Transitions. Nesta postagem, introduziremos um caso de uso “não convencional” dessas tecnologias ao descrevermos o conceito de “animações em página inteira”, que pode ser usado durante o processo de navegação para adicionar fluidez e continuidade à navegação. Nosso objetivo é criar uma experiência de navegação mais fluida na qual o conteúdo surge suavemente para ser exibido quando o usuário visita uma página e sai da exibição quando o usuário clica em um link ou realiza alguma ação relevante.
Esses efeitos podem ser obtidos ao transformar o elemento HTML <body>
usando CSS Animations. No entanto, esse caso apresenta algumas considerações que achávamos que mereciam ser discutidas, como o efeito do layout e do tamanho durante a transformação de <body>
, assim como a marcação correta do tempo das navegações das páginas para que eles mesclem adequadamente com nossas animações.
Os exemplos de códigos nesta postagem utilizam marcação CSS sem prefixos de acordo com o suporte do IE10 Release Preview. Outros navegadores devem solicitar prefixos de fornecedores para as propriedades CSS Animations e CSS Transforms usadas.
Transformando o conteúdo completo de uma página
Os CSS Transforms são definidos com base nas propriedades estilísticas de um elemento HTML DOM. Por exemplo, a marcação para o giro de 45 graus de um elemento ao longo de seu próprio eixo Z seria assim:
#element {
transform: rotateZ(45deg);
}
Anexar um transform ao elemento <body>
do seu documento HTML funciona exatamente da mesma maneira. Portanto, realizar uma ação para adicionar declarativamente o mesmo efeito ao <body>
do seu documento, poderia ser feito desta maneira:
body {
transform: rotateZ(45deg);
}
Vejamos uma imagem antes e depois de uma página ao aplicarmos um código transfom ao elemento body:
Aplicando rotateZ(45deg) transform ao elemento body de um documento.
Para transformações de três dimensões, a especificação CSS Transforms define a propriedade perspective
que pode ser especificada no pai do elemento que estamos transformando. Ao transformar o elemento <body>
do seu conteúdo, ela deve ser aplicada ao elemento <html>
que está acima dele na hierarquia DOM. Como fazer isso de maneira simplificada:
html {
perspective: 500px;
}
Combinando isso com um rotateY(45deg)
transform no elemento <body>
traz o seguinte resultado:
Aplicação de rotateY(45deg) transform em <body> com perspective: 500px definidos no <html>.
Podemos manipular a propriedade do transform-origin
no elemento body para obter resultados interessantes. Vejamos alguns exemplos:
body {
transform-origin: 50% 100%;
transform: rotateX(45deg);
}
A marcação acima define um giro no eixo X para o elemento body enquanto altera a origem dos giros para a parte inferior do elemento utilizando transform-origin
. Isso proporcionará o giro do conteúdo do documento para “dentro” da tela da seguinte maneira:
Também podemos manipular a propriedade perspective-origin
no elemento raiz de nosso documento para alcançar um efeito de projeção para fora do eixo. Alterando o estilo de <html>
para:
html {
perspective: 500px;
perspective-origin: 90% 50%;
}
Nossa página agora está assim:
Ao usar CSS Transforms, podemos facilmente manipular a aparência completa do conteúdo da página. Já que as regras comuns de layout e de tamanho ainda se aplicam, alguns transforms no elemento body (em particular aquelas que utilizam valores de porcentagem ou que dependem da propriedade transform-origin
) podem resultar em efeitos visuais diferentes dependendo do conteúdo da nossa página. Basta lembrar de nosso exemplo rotateX(45deg)
anterior com transform-origin
definido para 50% 100%
.
Abaixo, é possível observar os resultados antes e depois da aplicação do transform.
Observe como o conteúdo não se concentra na parte inferior da janela, e sim em um ponto determinado fora do visor. Isso é um comportamento esperado do CSS Transforms: o elemento <body>
é detalhado normalmente e depois é girado ao longo de sua extremidade inferior que está em algum ponto fora da tela. Você também notará que o volume real do conteúdo foi expandido (dê uma olhada nas barras de rolagem na imagem “depois”) para acomodar o conteúdo transformado (o fato de estarmos utilizando projeção em perspectiva torna este efeito ainda mais pronunciado).
Portanto, como lidamos com um conteúdo de tamanho arbitrário ao aplicar transforms em nosso elemento body? A personalização de todo o conteúdo para assegurar que o tamanho de body não se expanda mais do que uma quantidade específica pode ser irreal. Em vez disso, podemos utilizar um padrão simples HTML/CSS que nos permita adaptar o tamanho do elemento body para o da janela do navegador e o conteúdo de acréscimo dentro de um wrapper<div>
. A marcação a seguir produz exatamente isso:
html, body {
width: 100%;
height: 100%;
min-width: 100%;
max-width: 100%;
padding: 0;
margin: 0;
overflow: hidden;
}
#Wrapper {
position: absolute;
width: 100%;
height: 100%;
overflow: scroll;
}
A ilustração abaixo mostra o que ocorre quando uma página é exibida verticalmente e nós aplicamos rotateY(45deg)
transform ao elemento <body>
de nosso documento diretamente (esquerda) e utilizando o padrão wrapper (direita):
A aplicação direta do transform resulta em uma exibição inclinada devido à projeção fora do eixo (já que não estamos mais olhando o “centro” do elemento body). Ao utilizarmos um padrão wrapper nos asseguramos de que a propriedade perspective-origin
do elemento <html>
(50% 50%
por padrão) seja sempre corretamente centralizada em relação ao elemento <body>
, nos oferecendo assim um efeito visual agradável.
Ao utilizarmos o padrão acima e definirmos, sempre que possível, o CSS Transforms com valores de porcentagem, podemos afetar nosso elemento <body>
de maneira consistente, independentemente do tamanho de seu conteúdo.
De Transforms à Animations
Tendo definido a complexidade da aplicação do CSS Transforms ao elemento <body>
, o CSS Animations é o próximo passo. Ao seguir os princípios descritos acima, podemos criar animações que dão destaque (ou removem) da exibição o nosso conteúdo Web de maneiras interessantes.
Considere esta regra @keyframes
básica:
@keyframes rotateInLeft {
from {
transform-origin: 0% 0%;
transform: rotateY(180deg);
}
to {
transform-origin: 0% 0%;
transform: rotateY(0deg);
}
}
Ao ser aplicada em um elemento, esta animação iniciará um giro do lado esquerdo. Ao ser aplicado em um elemento <body>
que utiliza nosso padrão wrapper, o resultado visual é mais interessante. O documento fará o giro de fora da área visível da janela do navegador até ser exibido completamente:
Semelhantemente, podemos compor animações que removem de maneira fluida o nosso conteúdo Web exibido. Por exemplo, se quiséssemos que nossa página desaparecesse ao fundo girando, poderíamos utilizar algo assim:
@keyframes whirlOut {
to {
transform: scale(0)rotateZ(1260deg);
}
}
E o resultado visual seria o seguinte:
Já que podemos utilizar o todo o potencial do CSS Animations em nosso conteúdo Web, há bastante flexibilidade na geração desses efeitos de página (e certamente não estamos limitados ao uso do CSS Transforms). Após termos composto os efeitos que desejamos aplicar em nosso conteúdo, como fazemos para que eles sejam acionados durante o processo de navegação da página?
Anexando Animations ao <body>
Nossa meta é utilizar animações acionadas em momentos estratégicos durante a experiência de navegação para criar a aparência de transição de conteúdo para dentro da área de exibição quando a página for carregada e para fora da área de exibição quando o usuário clicar em um link.
O primeiro local intuitivo a adicionar uma animação ao elemento body seria o evento onload
JavaScript. Ao que parece, no entanto, a adição de uma animação quando onload
é disparado é tarde demais. Este evento na verdade é acionado quando o conteúdo completo em nossa página terminou de ser carregado (incluindo imagens ou outros recursos que exigem mais da largura de banda). Anexar uma animação a onload
em uma página que exige muito da largura de banda resultaria em uma exibição “normal” de nosso conteúdo, seguido por um acionamento da animação que traria de volta o conteúdo para a área de exibição. E isso não é exatamente o efeito que estávamos buscando.
Como alternativa, poderíamos utilizar o evento DOMContentLoaded
que é acionado quando o navegador conclui a análise da estrutura DOM de nosso conteúdo (mas possivelmente antes de os recursos terem concluído o carregamento). A demonstração DOMContentLoaded
do ''test drive'' do IE ilustra a diferença entre esses dois eventos. No entanto, no caso de um conteúdo Web mais complexo, um navegador moderno pode escolher executar a renderização “progressiva”, exibindo a página antes de a árvore DOM ter sido completamente carregada. Nessas situações, o resultado visual seria semelhante ao cenário onload
.
O local ideal para se definir uma animação que transforma o conteúdo em exibição na nossa página está embutido no topo do elemento <body>
. Isso garante que a animação seja iniciada corretamente quando o conteúdo for renderizado (e que a posição inicial do conteúdo seja a do quadro chave from
de nossa animação selecionada). Um efeito colateral positivo dessa abordagem é que a animação pode mascarar qualquer renderização progressiva, re-layout ou carregamento de recurso que possam ocorrer em um conteúdo complexo.
A configuração de animações que fazem a transição de nosso conteúdo para fora da exibição também é interessante. É possível presumir que poderíamos anexar um manipulador onclick
em todos os elementos de interesse em nosso conteúdo (por exemplo, todas as marcas <a>
) e simplesmente define as propriedades de animação relevantes (animation-name
, animation-duration
etc.) na função de retorno. No entanto, se não atrasarmos a navegação, não veremos a transição fluida esperada.
Esta é uma boa oportunidade para utilizarmos os eventos de animação descritos na especificação do CSS Animations. Especificamente, podemos utilizar o evento animationend
para detectar quando a animação foi concluída e então acionar uma navegação (definindo window.location.href
, por exemplo). E assim, onclick
acionará a animação “remove-from-view” e registrará um manipulador para animationend
em <body>
que garantirá que o evento de navegação ocorra.
Demonstração online disponível
Criamos uma demonstração e um tutorial em inglês sobre como acrescentar dinamismo às páginas com CSS Transforms e Animations. A demonstração oferece mais informações e exemplos do que esses que conseguimos mostrar aqui. O próprio tutorial utiliza animações em página inteira que funcionam no Internet Explorer 10 no Windows 8, assim como nas versões recentes do Chrome e do Firefox.
Para aproveitar as animações de cada página, navegue pelas páginas do tutorial utilizando os links “Continue to ...” (Continuar para...) no canto inferior direito de cada página.
Ao fim do tutorial, fornecemos algumas orientações adicionais e um código de exemplo sobre como incorporar essas animações ao seu próprio conteúdo Web.
Conclusão
CSS Transforms e CSS Animations são dois conjuntos de recursos avançados que possibilitam experiências mais imersivas na Web. Esta postagem do blog descreveu algumas considerações sobre o uso de CSS Transforms e CSS Animations para que você possa acrescentar mais dinamismo em todo o seu conteúdo Web. Sem muito esforço, é possível criar páginas da Web (até mesmo páginas estáticas) que ofereçam uma experiência de navegação mais fluida e semelhante a dos aplicativos.
—Charilaos “Harris” Papadopoulos, estagiário de gerenciamento de programas, gráficos do Internet Explorer