Pião da Casa Própria em CSS 3D

Quem não lembra do lendário programa do Silvio Santos Pião da Casa Própria? Neste post vamos trazer esta lenda de volta a vida, desta vez encarnado em puro código HTML5, sem imagens ou plugins. Se seu navegador for o Chrome, Safari ou Firefox atualizados, você poderá ver abaixo como nosso experimento irá ficar ao final deste post.

Todo o código deste experimento está disponível no GitHub e um preview completo pode ser visto aqui.

A brincadeira é muito fácil

Vamos começar com o código HTML. Apenas uma div contendo 6 outras div, uma para cada face do pião, a div wrapper, que servirá de container para o pião, e mais uma última para a moldura do pião.

<div id="wrapper">
  <div id="piao">
    <!-- todas as faces do pião -->
    <div class="numero um">1</div>
    <div class="numero dois">2</div>
    <div class="numero tres">3</div>
    <div class="numero quatro">4</div>
    <div class="numero cinco">5</div>
    <div class="numero seis">6</div>
  </div>
  <div id="moldura"> </div>
</div>

Agora vamos dar um pouco de estilo ao pião e à moldura.

#wrapper {
  width: 400px;
  height: 400px;
  position: absolute;
  left: 50%;
  top: 50%;
  margin-left: -200px;
  margin-top: -200px;
}

#piao {
  position: relative;
  top: 40px; /* centraliza o pião */
  margin: 0 auto; /* centraliza o pião */
  height: 330px;
  width: 200px;
}

#piao .numero {
  position: absolute;
  height: 100%;
  width: 200px;
  border: 6px solid white;
  -webkit-box-sizing: border-box;
  text-align: center;
  line-height: 320px;
  font-family: Impact, sans-serif;
  font-size: 240px;
  color: white;
  background-color: rgb(0, 0, 0);
}

#moldura {
  height: 400px;
  width: 400px;
  border: 50px solid rgb(200, 0, 0);
  border-radius: 250px;
  position: absolute;
  top: -45px;
  left: -50px;
  /*
    1ª shadow: simula 3D no elemento, na parte interna
    2ª shadow: shadow interna para simular profundidade
    3ª shadow: simula 3D no elemento, na parte externa
    4ª shadow: shadow externa para simular profundidade
  */
  box-shadow:
    inset -1px -2px 0px 3px rgb(150, 0, 0),
    inset -1px -2px 10px 10px rgba(0, 0, 0, 0.5),
    -2px -2px 0px 3px rgb(150, 0, 0),
    -4px -4px 10px 10px rgba(0, 0, 0, 0.5);
}

Agora já podemos ver algo sem graça no browser com o código acima: um número 6 dentro de um círculo vermelho com um efeito 3D simulado.

Posição no plano 3D

Vamos agora posicionar o pião no plano 3D. Mas antes uma breve explicação sobre o plano 3D em CSS.

Temos 3 eixos de coordenadas para posicionarmos os elementos relativos a eles. O eixo X é o eixo horizontal (esquerda-direita) e tem sua origem no ponto mais a esquerda. O eixo Y é o eixo vertical (cima-baixo) e, diferente de um plano cartesiano comum, tem seu início na parte mais acima do navegador. Portanto, o ponto do seu navegador mais acima e a esquerda é o ponto de coordenadas X = 0 e Y = 0.

Mas para objetos 3D nós precisamos de mais um eixo, o eixo Z, que vai nos dar a sensação de profundidade. Este eixo se inicia no monitor e cresce no sentido monitor ↝ você. Então, quanto mais “distante” do monitor o objeto aparentar estar, maior o valor de Z.

Agora entendendo um pouco sobre o plano 3D, vamos organizar os elementos a fim de formar o pião.

#piao > .numero.um {
  /*
    a rotação deste elemento é 0, o que já é o valor padrão
    então não há necessidade de redeclarar sua rotação
   */
}

#piao > .numero.dois {
  -webkit-transform: rotateY(60deg);
}

#piao > .numero.tres {
  -webkit-transform: rotateY(120deg);
}

#piao > .numero.quatro {
  -webkit-transform: rotateY(180deg);
}

#piao > .numero.cinco {
  -webkit-transform: rotateY(240deg);
}

#piao > .numero.seis {
  -webkit-transform: rotateY(300deg);
}

