Go to English Blog

Um pouco sobre SVG

Leia em 5 minutos

O SVG é um formato de imagem cuja especificação é definida pelo W3C. O SVG descreve gráficos vetoriais bidimensionais através de marcação XML. Você pode pensar nele como sendo o equivalente do HTML para imagens.

SVG Logo

Em vez de definir as imagens com colunas e linhas de pixels, o SVG usa primitivas geométricas como pontos, linhas, curvas e polígonos para representar a imagem. É o que chamamos de gráficos vetoriais. A diferença está no modo como essas imagens funcionam quando aumentamos o seu tamanho. Como imagens vetoriais usam expressões matemáticas para redimensionar o gráfico, não temos perda na definição da imagem.

Diferença entre imagens vetoriais e rasterizadas

Focando no SVG, temos outras vantagens:

Mas nem tudo é lindo. Dependendo dos navegadores que você precisa suportar, terá que fazer fallback para imagens rasterizadas, como PNG. O Internet Explorer só começou a suportar SVGs à partir da versão 9 e o Android 2.3, ainda muito utilizado no Brasil, não tem suporte. A performance do SVG também pode ser um problema caso você precise fazer animação de muitas imagens simultaneamente, o que não acontece com imagens rasterizadas.

Criando arquivos SVG

Embora arquivos SVG sejam apenas XML, é muito mais provável que você utilize um editor de imagens vetoriais para criar os seus gráficos. As alternativas mais comuns são o Adobe Illustrator e Inkscape, mas no Mac temos uma outra alternativa muito boa chamada Sketch.

SVG funciona melhor quando não é tão complexo. Isso porque o seu tamanho pode aumentar muito dependendo do que você for fazer; cores sólidas são muito menores que gradientes, por exemplo. Isso não significa que você não possa ter gráficos complexos, mas tenha a questão do tamanho do arquivo em mente se for usar este SVG em um site.

Se você usa Adobe Illustrator, existem algumas coisas que você pode fazer para diminuir esta complexidade na hora de exportar o SVG. Outros aplicativos podem ter funcionalidades semelhantes, mas não sei como funcionam.

A primeira coisa a fazer é expandir os gráficos, modificando os atributos que definem a sua aparência e outras propriedades de elementos que estão dentro dele. Isso também irá ajudar em coisas como opacidade e gradientes, embora nem sempre funcione bem.

Selecione o gráfico, vá ao menu Object > Expand. Se o gráfico tiver atributos de aparência definidos, você precisará selecionar Object > Expand Appearance antes.

Expandindo gráficos no Illustrator

Outra coisa que você pode fazer é juntar as diferentes partes do gráfico. Exiba o painel de opções do Pathfinder em Window > Pathfinder e escolha a opção “Merge”. Às vezes o gráfico é alterado (coisas como opacidade deixam de funcionar) e eu desfaço essa opção.

Fazendo merge das partes do gráfico no Illustrator

Defina sempre o artboard rente ao gráfico. Isso pode ser feito facilmente através da opção Object > Artboards > Fit to Artwork Bounds.

Configurações de exportação do SVG no Illustrator

Finalmente, na hora da exportação também existem algumas coisas a fazer.

Escolha o perfil SVG 1.1, que é o que possui maior compatibilidade entre os navegadores. Os perfis SVG Tiny 1.1 e variações são voltados para dispositivos móveis mas ainda não possui um suporte muito bom.

Se você não precisa manipular o texto dinamicamente, converta todas as fontes para objetos. Isso fará com que o texto mantenha as características que você definiu, sem aumentar o tamanho final do arquivo, já que para todos os efeitos os textos serão apenas objetos.

Os arquivos exportados pelos editores podem ser otimizados. Os arquivos gerados pelo Illustrator, por exemplo, sempre possuem elementos que podem ser removidos, além de atributos redundantes. Você pode usar uma ferramenta como SVGO para automatizar este processo de otimização.

Para instalá-lo, você vai precisar do Node.js.

