Postado dia

E ae pessoas! Por acaso vocês conhecem SVG? Basicamente, é uma formato de imagem em vetor. Isso quer dizer que ela é formada por expressões matemáticas que desenham as linhas. Nada de pixels! Quer dizer também que ela é redimensionável e não perde a qualidade.

Mas no caso do SVG, essas expressões são traduzidas para uma linha de sequência de comandos inseridas em uma estrutura XML, indicando como o conteúdo do vetor deve ser desenhado ao ser exibido. O fato de ser XML permite que você possa inserir o conteúdo do SVG direto no HTML. E por causa disso, é possível que o CSS leia o XML. Percebeu aonde quero chegar?

Sim, vamos animar um SVG com CSS! Preparados? Partiu!

1. Inserindo o SVG no HTML

Vou começar já lhe dando duas opções: usar o arquivo base deste tutorial ou fazer do zero. Se escolher usar o arquivo base, clique no botão abaixo para baixá-lo. Você vai precisar abri-lo no Illustrator. De qualquer forma, continue lendo.

Baixar arquivo do tutorial

Primeiramente, precisamos de um SVG. Para isso, você pode criar seu SVG pelo Illustrator. Então abra o Illustrator, crie seu arquivo novo com o tamanho de prancheta que quiser e faça sua arte! Não precisa fazer algo detalhado para seguir este tutorial, pode ser um desenho simples, como um logo! Sem degradês, sem muitos detalhes, somente para seguir este tutorial.

Depois que terminar (ou caso baixou o arquivo base do tutorial e abriu ele no Illustrator), vá em “Salvar como” (ou aperte Shift + Ctrl + S no Windows, ou Shift + Command + S no Mac) e na janela de salvar, escolha o tipo SVG e depois clique em Salvar.

Isso irá abrir uma janela de opções do seu futuro SVG, mas calma lá! Não vamos usar um arquivo SVG, e sim a estrutura do SVG.

Imagem 1 - Pisa no freio Zé! Olha as opções de SVG aí!

Imagem 1 – Pisa no freio Zé! Olha as opções de SVG aí!

Normalmente o perfil SVG fica definido como “SVG 1.1”. Se não estiver, mude-o para 1.1, pois isso interfere na estrutura XML do SVG. Depois clique no botão “Código SVG…”. Isso irá abrir uma janela nova no seu computador com a estrutura completa do seu SVG.

Porém não usaremos tudo. Dos atributos da tag <svg>, precisamos ter o atributo "viewBox" com o seu valor, importante para definir a área da tela do SVG. Se quiser, pode manter os atributos version e xmlns também, mas são só atributos consultivos para o navegador e não influenciam na renderização do SVG, nem no processamento dele. O resto pode ser ignorado.

No atributo viewBox, existem quatro números separados por espaços definem as coordenadas da área da tela dentro do SVG, sendo que os dois primeiros números são as coordenadas X e Y, normalmente definido como “0 0”, que indicam o canto superior esquerdo do SVG. Os outros dois números são as coordenadas X e Y que indicarão o canto inferior direito do SVG.

Quanto ao conteúdo da tag <svg>, precisaremos de tudo, pois isso forma toda a arte do SVG.

Então agora no seu HTML (se não sabe como deixar a estrutura do seu html, copie o código do primeiro passo do tutorial de perspectiva com CSS e Javascript e apague tudo que tem dentro da tag <body> e mude o <title> como quiser), crie uma tag <svg> e defina o atributo "viewBox" com o valor gerado no arquivo de texto do Illustrator.

Olhando o arquivo base do tutorial no Illustrator, perceba que a arte está toda dentro de um grupo. Por este motivo, a estrutura do SVG é formada por três tags <path> dentro de uma tag <g>. Neste caso, selecione toda a tag <g> e cole dentro da sua tag <svg> no seu html.

Porém, ao invés de colar uma vez, cole a tag <g> três vezes. E na primeira tag, define o atributo "id" com o valor “stroke-gray”, a segunda tag com o atributo "id" com o valor “stroke-white”, e a terceira tag define o "id" com o valor “fill-white”.

