Comment créer un portfolio Masonry en CSS ?

Comment créer un portfolio Masonry en CSS ?

Pour afficher votre portfolio en ligne, plusieurs solutions s'offrent à vous en fonction d'un choix simple : installer une extension standardisée ou apprendre et avoir un porfolio 100% fait maison. Dans ce tutoriel, je vous montre comment créer un portfolio Masonry en CSS.

Pourquoi s'embêter à créer un portfolio de A à Z alors qu'il en existe des dizaines (centaines ?) prêts à l'emploi et installables en quelques clics ?

C'est vrai que la question mérite d'être posée car j'aurais sans doute pu mettre cette partie en ligne sur mon site en quelques dizaines de minutes et ainsi, profiter de mon week-end pour me reposer. Mais essayons de voir les choses sous un autre angle, justement.

  • Concevoir et créer, c'est apprendre. Créer un portfolio n'est sans doute pas le truc le plus compliqué que j'ai fait jusqu'ici. Certes, cela nécessite d'être attentif à quelques détails pour que l'ensemble soit parfaitement fonctionnel sur tous les navigateurs modernes mais rien de très compliqué, comme vous le verrez plus loin. En installant une extension (ou un plugin), vous gagnerez surement beaucoup de temps mais vous n'apprendrez... rien.
  • Plus c'est léger, mieux c'est !. Cette traduction approximative de la devise de Colin Chapman (le créateur de la marque automobile Lotus) est parfaitement applicable au Web. Une extension installée représente des dizaines de fichiers et de dossiers qui viendront alourdir votre site et qu'il faudra maintenir à jour régulièrement. Le portfolio que je vous propose ici est plus léger qu'une plume : 60 lignes de CSS !
  • Un design parfaitement adapté. Le portfolio que vous allez apprendre à créer est entièrement customizable, selon vos besoins. Si vous avez installé une extension, êtes-vous certain.e que le rendu sera parfaitement adapté à votre site Web ? Si non, pourrez-vous le modifier et l'adapter facilement ?

Créer un portfolio Masonry uniquement en CSS

Il existe plusieurs styles de portfolio et celui que nous allons créer ici est de type Masonry. Dans cette configuration, les images s'empillent les unes sur les autres en essayant de remplir tout l'espace disponible. Si vous connaissez Pinterest, vous voyez l'effet obtenu.

En règle générale, un portfolio dispose d'une option permettant de cliquer les images pour les afficher dans une fenêtre modale. Nous utiliserons cette possibilité dans ce tutoriel.

Certains portfolio disposent également d'un système de filtres (pour trier les images d'une même catégorie, par exemple) mais vu que cette fonctionnalité nécessite le recours à JavaScript, nous ferons l'impasse dans le cas présent.

Si vous ne l'avez pas encore vu, voici à quoi ressemble une grille de type Masonry :

Exemple de grille Masonry
Source : Reddit

De quoi avez-vous besoin pour suivre ce tutoriel et réaliser ce portfolio ?

  • Un éditeur de texte: n'importe quel IDE convient ici pour écrire du code HTML et du CSS. Si vous n'en avez pas encore un d'installé sur votre ordinateur, je vous conseille Notepad++ qui est gratuit et parfaitement suffisant pour suivre ce tutoriel.
  • Material Design Bootstrap: c'est avec ce framework que nous allons créer notre portfolio Masonry. Pourquoi ce framework ? Parce qu'il est gratuit, parce qu'il est très complet et qu'il est facile à prendre en mains, même par les novices. Vous pouvez télécharger la version gratuite ici.

La structure HTML

Pour l'instant, on commence par poser les bases de la structure. Celle-ci se résume à une première div qui contient autant d'autres div qu'il y a d'images à afficher. Ce qui nous donne ceci :

<div class="masonry">
	<div class="item">
		<img src="/url/de/mon/image1.jpg" class="img-fluid" alt="">
	</div>
	<div class="item">
		<img src="/url/de/mon/image2.jpg" class="img-fluid" alt="">
	</div>
	<div class="item">
		<img src="/url/de/mon/image3.jpg" class="img-fluid" alt="">
	</div>
	<div class="item">
		<img src="/url/de/mon/image4.jpg" class="img-fluid" alt="">
	</div>
	<div class="item">
		<img src="/url/de/mon/image5.jpg" class="img-fluid" alt="">
	</div>
	<div class="item">
		<img src="/url/de/mon/image6.jpg" class="img-fluid" alt="">
	</div>		
	<div class="item">
		<img src="/url/de/mon/image7.jpg" class="img-fluid" alt="">
	</div>
	<div class="item">
		<img src="/url/de/mon/image8.jpg" class="img-fluid" alt="">
	</div>
