J'ai récemment créé un motif de mur de briques dans le cadre de mon #PetitePatterns series, un défi où je crée des motifs ou des textures d'aspect organique en SVG dans les 560 octets (soit environ la taille de deux tweets). Pour m'adapter à cette contrainte, j'ai suivi un parcours qui m'a appris des manières radicales d'optimiser les modèles SVG afin qu'ils contiennent le moins de code possible sans affecter la qualité globale de l'image.
Je veux vous guider tout au long du processus et vous montrer comment nous pouvons prendre un modèle SVG qui commence à 197 octets jusqu'à 44 octets à peine - une énorme réduction de 77.7 % !
Le motif SVG
C'est ce qu'on appelle un motif de briques «en cours d'exécution». C'est le motif de brique le plus courant, et celui que vous avez sûrement déjà vu : chaque rangée de briques est décalée d'une moitié de la longueur d'une brique, créant un motif en quinconce répétitif. L'arrangement est assez simple, faisant des SVG <pattern>
élément un ajustement parfait pour le reproduire dans le code.
Le SVG <pattern>
utilise un objet graphique prédéfini qui peut être reproduit (ou « en mosaïque ») à intervalles fixes le long des axes horizontal et vertical. Essentiellement, nous définissons un motif de mosaïque rectangulaire et il est répété pour peindre la zone de remplissage.
Tout d'abord, définissons les dimensions d'une brique et l'espace entre chaque brique. Par souci de simplicité, utilisons des nombres nets et ronds : une largeur de 100
et une hauteur de 30
pour la brique, et 10
pour les écarts horizontaux et verticaux entre eux.
Ensuite, nous devons identifier notre tuile "de base". Et par « tuile », je parle de tuiles à motifs plutôt que de tuiles physiques, à ne pas confondre avec les briques. Utilisons la partie en surbrillance de l'image ci-dessus comme motif : deux briques entières dans la première rangée et une entière prise en sandwich entre deux demi-briques dans la deuxième rangée. Remarquez comment et où les espaces sont inclus, car ceux-ci doivent être inclus dans le carreau de motif répété.
Lors de l'utilisation <pattern>
, nous devons définir le motif width
ainsi que height
, qui correspondent à la largeur et à la hauteur de la tuile de base. Pour obtenir les dimensions, nous avons besoin d'un peu de calcul :
Tile Width = 2(Brick Width) + 2(Gap) = 2(100) + 2(10) = 220
Tile Height = 2(Bright Height) + 2(Gap) = 2(30) + 2(10) = 80
D'accord, donc notre motif de carreaux est 220✕80
. Nous devons également définir le patternUnits
attribut, où la valeur userSpaceOnUse
signifie essentiellement pixels. Enfin, en ajoutant un id
au motif est nécessaire pour qu'il puisse être référencé lorsque nous peignons un autre élément avec.
<pattern id="p" width="220" height="80" patternUnits="userSpaceOnUse"> <!-- pattern content here -->
</pattern>
Maintenant que nous avons établi les dimensions de la vignette, le défi consiste à créer le code de la vignette de manière à rendre le graphique avec le plus petit nombre d'octets possible. Voici ce que nous espérons obtenir à la toute fin :
Balisage initial (197 octets)
L'approche la plus simple et la plus déclarative pour recréer ce motif qui me vient à l'esprit est de dessiner cinq rectangles. Par défaut, le fill
d'un élément SVG est noir et le stroke
est transparente. Cela fonctionne bien pour optimiser les modèles SVG, car nous n'avons pas à les déclarer explicitement dans le code.
Chaque ligne du code ci-dessous définit un rectangle. le width
ainsi que height
sont toujours définis, et le x
ainsi que y
les positions ne sont définies que si un rectangle est décalé par rapport au 0
position.
<rect width="100" height="30"/>
<rect x="110" width="100" height="30"/>
<rect y="40" width="45" height="30"/>
<rect x="55" y="40" width="100" height="30"/>
<rect x="165" y="40" width="55" height="30"/>
La rangée supérieure de la tuile contenait deux briques pleine largeur, la deuxième brique est positionnée pour x="110"
permettant 10
pixels d'écart avant la brique. De même il y a 10
pixels d'écart après, car la brique se termine à 210
pixels (110 + 100 = 210
) sur l'axe horizontal même si le <pattern>
la largeur est 220
pixels. Nous avons besoin de ce petit peu d'espace supplémentaire; sinon la deuxième brique fusionnerait avec la première brique de la tuile adjacente.
Les briques de la deuxième rangée (du bas) sont décalées de sorte que la rangée contienne deux demi-briques et une brique entière. Dans ce cas, nous voulons que les briques demi-largeur fusionnent afin qu'il n'y ait pas d'espace au début ou à la fin, leur permettant de s'écouler de manière transparente avec les briques dans les carreaux de motif adjacents. Lors du décalage de ces briques, nous devons également inclure des demi-espaces, ainsi le x
les valeurs sont 55
ainsi que 165
, Respectivement.
Réutilisation d'éléments, (-43B, 154B au total)
Il semble inefficace de définir chaque brique aussi explicitement. N'y a-t-il pas un moyen d'optimiser les modèles SVG en réutilisant les formes à la place ?
Je ne pense pas qu'il soit largement connu que SVG a un <use>
élément. Vous pouvez référencer un autre élément avec lui et rendre cet élément référencé n'importe où <use>
est utilisé. Cela permet d'économiser pas mal d'octets car nous pouvons omettre de spécifier les largeurs et les hauteurs de chaque brique, à l'exception de la première.
Cela dit, <use>
vient avec un petit prix. C'est-à-dire qu'il faut ajouter un id
pour l'élément que nous voulons réutiliser.
<rect id="b" width="100" height="30"/>
<use href="#b" x="110"/>
<use href="#b" x="-55" y="40"/>
<use href="#b" x="55" y="40"/>
<use href="#b" x="165" y="40"/>
Le plus court id
possible est un caractère, j'ai donc choisi "b" pour la brique. le <use>
l'élément peut être positionné de la même manière que <rect>
, Avec le x
ainsi que y
attributs comme décalages. Étant donné que chaque brique est pleine largeur maintenant que nous sommes passés à <use>
(rappelez-vous, nous avons explicitement divisé par deux les briques de la deuxième rangée de la tuile de motif), nous devons utiliser un négatif x
valeur dans la deuxième ligne, puis assurez-vous que la dernière brique déborde de la tuile pour cette connexion transparente entre les briques. Ce n'est pas grave, cependant, car tout ce qui tombe en dehors du carreau de motif est automatiquement coupé.
Pouvez-vous repérer des chaînes répétitives qui peuvent être écrites plus efficacement ? Travaillons sur ceux-ci ensuite.
Réécriture dans le chemin (-54 B, 100 B au total)
<path>
est probablement l'élément le plus puissant de SVG. Vous pouvez dessiner à peu près n'importe quelle forme avec des "commandes" dans sa d
attribut. Il y a 20 commandes disponibles, mais nous n'avons besoin que des plus simples pour les rectangles.
Voici où j'ai atterri avec ça:
<path d="M0 0h100v30h-100z M110 0h100v30h-100 M0 40h45v30h-45z M55 40h100v30h-100z M165 40h55v30h-55z"/>
Je sais, des chiffres et des lettres super bizarres ! Ils ont tous un sens, bien sûr. Voici ce qui se passe dans ce cas précis :
M{x} {y}
: Se déplace vers un point en fonction des coordonnées.z
: Ferme le segment en cours.h{x}
: Dessine une ligne horizontale à partir du point actuel, avec la longueur dex
dans le sens défini par le signe dex
. Minusculex
indique une coordonnée relative.v{y}
: Dessine une ligne verticale à partir du point actuel, avec la longueur dey
dans le sens défini par le signe dey
. Minusculey
indique une coordonnée relative.
Ce balisage est beaucoup plus concis que le précédent (les sauts de ligne et les espaces d'indentation ne servent qu'à la lisibilité). Et, hé, nous avons réussi à réduire la moitié de la taille initiale, en arrivant à 100 octets. Pourtant, quelque chose me donne l'impression que cela pourrait être plus petit…
Révision des tuiles (-38B, 62B au total)
Notre carreau à motif n'a-t-il pas de parties répétitives ? Il est clair que dans la première rangée, une brique entière est répétée, mais qu'en est-il de la deuxième rangée ? C'est un peu plus difficile à voir, mais si nous coupons la brique du milieu en deux, cela devient évident.
Eh bien, la brique du milieu n'est pas exactement coupée en deux. Il y a un léger décalage parce qu'il faut aussi tenir compte de l'écart. Quoi qu'il en soit, nous venons de trouver un modèle de mosaïque de base plus simple, ce qui signifie moins d'octets ! Cela signifie également que nous devons réduire de moitié le width
de notre <pattern>
élément de 220 à 110.
<pattern id="p" width="110" height="80" patternUnits="userSpaceOnUse"> <!-- pattern content here -->
</pattern>
Voyons maintenant comment la tuile simplifiée est dessinée avec <path>
:
<path d="M0 0h100v30h-100z M0 40h45v30h-45z M55 40h55v30h-55z"/>
La taille est réduite à 62 octets, soit déjà moins d'un tiers de la taille d'origine ! Mais pourquoi s'arrêter là quand on peut faire encore plus !
Raccourcir les commandes de chemin (-9B, 53B au total)
Cela vaut la peine d'approfondir un peu <path>
car il fournit plus d'astuces pour optimiser les modèles SVG. Une idée fausse que j'ai eue en travaillant avec <path>
concerne la façon dont le fill
l'attribut fonctionne. Ayant beaucoup joué avec MS Paint dans mon enfance, j'ai appris que toute forme que je veux remplir avec une couleur unie doit être fermée, c'est-à-dire sans points ouverts. Sinon, la peinture fuira de la forme et se répandra sur tout.
En SVG, cependant, ce n'est pas vrai. Permettez-moi de citer la spécification lui-même:
L'opération de remplissage remplit les sous-chemins ouverts en effectuant l'opération de remplissage comme si une commande "closepath" supplémentaire était ajoutée au chemin pour connecter le dernier point du sous-chemin au premier point du sous-chemin.
Cela signifie que nous pouvons omettre les commandes de fermeture de chemin (z
), car les sous-chemins sont considérés comme automatiquement fermés lorsqu'ils sont remplis.
Une autre chose utile à savoir sur les commandes de chemin est qu'elles existent en variantes majuscules et minuscules. Les lettres minuscules signifient que des coordonnées relatives sont utilisées ; les lettres majuscules signifient que des coordonnées absolues sont utilisées à la place.
C'est un peu plus compliqué que ça avec le H
ainsi que V
commandes car elles n'incluent qu'une seule coordonnée. Voici comment je décrirais ces deux commandes :
H{x}
: Dessine une ligne horizontale à partir du point actuel pour coordonnerx
.V{y}
: Dessine une ligne verticale à partir du point actuel pour coordonnery
.
Lorsque nous dessinons la première brique du carreau de motif, nous partons du (0,0)
coordonnées. Nous traçons ensuite une ligne horizontale pour (100,0)
et une ligne verticale pour (100,30)
, et enfin, tracez une ligne horizontale pour (0,30)
. Nous avons utilisé le h-100
commande dans la dernière ligne, mais c'est l'équivalent de H0
, soit deux octets au lieu de cinq. Nous pouvons remplacer deux occurrences similaires et réduire le code de notre <path>
jusqu'à ceci:
<path d="M0 0h100v30H0 M0 40h45v30H0 M55 40h55v30H55"/>
Encore 9 octets rasés - combien plus petit pouvons-nous aller ?
Pontage (-5B, 48B au total)
Les commandes les plus longues qui nous empêchent d'avoir un modèle SVG entièrement optimisé sont les commandes "déplacer vers" qui occupent respectivement 4, 5 et 6 octets. Une contrainte que nous avons est que :
Un segment de données de chemin (s'il y en a un) doit commencer par une commande "moveto".
Mais ça va. Le premier est de toute façon le plus court. Si nous échangeons les lignes, nous pouvons trouver une définition de chemin où nous n'avons qu'à nous déplacer horizontalement ou verticalement entre les briques. Et si nous pouvions utiliser le h
ainsi que v
commandes là au lieu de M
?
Le diagramme ci-dessus montre comment les trois formes peuvent être dessinées avec un seul chemin. Notez que nous tirons parti du fait que le fill
opération ferme automatiquement la partie ouverte entre (110,0)
ainsi que (0,0)
. Avec ce réarrangement, nous avons également déplacé l'espace vers la gauche de la brique pleine largeur de la deuxième rangée. Voici à quoi ressemble le code, toujours divisé en une brique par ligne :
<path d="M0 0v30h50V0 h10v30h50 v10H10v30h100V0"/>
Nous avons sûrement trouvé la plus petite solution absolue maintenant que nous en sommes à 48 octets, n'est-ce pas ? ! Bien…
Ajustement des chiffres (-4B, 44B au total)
Si vous pouvez être un peu flexible avec les dimensions, il existe un autre moyen d'optimiser les modèles SVG. Nous avons travaillé avec une largeur de brique de 100
pixels, mais c'est trois octets. Le changer en 90
signifie un octet de moins chaque fois que nous devons l'écrire. De même, nous avons utilisé un écart de 10
pixels - mais si nous le changeons en 8
à la place, nous économisons un octet sur chacune de ces occurrences.
<path d="M0 0v30h45V0 h8v30h45 v8H8v30h90V0"/>
Bien sûr, cela signifie également que nous devons ajuster les dimensions du motif en conséquence. Voici le code de modèle SVG optimisé final :
<pattern id="p" width="98" height="76" patternUnits="userSpaceOnUse"> <path d="M0 0v30h45V0h8v30h45v8H8v30h90V0"/>
</pattern>
La deuxième ligne de l'extrait ci-dessus - sans compter les indentations - est Octets 44. Nous sommes arrivés ici à partir de 197 octets en six itérations. C'est un morceau 77.7 % de réduction de taille!
Je me demande cependant… est-ce vraiment la plus petite taille possible ? Avons-nous examiné toutes les manières possibles d'optimiser les modèles SVG ?
Je vous invite à essayer de minifier davantage ce code, ou même à expérimenter des méthodes alternatives pour optimiser les modèles SVG. J'aimerais voir si nous pouvions trouver le vrai minimum global avec la sagesse de la foule !
En savoir plus sur la création et l'optimisation des modèles SVG
Si vous souhaitez en savoir plus sur la création et l'optimisation de modèles SVG, lisez mon article sur créer des modèles avec des filtres SVG. Ou, si vous voulez consulter une galerie de plus de 60 modèles, vous pouvez voir le Collection CodePen de PetitePatterns. Enfin, vous êtes les bienvenus pour regarder mes tutos sur YouTube pour vous aider à aller encore plus loin dans les modèles SVG.
Optimiser les modèles SVG à leur plus petite taille publié à l'origine le Astuces CSS. Vous devriez recevoir le bulletin.
- "
- 10
- 100
- 77
- 9
- 98
- Qui sommes-nous
- Absolute
- Compte
- Supplémentaire
- Tous
- Permettre
- déjà
- Une autre
- une approche
- Réservé
- article
- attributs
- disponibles
- HACHES
- Bit
- Noir
- challenge
- Change
- fonds à capital fermé
- code
- Commun
- connexion
- contient
- contenu
- coordonner
- pourriez
- La création
- Courant
- données
- profond
- down
- se termine
- établies
- peut
- exemple
- Sauf
- expérience
- finalement
- Prénom
- s'adapter
- flux
- trouvé
- plus
- écart
- obtention
- Global
- ayant
- la taille
- aider
- ici
- Surbrillance
- Comment
- HTTPS
- identifier
- image
- comprendre
- inclus
- IT
- lui-même
- connu
- fuite
- APPRENTISSAGE
- savant
- en tirant parti
- Gamme
- peu
- regardé
- love
- FAIT DU
- Fabrication
- gérés
- math
- l'esprit
- PLUS
- (en fait, presque toutes)
- Bougez
- MS
- nombre
- numéros
- compenser
- Bien
- ouvert
- optimisé
- autrement
- Patron de Couture
- Physique
- Point
- positionnée
- possible
- solide
- assez
- prix
- processus
- fournit
- qualité
- Round
- pour le running
- Saïd
- fluide
- Série
- set
- formes
- similaires
- étapes
- SIX
- Taille
- So
- sur mesure
- quelque chose
- Space
- Spot
- Commencer
- départs
- Appareils
- parlant
- Avec
- top
- communication
- tutoriels
- utilisé
- Plus-value
- Voir
- W3
- Montres
- bienvenu
- Quoi
- dans les
- sans
- Activités principales
- de travail
- vos contrats
- vaut
- Youtube