Na parte de CSS, defina o seguinte:

body{background: #666;}
svg{width: 70vw; min-width: 300px; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); cursor: pointer;}

Só para definir uma aparência para o arquivo e um tamanho bom para o SVG, deixando ele centralizado (no seu arquivo, você pode definir seu CSS como quiser). Adicionei o cursor: pointer; para que o cursor do mouse vire aquele cursor de mãozinha quando passa sobre um link, sabe? Ele deve estar assim agora:

2. Definindo estilos ao SVG

Agora vamos definir a aparência inicial do SVG. Em seu CSS, insira essas linhas:

#stroke-gray *{stroke: #767676; fill: none; stroke-width: 4px;}
#stroke-white *{stroke: #FFF; fill: none; stroke-width: 4px;}
#fill-white *{fill: #FFF; stroke-width: 4px; fill-opacity: 0;}

Agora vamos analisar linha por linha.

#stroke-gray *{stroke: #767676; fill: none; stroke-width: 4px;}

A primeira linha define a aparência de todos os elementos (indicado pelo *) dentro da tag <g id="stroke-gray">. A propriedade "stroke" define a cor dos traços dos <path> com um tom de cinza um pouco mais claro que o tom de cinza da tag <body>. Já a propriedade "fill" define a cor dos preenchimentos como “none”, ou seja, sem preenchimento. Depois a propriedade "stroke-width" define a espessura dos traços para 4px.

#stroke-white *{stroke: #FFF; fill: none; stroke-width: 4px;}

