Introduction
Dans cet article, nous allons détourner CSS de son usage initial, pour des raisons "éducatives". En général, le CSS est utilisé pour créer le style des pages, mais pour changer un peu, nous allons l’employer pour dessiner. Nous allons réaliser du Pixel Art en CSS.
Il y a plusieurs moyens de créer un pixel art en CSS, comme par exemple créer une multitude d’éléments en HTML puis les styliser avec CSS. On pourrait aussi utiliser du Javascript ou encore un SVG.
Personnellement, je vais vous montrer comment détourner la propriété box-shadow
. Cette propriété initialement prévue pour créer des ombres. Cependant ici, on va s'en servir pour créer du pixel art. C’est pour moi la technique la plus intéressante et c’est surtout un très bon moyen d’en apprendre plus sur la propriété.
Comment créer un pixel art en CSS avec box-shadow ?
Avant de créer notre premier pixel art, il est important de comprendre le fonctionnement même de box-shadow
. Et comment il est possible d’en détourner son usage principal.
La propriété box-shadow
La propriété CSS box-shadow ajoute des ombres à la boîte d’un élément via une liste d’ombres séparées par des virgules lorsqu'il y en a plusieurs. C’est une propriété très largement utilisée et que vous avez déjà sûrement employée.
Une ombre peut prendre jusqu’à 5 valeurs :
- un décalage horizontal,
- un décalage vertical,
- un rayon de flou,
- un rayon d’étalement
- et, pour finir, une couleur.
Les décalages peuvent recevoir une valeur négative ou positive, ce qui permet de placer précisément l’ombre. C’est grâce à ça que nous allons pouvoir créer nos pixels.
Créer un pixel avec une ombre CSS
On va commencer par quelque chose de simple pour mieux comprendre où se situe l’astuce. Nous allons créer notre premier pixel.
Je commence donc par créer un élément en HTML et je le stylise en CSS.
.pixel {
width: 40px;
height: 40px;
background-color: #333;
}
Jusqu’ici rien de compliqué. De plus j’ai théoriquement mon premier pixel.
Et maintenant je vais lui ajouter une ombre avec box-shadow.
.pixel {
width: 40px;
height: 40px;
background-color: #333;
box-shadow: 4px 4px 6px #777;
}
J’ai maintenant un pixel avec une ombre. On peut modifier cette ombre pour créer un nouveau pixel. Il suffit de supprimer son blur (rayon de flou) et d’augmenter son décalage. Ce qui donne le code suivant :
.pixel {
width: 40px;
height: 40px;
background-color: #333;
box-shadow: 40px 40px #777;
}
Pour les pixels supplémentaires, il suffit de rajouter une nouvelle ombre à la suite dans la déclaration de la propriété box-shadow.
.pixel {
width: 40px;
height: 40px;
background-color: #333;
box-shadow: 40px 40px #777, 80px 80px #777;
}
J’ai résumé les étapes avec une petite illustration :
Mais comment ça marche ?
Pourquoi l’ombre se décale hors du parent et fait exactement la même taille que l’élément de base ?
Il faut savoir qu’en CSS les ombres héritent des dimensions du parent. C’est donc pour cela que dans notre exemple notre ombre crée un carré qui est identique au parent (sauf pour la couleur).
Pour le décalage, il suffit de lui donner au minimum la taille du parent sur les deux axes pour décaler l’ombre.
Pour finir, en CSS les ombres ne peuvent être visibles que en-dehors d’un élément, c’est pourquoi si on essaye de créer un pixel avec 10px de décalage alors celui-ci apparaîtra coupé.
Pixel art, box-shadow et animation
Le pixel art, c’est beau, mais animé, c’est encore mieux !
Le plus souvent dans les jeux rétro, une animation est composée de plusieurs images généralement appelées « sprites », qui s’affichent à la suite les unes des autres afin de créer une impression de mouvement et donc une animation. Ainsi plus il y a d’images, plus l’animation est fluide.
Cette technique d’animation est utilisée depuis très longtemps et il est très facile de trouver des exemples de sprites sur le net.
Pour animer notre pixel art, nous allons utiliser la même technique. En utilisant une keyframes nous pouvons définir chaque étape de notre animation et le sprite associé afin d’animer le pixel art.
// Une animation de 4 sprites
@keyframes fireball {
0%,
25% {
box-shadow: /* ... */;
}
25.01%,
50% {
box-shadow: /* ... */;
}
50.01%,
75% {
box-shadow: /* ... */;
}
75.01%,
100% {
box-shadow: /* ... */;
}
}
Ainsi en utilisant une keyframe et en définissant chaque sprite dans les étapes d’animation, il est possible de créer un pixel art animé. J’ai réalisé un exemple sur Codepen en 4 sprites :
Point sur les performances
Certains développeurs s’étaient rendu compte qu’une application complexe réalisée en Material design, qui est donc très dépendante de l’utilisation des ombres (et donc de box-shadow) aurait des moins bonnes performances que des designs qui se reposent moins sur l’utilisation d’ombre.
Cette théorie n’a pas été confirmée, cependant Ross Allen de chez AirBnb a prouvé que les ombres en CSS étaient très gourmandes en ressources et pouvaient impacter le scroll.
Et c’est encore pire quand on anime une box-shadow
. L’animation de celle-ci provoque beaucoup de repaint et donc une consommation de données.
Faisons le test avec un pixel art en CSS que j’ai réalisé il y a quelque temps.
Si vous l’ouvrez de votre côté, vous pourrez voir que le pixel art met un certain temps à s’ouvrir. De mon côté, il m’aura fallu environ 3 secondes pour afficher le pixel art. J’ai enregistré (et ressenti) deux chutes brutales de FPS. Et on peut distinguer, en rouge, plusieurs demandes de ressources auprès de la carte graphique.
PS: j’ai effectué le rapport de performances avec la vue « debug » coté Codepen qui affiche uniquement mon code.
On peut donc en conclure que faire du pixel art en CSS n’est pas forcement la meilleure idée pour une application en production…
Usage en production et conclusion
Le pixel art en CSS avec l’utilisation de box-shadow
, est, comme on l’a vu, très gourmand en ressources. Vous vous doutez donc qu’il est plus avantageux de se servir d'une image (jpg, png, webp) ou même un SVG pour afficher un pixel art.
Mais alors quel est l’intérêt ? J’y vois deux raisons : apprendre et s’amuser en créant.
Je pense que juste en expliquant dans cet article et comment j’ai détourné box-shadow
pour créer du pixel art, vous avez dû apprendre plus sur cette propriété ou sur ses performances.
Deuxièmement, c’est un bon moyen de créer et s’exprimer en utilisant uniquement CSS, de faire du pixel art d’une façon un peu originale et d’impressionner vos amis développeurs.
On peut aller plus loin dans la création de pixel art en utilisant par exemple SCSS pour créer plus facilement nos lignes de pixels et ainsi pratiquer SCSS.
Certaines personnes ont même créé des outils pour générer du pixel art en CSS :
- https://www.pixelartcss.com/
- https://kushagra.dev/lab/picssel-art/
- https://codepen.io/jcoulterdesign/pen/oqPNXL
Conclusion
Le but même de cet article était de vous montrer comment on pouvait détourner une propriété CSS pour en faire un autre usage.
Mais aussi de vous montrer, comment utiliser des propriétés CSS d’une autre façon, hors de leur cadre habituel, peut, dans certains cas, aider à mieux comprendre leurs fonctionnement même.
J’ai personnellement appris le CSS en l’utilisant pour dessiner des illustrations en flat design. Je continue encore aujourd’hui à créer des choses délirantes avec du CSS pour en apprendre plus sur certains concepts et vous le partager.
Que pensez-vous de tout ça ?
Commentaires
Merci pour la partie analyse de perf et la conclusion ! Ca rajoute un vrai plus a l'article ! Et gg pour les pixel arts ils sont vraiment cool !
@_laurent : Merci pour ton retour ! ???? Je trouvais intéressant de présenter les points négatifs, cela permet d'en apprendre plus sur le fonctionnement même de la propriété et de nuancer le propos.
bonjour et merci pour l'article mais rien n'y fait j'au texte / code qui s'affiche et pas des carrés pixels ...je suis pur débutant ??
voici ma xième tentative :
<DOCTYPE html>
<head>
</head>
<body>
box-shadow:20px 20px 5px 5px #777;
box-shadow:20px 20px 5px#777;
box-shadow:20px 20px #777;
.pixel {
width: 40px;
height: 40px;
background-color: #333;
box-shadow: 4px 4px 6px #777;
}
</body>
</html>
pouvez vous m'aiguiller svp ? bien cordialement
Andrew