</div>

Il ne vous a pas échappé que la div parente contient déjà une class Masonry et que chaque div enfant a une classe item.

Voilà qui nous fait une excellente transition vers... les CSS !

Les classes CSS

La beauté des CSS est qu'il suffit de quelques instructions pour que tout ceci se transforme en une élégante galerie d'images.

Dans cet exemple, nous allons afficher nos images sur 3 colonnes en prenant bien soin d'avoir un affichage parfaitement respecté sur les différents navigateurs Web. Pour réaliser cela simplement, nous allons utiliser la propriété column-count, ce qui va nous donner ceci :

.masonry {
    -webkit-column-count: 3;
	-moz-column-count: 3;
	column-count: 3;
	-webkit-column-gap: 1em;
	-moz-column-gap: 1em;
	column-gap: 1em;
	margin: 1.5em;
    padding: 0;
    -moz-column-gap: 1.5em;
    -webkit-column-gap: 1.5em;
    column-gap: 1.5em;
    font-size: .85em;
}

Si vous souhaitez plutôt avoir un affichage sur 4 colonnes, vous voyez tout de suite quelles sont les lignes que vous devez modifier. Simple, n'est ce pas !

Ce n'est vraiment pas plus compliqué que ça et ces quelques lignes vont suffire (enfin, presque) à avoir un très joli portfolio Mansory.

Pour la petite histoire, retenez que -webkit concerne les navigateurs dérivés de Chromium (Opera, Chrome, Brave, Safari, etc) et que -moz concerne le navigateur Mozilla Firefox.

Comme nous sommes au 21ème siècle, nous souhaitons également que notre portfolio soit responsive pour s'afficher parfaitement sur tous les écrans. Dans le cas présent, nous allons arbitrairement choisir 4 résolutions d'écran : inférieur à 320 px (affichage sur une colonne), de 321 px à 768 px (affichage sur 2 colonnes), de 769 px à 1200 px (affichage sur 2 colonnes) et à partir de 1201 px (affichage sur 3 colonnes). Naturellement, libre à vous de modifier ces valeurs si vous souhaitez, par exemple, avoir un affichage en 4 colonnes sur les plus grands écrans.

@media only screen and (max-width: 320px) {
    .masonry {
        -moz-column-count: 1;
        -webkit-column-count: 1;
        column-count: 1;
	}
}
@media only screen and (min-width: 321px) and (max-width: 768px){
    .masonry {
        -moz-column-count: 2;
        -webkit-column-count: 2;
        column-count: 2;
	}
}
@media only screen and (min-width: 769px) and (max-width: 1200px){
    .masonry {
        -moz-column-count: 2;
        -webkit-column-count: 2;
        column-count: 2;
	}
}
@media only screen and (min-width: 1201px) {
    .masonry {
        -moz-column-count: 3;
        -webkit-column-count: 3;
        column-count: 3;
	}
}

Avouez que les CSS sont quand même très simples à lire.

Maintenant que la mise en forme de la structure est terminée, il ne nous reste plus qu'à nous occuper des images !

Ici, nos images vont s'afficher les unes en dessous des autres (en colonne, donc) et les CSS se chargeront de les répartir sur le nombre de colonnes que nous avons décidé. Ainsi, vous n'avez absolument pas à vous soucier de l'ordre de vos images ou de la mise en forme globale de votre portfolio.

Pour une meilleur rendu visuel, on veillera également à avoir un espacement identique entre les colonnes et entre les images et à ce que les images occupent tout l'espace disponible.

Ces dernières seront affichées sur un fond blanc pour imiter un cadre. Pour souligner ces cadres, j'ai utilisé la classe CSS z-depth-1 pour leur appliquer une ombre portée.

Traduisons maintenant tout cela en CSS, ce qui nous donne :

.item {
    display: inline-block;
    background: #fff;
    padding: 1em;
    margin: 0 0 1.5em;
    width: 100%;
	-webkit-transition:1s ease all;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
}
.item img{max-width:100%;}

Et voilà, nous venons déjà de terminer la première partie de ce tutoriel. Passons maintenant à la dernière partie concernant l'ouverture des images dans une fenêtre modale.

La fenêtre modale

Pour que les images soient cliquables, nous allons devoir leur appliquer un lien <a>. Tout simplement.

<div class="item z-depth-1">
		<a data-toggle="modal" data-target="#RefImage1">
			<img src="/url/de/mon/image1.jpg" class="img-fluid" alt="">
		</a>
	</div>

A notre lien <a>, j'ai ajouté les attributs data-toggle et data-target de Bootstrap. Ces attributs permettent respectivement d'ouvrir la fenêtre modale et d'indiquer quelle fenêtre Bootstrap doit ouvrir. Si vous connaissez le principe de fonctionnement des ancres, c'est exactement le même qui est mobilisé ici.

Construisons maintenant le contenu de notre fenêtre modale.
Dans mon exemple, j'ai scindé la fenêtre en deux parties égales : une image d'un côté et du texte de l'autre. Libre à vous d'intervertir le texte et l'image, de n'avoir qu'une image, de n'avoir que du texte ou tout ce que vous voulez.

<div class="row">	
	<!-- Partie de gauche -->
	<div class="col-md-6 py-5 pl-5">
		<!-- Présentation du projet -->
		<h5 class="font-weight-normal mb-3">Titre du contenu</h5>						
		<p class="text-muted">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras ornare, tortor in accumsan imperdiet, diam felis pellentesque neque, et feugiat eros augue quis leo. Aliquam eu malesuada dui, eget fermentum erat. Etiam ante est fringilla et.</p>							
		<!-- Liste des caractéristiques -->
		<ul class="list-unstyled font-small mt-5 mb-0">
			<li>
				<p class="text-uppercase mb-2"><strong>Adipiscing elit</strong></p>
				<p class="text-muted mb-4">Etiam ante est fringilla et</p>
			</li>							
			<li>
				<p class="text-uppercase mb-2"><strong>Lorem ipsum dolor</strong></p>
				<p class="text-muted mb-4">Etiam ante est fringilla et</p>
			</li>							
			<li>
				<p class="text-uppercase mb-2"><strong>Pellentesque neque</strong></p>
				<p class="text-muted mb-4">Etiam ante est fringilla et</p>
			</li>							
		</ul>						
	</div>
	<!-- Partie de droite -->	
	<div class="col-md-6">						
		<div class="view rounded-right">
			<img class="img-fluid" src="/url/de/mon/image1.jpg" alt="">
		</div>						
	</div>
</div>

Explications

On utilise ici simplement la grille de Bootstrap pour créer nos deux colonnes avec d'abord row puis ensuite deux fois col-md-6.

Pour la partie de gauche (celle contenant du texte), j'ai appliqué un padding de 5 en haut, à gauche et en bas : py-5 pl-5. Cela fera une marge intérieure qui donnera de l'espace au contenu.

La mise en forme du texte vous appartient, celle-ci n'est qu'un exemple de ce qui est possible de faire avec les classes CSS du framework Material Design Bootstrap.

Pour la partie de droite (celle contenant l'image), j'ai ajouté une classe rounded-right pour arrondir légèrement les coins droits de l'image.

Si nous affichons une fenêtre modale, il faut donner la possibilité à l'utilisateur de pouvoir la refermer simplement. Pour cela, nous allons ajouter un bouton (c'est à dire, une croix affiché avec le symbole &times;) dans le coin supérieur droit de notre fenêtre.

<button type="button" class="close" data-dismiss="modal" aria-label="Close">
					<span aria-hidden="true">&times;</span>
	</button>

Explications

Là encore, on mobilise les attributs Bootstrap pour indiquer comment l'objet doit réagir.

Attention à bien veiller à ce que le symbole de la croix (là où l'utilisateur doit cliquer pour refermer la fenêtre) soit encodé correctement.

Enfin pour positionner le bouton au bon endroit, il faut rajouter une classe CSS close que voici :

button.close {
	position: absolute;
	right: 0;
	z-index: 2;
	padding-right: 1rem;
	padding-top: .6rem;
	}

Il ne nous reste plus qu'à ajouter la structure de notre fenêtre grâce au composant Modal de Bootstrap 4.

En suivant la documentation de Bootstrap 4, la construction de cette étape est un jeu d'enfant. Un copier/coller et quelques légères adaptations nous donner le code suivant :

<div class="modal fade" id="RefImage1" tabindex="-1" role="dialog" aria-labelledby="ExempleLabelFenetreModal" aria-hidden="true">
	<div class="modal-dialog modal-lg modal-dialog-centered" role="document">
		<div class="modal-content">
			<div class="modal-body p-0">
			<!-- Code du contenu de la fenêtre modale à ajouter ici -->
			</div>
		</div>
	</div>
</div>

Explication

Pour que la fenêtre modale interagisse avec le lien correspondant, on renseigne l'id (ici: RefImage1) qui doit correspondre au contenu de l'attribut data-target : #RefImage1

Et voilà, c'est terminé !

Les codes HTML et CSS de ce portfolio Masonry

Le marquage HTML complet

<!-- Code HTML pour la fenêtre modale - à dupliquer pour chaque fenêtre -->
<div class="modal fade" id="RefImage1" tabindex="-1" role="dialog" aria-labelledby="ExempleLabelFenetreModal" aria-hidden="true">
	<div class="modal-dialog modal-lg modal-dialog-centered" role="document">
		<div class="modal-content">
			<div class="modal-body p-0">
				<button type="button" class="close" data-dismiss="modal" aria-label="Close">
					<span aria-hidden="true">&times;</span>
				</button>
				<div class="row">							
					<div class="col-md-6 py-5 pl-5">
						<h5 class="font-weight-normal mb-3">Titre du contenu</h5>						
						<p class="text-muted">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras ornare, tortor in accumsan imperdiet, diam felis pellentesque neque, et feugiat eros augue quis leo. Aliquam eu malesuada dui, eget fermentum erat. Etiam ante est fringilla et.</p>							
						<ul class="list-unstyled font-small mt-5 mb-0">
							<li>
								<p class="text-uppercase mb-2"><strong>Adipiscing elit</strong></p>
								<p class="text-muted mb-4">Etiam ante est fringilla et</p>
							</li>							
							<li>
								<p class="text-uppercase mb-2"><strong>Lorem ipsum dolor</strong></p>
								<p class="text-muted mb-4">Etiam ante est fringilla et</p>
							</li>							
							<li>
								<p class="text-uppercase mb-2"><strong>Pellentesque neque</strong></p>
								<p class="text-muted mb-4">Etiam ante est fringilla et</p>
							</li>							
						</ul>						
					</div>
					<div class="col-md-6">						
						<div class="view rounded-right">
							<img class="img-fluid" src="/url/de/mon/image1.jpg" alt="">
						</div>						
					</div>
				</div>
			</div>
		</div>
	</div>
</div>
<!-- Galerie Masonry -->
<div class="masonry">
	<!-- Code HTML pour une image - à dupliquer pour chaque image -->
    <div class="item z-depth-1">
		<a data-toggle="modal" data-target="#RefImage1">
			<img src="/url/de/mon/image1.jpg" class="img-fluid" alt="">
		</a>
	</div>
</div>

Le code CSS complet

/* Portfolio Masonry */
.masonry {
    -webkit-column-count: 3;
	-moz-column-count:3;
	column-count: 3;
	-webkit-column-gap: 1em;
	-moz-column-gap: 1em;
	column-gap: 1em;
	margin: 1.5em;
    padding: 0;
    -moz-column-gap: 1.5em;
    -webkit-column-gap: 1.5em;
    column-gap: 1.5em;
    font-size: .85em;
}
.item {
    display: inline-block;
    background: #fff;
    padding: 1em;
    margin: 0 0 1.5em;
    width: 100%;
	-webkit-transition:1s ease all;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
}
.item img{max-width:100%;}
button .close {
	position: absolute;
	right: 0;
	z-index: 2;
	padding-right: 1rem;
	padding-top: .6rem;
}
@media only screen and (max-width: 320px) {
    .masonry {
        -moz-column-count: 1;
        -webkit-column-count: 1;
        column-count: 1;
	}
}
@media only screen and (min-width: 321px) and (max-width: 768px){
    .masonry {
        -moz-column-count: 2;
        -webkit-column-count: 2;
        column-count: 2;
	}
}
@media only screen and (min-width: 769px) and (max-width: 1200px){
    .masonry {
        -moz-column-count: 2;
        -webkit-column-count: 2;
        column-count: 2;
	}
}
@media only screen and (min-width: 1201px) {
    .masonry {
        -moz-column-count: 3;
        -webkit-column-count: 3;
        column-count: 3;
	}
}

Enfin pour terminer ce tutoriel, je vous affiche le portfolio que j'ai créé avec ce code pour que vous puissiez le tester en live. J'ai appliqué la propriété Grayscale pour que les images soient affichées en noir en blanc et qu'elles se colorisent au survol de la souris.

Conclusion

Voilà, j'espère que cet exercice vous a plu et que vous aurez l'envie de le mettre en application sur votre site en l'adaptant à vos besoins.

N'hésitez pas à poser vos questions (si vous en avez) dans les commentaires et à partager ce tutoriel auprès de vos réseaux.

Daniel Dubois

Daniel Dubois

Passionné par le Web depuis 2007, Daniel défend la veuve et l'orphelin du web en créant des sites respectueux du W3C. Fort d'une expérience de plusieurs années, il partage ses connaissances dans un état d'esprit open source.
Très impliqué dans la communauté Joomla depuis 2014, il est actif au sein de plusieurs projets, conférencier et fondateur du JUG Breizh.