Nesta linha, definimos algo semelhante a primeira linha, mas para os elementos da tag <g id="stroke-white">. Aqui, os traços serão todos branco (stroke: #FFF;), também não terá preenchimentos (fill: none;) e a espessura dos traços também terão a mesma espessura do grupo anterior. Aqui não terá a propriedade "stroke-dashoffset" definida.

#fill-white *{fill: #FFF; stroke-width: 4px; fill-opacity: 0;}

Enfim, na última linha, definimos o preenchimento dos elementos com a cor branca (fill: #FFF;), definimos a espessura do traço para 4px (stroke-width: 4px;) e aqui, definimos a transparência do preenchimento como totalmente transparente usando a propriedade "fill-opacity" com o valor 0. O valor daqui vai entre 0 (equivalente a 0%, transparente) e 1 (equivalente a 100%, opaco). Se fosse 50%, o valor seria equivalente a 0.5.

Esse CSS já estabelece a aparência inicial do SVG, agora precisamos animá-lo. Ainda no CSS, adicione mais essa linha:

svg:hover #fill-white *{fill-opacity: 1;}

Essa linha detecta quando o cursor passa sobre a tag <svg> usando o seletor :hover. Então quando acontecer isso, ele seleciona todos os elementos (indicado pelo *) dentro da tag <g id="fill-white"> e define a transparência do preenchimento para 1, ou seja, sem transparência.

Se você nunca alterou o SVG usando CSS, deve ter estranhado essas propriedades usadas. Qualquer propriedade "stroke", "stroke-", "fill" e "fill-" é usada especialmente para os elementos internos de SVGs.

Isso irá resultar nisso:

Legal, já está animando! Mas está muito simples, não é? Então vamos melhorar.

3. Suavizando animações

A ideia é não animar só o preenchimento, mas também o traçado. Para isso, vamos precisar trabalhar em cima de duas propriedades CSS: "stroke-dashoffset" e "stroke-dasharray".

  • A propriedade "stroke-dashoffset" define em que parte do caminho que forma o elemento o traçado começará a ser desenhado. Basta imaginar uma linha reta de 100px de comprimento. Se definirmos stroke-dashoffset: 25; a linha terá como ponto inicial o ponto equivalente a 25px do comprimento total da linha. É possível também definir % ou outras unidades no seu valor, mas normalmente usa-se sem unidades mesmo pois é difícil saber qual o valor do comprimento total de um caminho de um elemento no SVG. Usar unidades nunca retornarão o valor exato em artes que tem vários detalhes.
  • A propriedade "stroke-dasharray" permite definir quantos espaços vazios haverá dentro do seu traço, podendo definir uma aparência de linha tracejada. Quanto maior for o valor dessa propriedade, maior será a quantidade de espaços, ficando cada vez mais tracejado. Você pode usar unidades, mas o mais comum é usar valor sem unidade, se tornando relativo ao sistema de coordenadas definido pelo atributo “viewBox” na tag <svg>

Usaremos essas duas propriedades com o objetivo de animar o desenho do traçado. Vamos aproveitar melhorar a animação do preenchimento também. Para isso, adicione a propriedade transition: stroke-dashoffset 1s; na linha #stroke-white * e a propriedade transition: fill-opacity 1s; na linha #fill-white *. Ficará assim:

#stroke-gray *{stroke: #767676; fill: none; stroke-width: 4px;}
#stroke-white *{stroke: #FFF; fill: none; stroke-width: 4px; transition: stroke-dashoffset 1s;}
#fill-white *{fill: #FFF; stroke-width: 4px; fill-opacity: 0; transition: fill-opacity 1s;}

A propriedade "transition" permite animar propriedades do CSS com mais suavidade. Ele é uma propriedade que junta as propriedades "transition-property", "transition-duration", "transition-timing-function" e "transition-delay" em uma só, nesta ordem. Eis o que cada uma faz:

  • transition-property: define qual propriedade será animada, sendo obrigatório definir;
  • transition-duration: define o tempo de duração da animação em segundos (ex: 2.75s – 2 segundos e 750 milésimos de segundo), sendo obrigatório definir;
  • transition-timing-function: define como será a curva de velocidade da animação, ou seja, define a aceleração e desaceleração da animação em seu decorrer, podendo definir valores pré-definidos pelo CSS ou um valor personalizado usando a função cubic-bezier(). Se não for definido, o valor padrão será igual a “ease”, acelerando no começo até o meio e a partir deste ponto, desacelerando até o final;
  • transition-delay: define o tempo de duração do atraso da animação em segundos, lembrando que isso afeta a animação somente em seu começo, tanto no sentido normal quando no sentido reverso. Se não definido, o valor será de “0s”, 0 segundos;

No caso usamos somente as duas propriedades, mas dentro da propriedade "transition". A diferença seria assim:

Não resumido Resumido
transition-property: stroke-dashoffset;
transition-duration: 1s;
transition: stroke-dashoffset 1s;

Sendo assim, voltando ao CSS, definimos animações de 1 segundos de duração da propriedade "stroke-dashoffset" para todos os elementos dentro do elemento <g id="stroke-white"> e da propriedade "fill-opacity" para todos os elementos dentro do elemento <g id="fill-white">.

Mas lembre-se que para um "transition" funcionar, o mesmo elemento que tiver essa propriedade aplicada precisa ter a propriedade apontada dentro do "transition" definida nele mesmo. Então se um "transition" indica a propriedade "fill-opacity" para animar, esse elemento precisa ter um “fill-opacity” definido nele para ser considerado um valor inicial da animação.

Agora, adicione mais uma linha no CSS, de preferência junto a outra linha que tem :hover:

svg:hover #stroke-white *{stroke-dashoffset: 0;}

Igual a outra linha que usa o seletor :hover, aqui os elementos dentro da tag <g id="stroke-white"> terão sua propriedade "stroke-dashoffset" alterados para zero. Mas não definimos ainda um valor inicial ainda para ele, então não funcionará ainda. Porém, a animação do <g id="fill-white"> já estará funcionando com suavidade aplicada. Veja abaixo:

4. Animando os traços

Voltando a ideia de animar os traços, lembra o que mencionei sobre os caminhos do SVG na definição de "stroke-dashoffset"? Deixe eu refrescar sua memória:

É possível também definir % ou outras unidades no seu valor, mas normalmente usa-se sem unidades mesmo pois é difícil saber qual o valor do comprimento total de um caminho de um elemento no SVG. Usar unidades nunca retornarão o valor exato em artes que tem vários detalhes.

É o caso. Então teremos que usar uma gambiarra para conseguirmos descobrir o comprimento do caminho de cada elemento do SVG e assim podermos animar os traços. Para isso, vamos usar jQuery para facilitar (mas pode ser com Javascript nativo também). Em seu HTML adicione as seguintes linhas para puxar o jQuery:

<script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script></script>

Dentro da tag <script> vazia, adicione o seguinte código:

	$(document).ready(function(){
		$('svg g>*').each(function(){
		    var len = Math.round($(this).get(0).getTotalLength());
		    $(this).attr('stroke-dasharray',len);
		    $(this).attr('stroke-dashoffset',len);
		});
	});

Agora vamos por partes:

$(document).ready(function(){ ... });

Quando o documento terminar de carregar seus recursos…

$('svg g>*').each(function(){ ... });

…Ele vai procurar por qualquer elemento que tenha um parentesco direto com qualquer tag <g> na hierarquia do documento, que esteja dentro de qualquer tag <svg> (só por precaução), e para cada um, ele roda algumas linhas.

var len = Math.round($(this).get(0).getTotalLength());

Começando com uma variável chamada “len”, que vai mandar ler os nós do DOM através do método get(0) e vai pedir para pegar o valor do comprimento do caminho em pixels computado pelo user agent do seu navegador usando o método getTotalLength(). Esse método é específico de elementos de caminho de SVGs. Depois ele arredonda o valor usando Math.round().

$(this).attr('stroke-dasharray',len);
$(this).attr('stroke-dashoffset',len);

Tendo o valor de comprimento armazenado na variável “len”, as duas linhas seguintes mandam o jQuery definir os atributos "stroke-dasharray" e "stroke-dashoffset" direto no elemento com o valor de comprimento do caminho definido nestes atributos.

Tendo o "stroke-dashoffset", a linha começará a ser desenhada depois do pixel final, o que não faria a linha sumir. Mas junto com o "stroke-dasharray" definido com o valor do comprimento total, o espaçamento entre os tracejados será aplicado antes do ponto inicial e o seguinte será aplicado depois de uma distância igual ao comprimento total. O que será visível é esse espaço antes do ponto inicial, ou seja, não terá linha visível.

Porém se você testar o código, os traços brancos começarão desenhados, mas vão sumir rapidamente por causa da propriedade "transition" aplicada. Veja (clique em Rerun para recarregar):

Como agora temos um valor inicial de "stroke-dashoffset" definido nas tags <path>, o CSS vai ler esses atributos e vai animar o "transition". E isso ocorrerá com os traços cinzas também, ou seja, nada vai ficar visível inicialmente, e não é o que queremos. Vamos arrumar!

5. Arrumando o que faltar arrumar!

Queremos que os traços brancos só sejam visíveis somente quando passarmos o cursor sobre o SVG, mas os traços cinzas precisam estar sempre visíveis. Então primeiramente vamos mexer nos traços cinzas.

No CSS, faça a seguinte alteração:

#stroke-gray *{stroke: #767676; fill: none; stroke-width: 4px; stroke-dashoffset: 0;}

Adicionamos o stroke-dashoffset: 0; para fazer os traços serem desenhados a partir do primeiro pixel do caminho, fazendo os traços cinzas ficarem sempre visíveis.

Agora para parar os traços brancos de animarem assim que abrir o documento, vamos ter que mexer no jQuery. Dentro da função do método ready(), depois de fechar a parte do método each(), adicione as seguintes linhas:

	$(document).ready(function(){
		$('svg g>*').each(function(){
		    var len = Math.round($(this).get(0).getTotalLength());
		    $(this).attr('stroke-dasharray',len);
		    $(this).attr('stroke-dashoffset',len);
		});
		setTimeout(function(){
			$('svg').addClass("hover");
		},500);
	});

Este trecho destacado define uma função a ser executada dentro de 500 milésimos de segundos assim que o ready() for executado usando o método setTimeout. Nesta função, mandamos aplicar a classe “hover” para todos os <svg> do documento. Essa classe vai nos ajudar a controlar a animação dos traços brancos. Como? Com algumas alterações no CSS.

No CSS, você vai mover os "transition" dessas duas linhas:

#stroke-white *{stroke: #FFF; fill: none; stroke-width: 4px; transition: stroke-dashoffset 1s;}
#fill-white *{fill: #FFF; stroke-width: 4px; fill-opacity: 0; transition: fill-opacity 1s;}

Para essas duas novas linhas deste novo trecho:

svg.hover{opacity: 1;}
svg.hover #stroke-white *{transition: stroke-dashoffset 1s;}
svg.hover #fill-white *{transition: fill-opacity 1s;}

Fazendo com que esses dois trechos fiquem assim:

#stroke-gray *{stroke: #767676; fill: none; stroke-width: 4px; stroke-dashoffset: 0;}
#stroke-white *{stroke: #FFF; fill: none; stroke-width: 4px;}
#fill-white *{fill: #FFF; stroke-width: 4px; fill-opacity: 0;}

svg.hover{opacity: 1;}
svg.hover #stroke-white *{transition: stroke-dashoffset 1s;}
svg.hover #fill-white *{transition: fill-opacity 1s;}

Agora, por partes.

svg.hover{opacity: 1;}

Essa linha aplica o valor de transparência totalmente opaco usando a propriedade "opacity" igual a 1 a todos os elementos <svg> que tiverem a classe “hover”. Porém não faz sentido pois em nenhum momento definimos para um SVG inteiro ficar transparente. Não se preocupe, vamos arrumar isso.

svg.hover #stroke-white *{transition: stroke-dashoffset 1s;}

Aqui movemos a propriedade "transition" que mexe na animação dos traços para este elemento para que todos os elementos dentro de <g id="stroke-white"> só animem se o <svg> tiver a classe “hover”, ou seja, aquela animação inicial do traço não acontecerá mais.

svg.hover #fill-white *{transition: fill-opacity 1s;}

Semelhante a linha anterior, o preenchimento branco só será animado se o <svg> tiver a classe “hover”. Não era necessário pois já estava funcionando certo antes, mas pelo menos agora temos um controle maior em quando o preenchimento pode animar ou não.

Para adquirir um controle maior da animação :hover, adicione a classe “hover” nas duas linhas que definem o CSS do estado “hover”, assim:

svg.hover:hover #stroke-white *{stroke-dashoffset: 0;}
svg.hover:hover #fill-white *{fill-opacity: 1;}

E para finalizar, precisamos alterar a linha de CSS das tags <svg>. Deixe assim:

svg{width: 70vw; min-width: 300px; position: absolute; top: calc(50% - 30px); left: 50%; transform: translate(-50%,-50%); opacity: 0; transition: opacity 1s; cursor: pointer;}

Foi adicionado as propriedades "opacity" com o valor igual a 0, para que qualquer <svg> fique inicialmente transparente, e "transition", apontado para o “opacity”, para que a transparência dos <svg> sejam animadas. Com a classe “hover” mandando a transparência ficar em 1 logo de cara, a animação de 0 para 1 ocorrerá assim que o jQuery definir a classe “hover” no <svg>.

6. Final e últimas palavras

Voilá! Está pronto. Veja como ficou:

No exemplo acima adicionei algumas coisas que não acrescentam em nada.

Enfim, este tutorial te ajudará a começar a criar suas próprias animações com SVG, lembrando que existe outras propriedades CSS específicas de elementos de SVG que você pode explorar. Você pode usar as propriedades "animation" para criar animações que não dependem de uma ação do usuário ou de algum código Javascript para acontecer.

Aproveitando, veja o mesmo resultado deste tutorial aplicado no meu logo:

Ver demonstração

Eu organizei o SVG de maneira diferente, logo, o CSS também. Mas a ideia aplicada foi a mesma deste tutorial.

Legal, né? Até a próxima!

Manda sua palavra ae! Deixe um comentário: