Sistemas de Ícones SVG Editáveis

Exemplo Base

Existem muitas maneiras de se criar um sistema de ícone SVG, mas há um método que tira vantagem da capacidade do Vue de criar ícones inline editáveis como componente. Algumas das vantagens desta forma de trabalhar são:

Primeiramente, criaremos um arquivo para cada ícone, os nomeando de forma padronizada para fácil recuperação:

components/icons/IconBox.vue
components/icons/IconCalendar.vue
components/icons/IconEnvelope.vue

Eis um exemplo de repositório, em que é possível ver esse padrão em uso:
https://github.com/sdras/vue-sample-svg-icons/

Documentação do repositório

Criaremos um componente de ícone base (IconBase.vue), que usará um slot.

<template>
<svg xmlns="http://www.w3.org/2000/svg"
:width="width"
:height="height"
viewBox="0 0 18 18"
:aria-labelledby="iconName"
role="presentation"
>
<title
:id="iconName"
lang="en"
>{{ iconName }} icon</title>
<g :fill="iconColor">
<slot />
</g>
</svg>
</template>

Você pode usar essa base de ícones do jeito que está – a única coisa que você pode precisar atualizar é a viewBox, dependendo da viewBox dos ícones que for utilizar. Na base, vamos usar propriedades para width, height, iconColor e iconName, para que possam ser atualizados dinamicamente. O nome será usado tanto para o conteúdo do <title> e seu id quanto para a acessibilidade.

Nosso script vai ter a aparência a seguir. Definimos alguns valores padrão para que o ícone seja renderizado consistentemente mesmo se as propriedades não forem preechidas:

export default {
props: {
iconName: {
type: String,
default: 'box'
},
width: {
type: [Number, String],
default: 18
},
height: {
type: [Number, String],
default: 18
},
iconColor: {
type: String,
default: 'currentColor'
}
}
}

A propriedade currentColor, usada como padrão para o preenchimento, irá permitir ao ícone herdar a cor do texto que o rodeia. Podemos, inclusive, passar uma cor diferente através desta prop, caso desejemos.

Podemos usá-lo diretamente, bastando que o conteúdo do componente IconWrite.vue seja um conjunto de path referente ao desenho desejado:

<icon-base icon-name="write"><icon-write /></icon-base>

Caso você queira fazer vários tamanhos diferentes para o ícone, podemos alcançar facilmente:

<p>
<!-- pode-se passar pequenos `width` e `height` -->
<icon-base
width="12"
height="12"
icon-name="write"
><icon-write /></icon-base>
<!-- ou pode-se usar o padrão, que é 18 -->
<icon-base icon-name="write"><icon-write /></icon-base>
<!-- ou também deixar um pouco maior :) -->
<icon-base
width="30"
height="30"
icon-name="write"
><icon-write /></icon-base>
</p>

Ícones Animáveis

Manter ícones como componentes se mostra muito conveniente quando desejamos animá-los, especialmente em uma interação. Utilizando SVGs inline, temos maior suporte a interações, seja através de script ou de style. Eis um exemplo de um ícone sendo animado durante um evento @click:

<template>
<svg
@click="startScissors"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 100"
width="100"
height="100"
aria-labelledby="scissors"
role="presentation"
>
<title
id="scissors"
lang="en"
>Ícone de tesoura animado</title>
<path
id="bk"
fill="#fff"
d="M0 0h100v100H0z"/>
<g ref="leftscissor">
<path d="M..."/>
...
</g>
<g ref="rightscissor">
<path d="M..."/>
...
</g>
</svg>
</template>
import { TweenMax, Sine } from 'gsap'

export default {
methods: {
startScissors() {
this.scissorAnim(this.$refs.rightscissor, 30)
this.scissorAnim(this.$refs.leftscissor, -30)
},
scissorAnim(el, rot) {
TweenMax.to(el, 0.25, {
rotation: rot,
repeat: 3,
yoyo: true,
svgOrigin: '50 45',
ease: Sine.easeInOut
})
}
}
}

Estamos aplicando refs para os grupos de caminhos que precisamos mover e, como os lados da tesoura precisam mover-se em conjunto, criamos uma função que permite o reuso em ambas as refs. O uso da biblioteca GreenSock ajuda a resolver questões de suporte às animações e problemas de transform-origin entre os navegadores.

Veja em Sistema de Ícones SVG Editáveis: Ícone Animado por Vue (@Vue) em CodePen.



Um resultado belo e fácil de atingir! E fácil de se atualizar sempre que necessário.

Mais exemplos de animações podem ser visto neste repositório.

Notas Adicionais

Sabemos que designers podem mudar de ideia. Ou podem ocorrer mudanças nos requisitos do produto. Manter todo o seu sistema de ícones baseados em componentes garante a possibilidade de atualizá-los todos, e os ter automaticamente aplicados em todo o sistema. Mesmo com o uso de uma ferramenta do tipo icon loader, algumas situações irão requerer que você recrie ou edite todos os SVG, para tornar a mudança global. O presente método pode ainda poupar-lhe tempo e dor.

Quando Evitar o Padrão

Esse tipo de sistema de ícones SVG é muito útil quando se tem um número de ícones usados de diferentes maneiras por todo o site. Entretanto, se houver grande repetição do mesmo ícone em uma página (ex.: uma grande tabela com um ícone delete em cada linha), poderá fazer mais sentido ter todos os ícones compilados em um arquivo de sprites, com a tag <use> para carregá-los.

Padrões Alternativos

Outras ferramentas que podem auxiliar no gerenciamento de ícones:

Estes pacotes agrupam SVGs em tempo de compilação, mas os torna um pouco mais difíceis de se editar durante o tempo de execução, pois a tag <use> pode introduzir problemas de compatibildiade entre navegadores para quaisquer ações mais complexas. Eles ainda deixam você com duas propriedades viewBox aninhadas e, desta forma, dois sistemas de coordenadas. Isto deixa a implementação um pouco mais complexa.