No trecho de CSS acima, nós giramos as faces em relação ao eixo Y. Precisamos girar todas as faces a fim de fecharmos uma volta. Como uma volta possui 360 graus e o pião possui 6 faces, então iremos rotacionar cada face em 60 graus mais a rotação da face anterior, ou seja, o primeiro elemento irá ser rotacionado em 60 graus, o segundo em 120 graus, o terceiro em 180 graus, e assim por diante até o último elemento.

Porém se rotacionarmos apenas no eixo Y os elementos, eles ficarão todos um por cima dos outros, apenas inclinados de forma diferente. Estarão todos no centro do que será nosso pião. Precisamos agora afastar as faces umas das outras. E para isso iremos usar a propriedade translateZ.

#piao {
  ...
  -webkit-transform-style: preserve-3d;
}

#piao > .numero.um {
  -webkit-transform: translateZ(170px);
}

#piao > .numero.dois {
  -webkit-transform: rotateY(60deg) translateZ(170px);
}

#piao > .numero.tres {
  -webkit-transform: rotateY(120deg) translateZ(170px);
}

#piao > .numero.quatro {
  -webkit-transform: rotateY(180deg) translateZ(170px);
}

#piao > .numero.cinco {
  -webkit-transform: rotateY(240deg) translateZ(170px);
}

#piao > .numero.seis {
  -webkit-transform: rotateY(300deg) translateZ(170px);
}

Com o transform-style: preserve-3d estamos dizendo que os filhos diretos do elemento pião irão compartilhar o mesmo espaço 3D que o pai. Caso contrário os elementos seriam renderizados de forma plana no elemento pai.

Depois, com a regra translateZ, estamos afastanto todos os elementos do seu ponto inicial no eixo Z. Com o rotateY giramos todas as faces e com o translateZ é como se estivéssemos pedindo para que todas as faces dessem um passo de 170px à frente. Como giramos todas para um lado diferente, elas irão “caminhar” para um sentido diferente.

Com isso temos o nosso pião 3D, mas para deixar tudo mais interessante, vamos usar animation para fazer a rotação do pião.

Animação em ritmo de festa

O efeito que queremos ver é o do pião rodando em relação ao seu eixo Y, o mesmo eixo em que rotacionamos as faces do pião. Para isso iremos criar uma animação com o estado inicial no ponto 0 graus do eixo Y e estado final no 360 graus, ou seja, uma volta completa.

/*
  animação para o pião rodar
  uma animação básica ao redor do eixo Y
*/
@-webkit-keyframes rodando {
  from { -webkit-transform: rotateY(0); }
  to   { -webkit-transform: rotateY(-360deg); }
}

No trecho acima definimos nossa animação e a chamamos de rodando (em homenagem). Agora é só a usarmos no elemento que desejarmos.

#piao {
  ...
  -webkit-animation: rodando 4s infinite linear;
}

Aqui dizemos que queremos animar o elemento pião, utilizando a animação “rodando”, demorando 4 segundos para ir de seu estado inicial ao estado final, essa animação não irá parar (infinite) e a sua transição entre estados será linear.

Agora se checarmos no navegador, iremos finalmente ter nosso pião da casa própria em HTML5. E rodandooo.

One more thing…

O Pião da Casa Própria não seria o mesmo sem a clássica trilha sonnora. Então vamos adicioná-la ao experimento. Iremos usar a nova tag audio para reproduzir a música sem a nececissade do Flash. Basta declarar a tag audio e dentro dela as tags source com os caminhos para o mesmo arquivo salvo em diferentes codecs.

<!-- trilha do pião da casa própria. máá ô-ê -->
<audio preload="auto" loop="true">
  <source src="piao-da-casa-propria-soundtrack.mp3" />
  <source src="piao-da-casa-propria-soundtrack.m4a" />
  <source src="piao-da-casa-propria-soundtrack.ogg" />
</audio>

O navegador irá tentar de cima para baixo executar os formatos, e quando achar um que possa reproduzir, irá carregar e não irá mais procurar por outros source. O uso desta tag é necessário pois cada navegador dá suporte a um diferente conjunto de codecs.

Caso queiram escutar a trilha sonora agora e ver o pião rodando é só apertar o botão play no lado direito superior dentro do experimento, no início do post. Utilizei a API JavaScript para controlar o comportamento da tag audio, mas para não perdemos o foco, essa API fica para um próximo post.

#7