npm install -g svgo

Agora basta executar o comando svgo para otimizar o SVG.

svgo logo.svg logo.min.svg

Para otimizar um diretório inteiro, use a opção -f.

svgo -f path/to/folder/with/svg/files

Pronto! Agora basta adicionar o SVG ao seu documento HTML.

Adicionando o SVG ao HTML

Existem algumas maneiras diferentes de se adicionar SVG ao HTML. A maneira mais simples é usar a tag <img> para fazer isso.

<img src="logo.svg" alt="Simples Ideias">

A tag <object> também funciona muito bem.

<object type="image/svg+xml" data="logo.svg"></object>

Finalmente, você pode adicionar a própria tag <svg> diretamente ao seu documento. Basta abrir o arquivo e copiar o elemento <svg>.

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="20px" height="20px">
<circle fill="#7AC943" cx="10" cy="10" r="10"/>
<g enable-background="new">
  <path fill="#FFFFFF" d="M11.802,14.283l-0.126-1.099h-0.054c-0.486,0.685-1.423,1.297-2.665,1.297
    c-1.765,0-2.665-1.242-2.665-2.503c0-2.106,1.873-3.259,5.239-3.241v-0.18c0-0.721-0.197-2.017-1.98-2.017
    c-0.81,0-1.657,0.252-2.269,0.648l-0.36-1.045C7.643,5.677,8.687,5.37,9.785,5.37c2.665,0,3.312,1.819,3.312,3.565v3.259
    c0,0.757,0.037,1.495,0.145,2.089H11.802z M11.568,9.836c-1.729-0.036-3.691,0.27-3.691,1.963c0,1.026,0.684,1.512,1.494,1.512
    c1.135,0,1.854-0.72,2.107-1.458c0.053-0.162,0.09-0.342,0.09-0.504V9.836z"/>
</g>
</svg>

Este método possui vantagens e desvantagens. A principal vantagem é que você pode manipular a cor de fundo e bordas dos elementos do SVG com CSS, por exemplo.

circle {
  fill: blue;
}

A desvantagem, em contra-partida, é que você não pode mais contar com o cache do navegador, já que o elemento será adicionado diretamente ao documento.

Você também pode utilizar SVG como imagens de fundo. Para fazer isso, basta referenciar o arquivo como você já faz com PNGs, por exemplo.

.logo {
  background: url(logo.svg) no-repeat;
  height: 356px;
  width: 408px;
}

Uma técnica muito comum é codificar o SVG em Base64, e adicioná-lo diretamente ao arquivo CSS. Você pode fazer isso usando o comando base64, disponível em sistemas *nix (usuários de Windows, não tenho ideia de como isso funciona).

$ base64 sample.svg  | pbcopy

Com esse conteúdo em mãos, podemos agora adicionar isso diretamente ao CSS, usando data URIs.

.logo {
  width: 20px;
  height: 20px;
  background: url(data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjIwcHgiIGhlaWdodD0iMjBweCI+DQo8Y2lyY2xlIGZpbGw9IiM3QUM5NDMiIGN4PSIxMCIgY3k9IjEwIiByPSIxMCIvPg0KPGcgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyI+DQoJPHBhdGggZmlsbD0iI0ZGRkZGRiIgZD0iTTExLjgwMiwxNC4yODNsLTAuMTI2LTEuMDk5aC0wLjA1NGMtMC40ODYsMC42ODUtMS40MjMsMS4yOTctMi42NjUsMS4yOTcNCgkJYy0xLjc2NSwwLTIuNjY1LTEuMjQyLTIuNjY1LTIuNTAzYzAtMi4xMDYsMS44NzMtMy4yNTksNS4yMzktMy4yNDF2LTAuMThjMC0wLjcyMS0wLjE5Ny0yLjAxNy0xLjk4LTIuMDE3DQoJCWMtMC44MSwwLTEuNjU3LDAuMjUyLTIuMjY5LDAuNjQ4bC0wLjM2LTEuMDQ1QzcuNjQzLDUuNjc3LDguNjg3LDUuMzcsOS43ODUsNS4zN2MyLjY2NSwwLDMuMzEyLDEuODE5LDMuMzEyLDMuNTY1djMuMjU5DQoJCWMwLDAuNzU3LDAuMDM3LDEuNDk1LDAuMTQ1LDIuMDg5SDExLjgwMnogTTExLjU2OCw5LjgzNmMtMS43MjktMC4wMzYtMy42OTEsMC4yNy0zLjY5MSwxLjk2M2MwLDEuMDI2LDAuNjg0LDEuNTEyLDEuNDk0LDEuNTEyDQoJCWMxLjEzNSwwLDEuODU0LTAuNzIsMi4xMDctMS40NThjMC4wNTMtMC4xNjIsMC4wOS0wLjM0MiwwLjA5LTAuNTA0VjkuODM2eiIvPg0KPC9nPg0KPC9zdmc+DQo=)
}

Com esta técnica podemos contar com cache do navegador e carregar os gráficos em uma única requisição, mas fique de olho para que o arquivo não fique muito grande.

Compressão

Pelo fato de ser um arquivo baseado em texto, o SVG possui um fator de compressão muito bom. Um arquivo de 10KB, por exemplo, cai para 3.2KB quando servido com gzip.

Se você usar a técnica de Data URIs, um arquivo contendo 13KB cai para 4.9KB quando servido com gzip.

Fallback

A parte ruim é que se você precisa suportar o IE8, precisará fazer fallback para PNGs, por exemplo. Uma maneira simples de fazer isso é usar o evento onerror das imagens, que é lançado quando um SVG tenta ser carregado. Basta adicionar a função abaixo ao <head> e definir o evento nas imagens.

<script>
  function toPNG(image) {
    image.onerror = null;
    image.src = image.src.replace(/\.svg$/, ".png");
  }
</script>

<img src="logo.svg" alt="Logo" onerror="toPNG(this);">

Se você usa o Rails, pode criar um helper para isso, facilitando sua vida.

def svg_image(path, options = {})
  image_tag path, options.merge(onerror: "toPNG(this);")
end

Uma outra técnica que pode ser utilizada é com a tag <object>. Com ela é possível definir um conteúdo que será renderizado caso o navegador não suporte SVG. Um problema desta técnica é que a imagem PNG é sempre carregada, mesmo quando o navegador suporta SVG.

<object data="logo.svg" type="image/svg+xml">
  <img src="logo.png" alt="Logo">
</object>

No caso de imagens de fundo, eu uso o Modernizr. Quando um navegador que não possui suporte a SVG é detectado, uma classe no-svg é adicionada à tag <html>, permitindo exibir o PNG condicionalmente.

.logo { background-image: url(logo.svg); }
.no-svg .logo { background-image: url(logo.png); }

Se você usa Sass, pode usar um mixin para não ter que fazer isso manualmente.

@mixin svg($path) {
  background-image: image-url("#{$path}.svg");
  .no-svg & { background-image: image-url("#{$path}.png"); }
}

.logo {
  @include svg(logo);
}

Isso irá gerar o CSS abaixo:

.logo {
  background-image: url(/assets/logo.svg);
}

.no-svg .logo {
  background-image: url(/assets/logo.png);
}

Se você está usando o Modernizr, pode fazer a detecção do suporte a SVG com o atributo Modernizr.svg, que returna true caso o navegador tenha suporte.

if (Modernizr.svg) {
  // browser supports SVG
}

Finalizando

Uso SVG sempre que posso. Quase sempre são pequenos, não precisam de uma versão maior para telas Hi-DPI e possuem um fator de compressão excelente.

A questão de sprites pode não ser tão simples, mas é possível. Alternativamente você pode usar Data URIs, que também serão servidos com gzip.

Faça um teste. As chances de você querer usar para tudo são grandes!