Le site twikito.com est le webfolio de Matthieu Bué, Web et UI designer, développeur front-end et formateur.
Le site twikito.com est compilé avec l'application Prepros. Vous trouverez la config à la racine.
Le site twikito.com utilise Autoprefixer pour rendre la plupart des fonctionnalités compatibles avec les anciennes versions des navigateurs. D'après Can I Use, le site est compatible avec :
- Chrome
- Firefox
- Edge
- Internet Explorer 10+
- Opera
- Safari
Code copyright 2017 Matthieu Bué. Le code est délivré sous licence MIT. Les illustrations sont délivrées sous licence CC BY-NC-ND.
Le site twikito.com est codé à la main dans les règles de l'art, sans CMS et sans plugin jQuery. La plupart des fonctionnalités ont été codées par CSS uniquement.
Le code étant en grande partie expérimentale et démonstrative, pour des questions de maintenabilité, je commente ici les réflexions et choix des techniques employées.
- Une charte de codage
- Le dimensionnement
- Les icônes
- Le burger
- La barre de navigation
- La navigation responsive
- L'animation du logo
- Les zones de travers
- Le texte défilant
- L'apparition des éléments au scroll
- Les panneaux de réalisation
- Les images responsives
- La lightbox
- Le scroll automatique
- La page 404
- Le code Konami
- Pour finir
Pour des questions de maintenabilité, il est important de définir une charte de codage en SCSS. Ainsi fait, il est beaucoup plus simple de retrouver et comprendre ce code, pour soi-même, mais aussi pour toute personne amenée à le lire.
Ma façon de coder, élaborée au fil de mon expérience, se définit ainsi :
css-selector {
properties line 1: position styles;
properties line 2: box styles;
properties line 3: flex and grid styles;
properties line 4: transform styles;
properties line 5: border styles;
properties line 6: background styles;
properties line 7: text styles;
properties line 8: other styles;
properties line 9: animation and transition styles;
}
Ainsi, chaque propriété est rangée sur la même ligne que ses propriétés dépendantes, et chaque règle ne fera au maximum que neuf lignes de code. Au fil du temps, j'ai même fini par ranger les propriétés de chaque ligne dans un certain ordre.
Pour des questions de maintenabilité et d'accessibilité, tout le site, textes et illustrations sont dimensionnés en unités relatives : em
, rem
et %
.
Tout se passe à la base dans le fichier _sass-typo.scss. Comme l'explique raphaël, en paramétrant la taille de police du <html>
à 0.625em
, je simplifie les calculs et obtiens un rapport de 10 partout. Ensuite, je spécifie un ratio en fonction de la taille de l'écran par media queries sur <body>
, et la cascade fait son œuvre.
Ainsi, les adaptations responsives sont plus simples, et tout le site est un rapport de proportionnalité de la taille de police par défaut du navigateur… taille par défaut que vous avez peut-être modifiée vous-même d'ailleurs.
Toutes les illustrations du site sont réalisées par SVG. Pour des questions d'optimisation, les icônes sociales, de navigation et quote sont insérées par sprite SVG externe, afin de profiter du cache navigateur.
L'animation de SVG par transformations reste encore assez complexe via CSS, c'est pourquoi j'ai choisi d'animer des objets HTML.
L'icône « burger » est réalisée avec l'élément .navicon
. Un élément enfant et deux pseudo-éléments adjacents sur lesquels j'applique une transformation pour obtenir la flèche.
La navigation n'étant pas primordiale sur ce site en single page, j'ai fait le choix de la cacher par défaut.
L'apparition/disparition de cette barre se fait par CSS uniquement.
Je me sers d'un checkbox, converti en bouton via role='button'
. L'icône est placée dans un label qui est associé à ce checkbox. Le nav
étant adjacent, je n'ai qu'à appliquer les transformations voulues à l'icône et la navigation au :checked
du checkbox.
Pour une question d'accessibilité, j'ai laissé la navigation accessible au clavier même lorsqu'elle est fermée.
Une subtilité pour améliorer l'expérience utilisateur : sur mobile, j'ajoute un pseudo-élément au label qui recouvre tout le viewport, sous la navigation, ce qui permet ainsi de simplifier la fermeture de cette navigation.
Voir la démo isolée pour plus de détails.
La barre de navigation s'adapte en fonction de la taille de l'écran.
Sur grands écrans, la navigation est pensée pour être secondaire, c'est-à-dire qu'on peut faire le choix de ne pas l'utiliser, cela ne nuira pas à la lecture du site. Il est possible également de laisser cette navigation toujours ouverte, sans être gêné pour la lecture.
Sur écrans intermédiaires, les dimensions de la barre sont diminuées, de même pour tous les contenus du site.
Sur petits écrans, typiquement smartphones, la navigation recouvre une plus grande partie de l'espace disponible, les intitulés étant affichés d'emblée. C'est pour cette raison que la fermeture est facilitée avec la possibilité de cliquer (ou taper) en dehors pour fermer la navigation.
Enfin, sur écrans à hauteur réduite, typiquement smartphones ou tablettes en orientation paysage, j'ai fait le choix de cacher les items jugés secondaires, laissant ainsi les plus importants visibles sans débordement.
J'ai voulu l'animation du logo par CSS pour plus de fluidité, et pour éviter l'ajout d'un plugin JavaScript.
L'animation se fait par CSS uniquement. Cette animation est basée sur la propriété stroke-dasharray
sur chaque <path>
du SVG.
Voir la démo isolée pour plus de détails.
À l'époque où j'avais codé cette partie, le fait d'appliquer une transformation skew
à un conteneur et un skew
inverse à son contenu provoquait du crénelage au texte. J'ai donc dû trouver une autre solution.
Les zones de travers sont simulées avec un <hr>
avant et après chaque zone, sur lesquels j'applique une couleur d'arrière-plan. À l'intérieur de ces <hr>
, j'ajoute les deux pseudo-éléments. Sur l'un j'applique la couleur d'arrière-plan de la zone précédente, sur l'autre celle de la zone suivante.
J'applique enfin une transformation skew
légèrement différente sur chacun d'eux pour obtenir cet effet.
L'animation du texte défilant se fait par CSS uniquement. Un simple élément en inline-block
et overflow: hidden
, et un enfant multiligne animé sur la transformation translateY
.
Pour cette partie, j'ai voulu me séparer d'un plugin JavaScript devenu dépassé, qui n'était pas suffisamment permissif quant aux effets à configurer. Je l'ai donc recodé et optimisé moi-même.
Cette animation se fait par JavaScript (vanilla) et CSS.
Tout d'abord, j'ajoute l'attribut data-se
(configurable) à chaque élément que je veux animer, renseigné avec le nom de la classe CSS qui sera appliquée à cet élément lorsqu'il sera en dehors de l'écran. De cette façon, c'est l'état initial de l'élément qui est affiché à l'écran.
Ensuite je prépare la classe CSS voulue : elle peut être identique ou différente pour chaque élément, et être adaptée en responsive ou non. Classique. Ici, j'applique une opacité et une transformation.
Enfin la partie JavaScript : le principe est de vérifier si chaque élément ayant pour attribut data-se
est affiché à l'écran lors du scroll. Si l'élément est en dehors, j'ajoute la classe renseignée dans l'attribut data-se
de cet élément ; s'il est affiché, je supprime cette classe.
Ici, j'ai également ajouté un offset (configurable), c'est à dire un décalage depuis les bords haut et bas de l'écran après lequel la classe sera suprimée.
Voici l'usage :
<foo data-(sePrefix)="(class added when outside screen)" [ data-(sePrefix)-repeat="('true'|'false'|max count)" data-(sePrefix)-offset="(offset in px)" ]></foo>
Voir la démo isolée pour plus de détails.
Notez que j'utilise cette même méthode pour mettre en pause l'animation du logo lorsqu'il est en dehors de l'écran.
J'ai voulu cet effet par CSS pour plus de fluidité, mais aussi par challenge.
L'ouverture/fermeture de ces panneaux se fait via CSS uniquement.
J'utilise un checkbox, caché par aria-hidden='true'
, avant chaque panneau, puis le titre dans le label associé. Ainsi, je n'ai qu'à appliquer les styles voulus, notamment min-height
, à chaque élément du panneau au :checked
du checkbox.
Afin d'optimiser le chargement des images, j'ai utiliser les attributs sizes
et srcset
des éléments <img>
. Ainsi, le navigateur choisira quelle image est la plus appropriée en fonction de la largeur d'affichage.
Ces sets d'images ont été générées grâce au Responsive Image Breakpoints Generator v2.0 .
La plupart des Lightbox ne sont que peu configurables sur les effets, et lourds en ressources. Il m'est arrivé de coder cet effet par JavaScript, mais j'ai voulu tenter le coup par CSS.
Le zoom des captures par lightbox se fait via CSS uniquement.
Ici, j'ai préparé une imbrication de quatre <span>
qui ont chacune un objectif spécifique : overlay, effet, conteneur et image. Le fait que le conteneur soit en display: none
par défaut fait que l'image d'arrière-plan de son enfant ne se charge pas de suite. Je simule ainsi un lazyload et optimise la performance.
Enfin, lors du focus du lien adjacent, j'applique les styles, ce qui charge l'image.
Il semble y avoir un bug sur iOS pour quitter ce focus. Je n'ai pour le moment pas trouvé de solution.
Voir la démo isolée pour plus de détails.
Le scroll automatique vers les ancres se fait via JavaScript.
Auparavant, j'utilisais mon script basé sur jQuery, mais je me suis résolu à utiliser smooth-scroll de Chris Ferdinandi qui fait ça très bien en vanilla JS.
Une page 404 n'a que peu d'intérêt pour un site en single page. On peut donc se lâcher complètement.
La page 404 a été assez complexe à réaliser.
L'illustration s'adapte à la taille de l'écran. Ainsi, si vous redimensionnez votre navigateur, vous verrez la mouche se faire attraper, et approcher dangereusement d'une mort certaine :D
Pour obtenir cet effet, il faut une imbrication d'éléments, dimensionnés en pourcentage de la taille totale de l'illustration, avec débordements cachés, pour déplacer ces éléments par rapport à une référence : la mouche.
J'ai placé un lien par-dessus, son contenu dissimulé (et pas caché) pour rester lisible pour les lecteurs d'écran. Au survol et focus, j'applique une animation de filtre teinte en répétition infinie aux SVG adjacents directs. Aussi, je lance la lecture du son pour un effet des plus WTF.
Pour ça, je vous laisse voir par vous-même !
↑ ↑ ↓ ↓ ← → ← → B A
Mon seul regret est d'être encore dépendant de jQuery pour l'envoi du formulaire en Ajax… pour le moment.