Être développeur, c’est savoir correctement utiliser les outils à notre disposition. Être développeur c’est aussi être curieux. C’est pourquoi il n’est pas rare qu’on tombe sur des comportement parfois inattendus. Et c’est ce que j’aime avec le CSS ! En apparence très simple et fait uniquement pour passer un coup de peinture sur notre site, il permet de créer des items interactifs très simplement et sans JS. Aujourd’hui, nous allons donc voir comment créer une datatable uniquement en CSS !

La structure HTML

Ici nous allons partir sur une structure simple. Notre Datatable sera composée d’un header et d’un body. Nous n’allons pas passer par un vrai table HTML pour de nombreuses raisons, la principale étant que les tr/td sont assez peu permissifs en terme de style. Souvent les datatable ont besoin d’être expand afin d’afficher le détail d’une ligne. On ne le fera pas ici mais cette structure permet de le faire si besoin.

Pour la base nous allons partir sur très simple: une div avec dedans deux checkbox dont nous servirons plus tard et son titre. Et pour le côté pimp: un titre pour indiquer ce que notre datatable contient:

<div class="datatable">
    <input type="checkbox" id="reverse">
    <input type="checkbox" id="type">
    <h2>Users</h2>
    <!-- Content will go here -->
</div>

Pour notre ligne de tête, nous allons avoir besoin d’une div en contenant trois autres: une pour un texte et les deux autres qui contiendront le type de tri que nous voulons effectuer: soit inverser l’ordre, soit trier par type. Pour ces actions nous allons mettre un label ce qui nous permettra de toggle les inputs. Et pour lier ces labels aux inputs, n’oublions pas de remplir l’attribut for.

<div class="row head">
	<div>Order:</div>
	<div class="reverse"><label for="reverse">Reversed</label></div>
	<div class="type"><label for="type">By type</label></div>
</div>

Le contenu de notre datatable

Pour la partie content, nous allons créer des row dans un conteneur. Chaque row aura trois colonnes: une pour le nom de l’utilisateur, une pour son statut et une pour une catégorie. Afin de pouvoir changer le style et faire par la suite fonctionner notre système de tri, nous allons ajouter la catégorie en tant que class CSS de notre row:

<div class="content">
	<div class="row science">
		<div>Bruce Banner</div>
		<div>Actif</div>
		<div><p>Scientifique</p></div>
	</div>
	<div class="row spy">
		<div>Natasha Romanoff</div>
		<div>Actif</div>
		<div><p>Espion</p></div>
	</div>
	<div class="row science">
		<div>Stephen Strange</div>
		<div>Actif</div>
		<div><p>Scientifique</p></div>
	</div>
	<div class="row soldier">
		<div>Steven Rogers</div>
		<div>Inactif</div>
		<div><p>Soldat</p></div>
	</div>
	<div class="row science">
		<div>Tony Stark</div>
		<div>Inactif</div>
		<div><p>Scientifique</p></div>
	</div>
</div>

Vous devriez donc obtenir ceci pour le moment:

HTML de notre datatable
Un résultat des plus bouleversants

Un peu de mise en forme

Pour commencer notre CSS, vous avez l’habitude avec moi: préparons notre body ! Nous allons mettre une hauteur à 100vh et le tout en flex afin de centrer notre élément, c’est plus agréable. Et 2-3 bricoles pour le style, mais jusqu’ici rien de particulièrement important:

body {
	font-family: sans-serif;
	margin: 0;
	min-height: 100vh;
	background-color: #EDF0F0;
	color: #313A46;
	display: flex;
	justify-content: center;
	align-content: center;
}

Nous allons également pouvoir cacher nos inputs étant donné qu’ils sont purement utilitaires. Ensuite, nous mettons en forme notre conteneur principal en mettant son fond en blanc, une width par défaut, un peu de padding, un border-radius et en centrant le texte. Enfin on stylise un peu notre h2 pour le rendre plus agréable:

.datatable {
	width: 80%;
	margin: auto;
	text-align: center;
	background-color: #fff;
	padding: 20px;
	border-radius: 5px;
}
.datatable input {
	display: none;
}
.datatable h2 {
	text-align: left;
	margin: 0 0 10px;
	font-size: 20px;
	text-transform: uppercase;
}

Le head de notre datatable

Maintenant un peu de style sur ce head !

Dans un premier temps, mettons du flex sur nos row afin d’obtenir de belles lignes ! Et histoire que ce soit fait, ajoutons une petite bordure sous chaque ligne pour les délimiter. Maintenant que c’est fait, ciblons spécifiquement notre row head, ajoutons du bold, du radius et une bonne grosse bordure noire ! Ensuite on cible toutes les div dans les row et on les met en flex: 1 et un poil de padding pour qu’elles aient toutes la même largeur et que ça respire ! Puis retirons (oui je sais, désolé) le padding des deux dernières cases de notre head (l’explication arrive):

.row {
	display: flex;
	border-bottom: 1px solid #E8E9EC;
}
.row.head {
	font-weight: bold;
	border: 2px solid #666F7B;
	border-radius: 2px;
	margin-bottom: 20px;
}
.row div {
	flex: 1;
	padding: 10px 0;
}
.row.head div:not(:first-child) {
	padding: 0;
}

Un piège qui arrive souvent en CSS, c’est de mettre le padding autour d’un élément cliquable ce qui rend le clic confus ! Ici nous allons mettre le padding directement sur les labels. Cela permettra d’avoir une plus grand zone de clic et donc de le rendre plus accessible ! On ajoute aussi un display: block pour que le padding marche (notre label est en inline par défaut) et un cursor pointer pour que l’utilisateur comprenne bien:

.row label {
	padding: 10px;
	display: block;
	cursor: pointer;
}

Et ça commence déjà à ressembler un poil plus à quelque chose !

Notre datatable prend forme

Enfin mais pas la fin: le contenu

Pour notre contenu, nous allons simplement mettre notre div en display: flex mais avec un flex-direction: column. Ainsi vous obtiendrez visuellement exactement pareil que si vous n’aviez pas mis ces deux lignes. Pourquoi alors ? Parce qu’en appliquant un column-reverse nous allons pouvoir inverser l’ordre de nos lignes, et nous en aurons donc besoin plus tard:

.content {
	display: flex;
	flex-direction: column;
}

Pour le reste, c’est simple: nous allons retirer les marges de nos p, ajouter un petit peu de padding à la place et un peu de border-radius. Nous allons également mettre une petite couleur par défaut et le texte en blanc. Et pour finir nous allons mettre un margin: auto afin de centrer notre p. « Oui mais il prend toute la place » vous allez me dire. C’est vrai, pour ça deux solutions: soit mettre un width: fit-content pour forcer sa width à matcher le texte à l’intérieur, soit le mettre en inline-block.

Et nous allons également sélectionner nos class spy et soldier et changer le background de leur p afin d’avoir des couleurs différentes par catégories:

.row p {
	margin: 0;
	font-size: 12px;
	padding: 4px 8px;
	border-radius: 2px;
	display: inline-block;
	background-color: #EDC755;
	margin: auto;
	color: #fff;
}
.row.spy p {
	background-color: #32B0E0;
}
.row.soldier p {
	background-color: #F24F7C;
}

Et WOW !!! Nous avons désormais une superbe datatable bien intégrée ! On passe à la partie marrante ?

Faisons fonctionner tout ça

Je vous ai déjà parlé de ça: « ~ » ? (c’est réthorique, oui !)
Je crois que c’est de loin le meilleur et le plus puissant des sélecteurs CSS ! Et nous allons en avoir besoin ici puisqu’il permet de sélectionner un élément situé après un autre élément. Et ici nous voulons sélectionner un élément situé après nos inputs. Comme ça, quand l’input est sélectionné, on active quelque chose. Par exemple, si l’input reverse est sélectionné, on passe notre content en column-reverse:

#reverse:checked ~ .content {
	flex-direction: column-reverse;
}

Ici on récupére l’élément « frère » de notre input #reverse UNIQUEMENT s’il est checked ! Et même s’il est caché, comme nous avons un label qui pointe vers lui nous pouvons l’activer et désactiver à notre guise.

Maintenant plus dur ! On veut pouvoir changer le background de notre label quand on clique dessus ! Facile, avec notre input ! Hmmm… Mais il n’est pas un élément frère alors comment faire ? Tout simple: on passe par son parent ! Ici on va récupérer le head qui est frère avec notre input puis sélectionner le label à l’intérieur. Si, si, ça marche.

#reverse:checked ~ .head .reverse, #type:checked ~ .head .type {
	background-color: #8E8AC1;
	color: #fff;
}

Ici, on cible la class .reverse qui est dans une class .head qui est située après un id #reverse qui est checked. Et ce comportement rend le ~ si puissant: si nous mettons nos inputs directement dans notre body, nous pouvons agir sur n’importe quel élément de notre page. C’est tellement puissant qu’on pourrait presque imaginer pouvoir créer des RPG uniquement en CSS !!

Mais trêve de bavardages ! Il nous reste encore notre tri par type. Et idem, rien de plus simple: le flex a une propriété toute faite pour ça: le order. Par défaut le order de n’importe quel élément est de 0. Si nous mettons des éléments à 1, ils seront situés après les éléments 0. Si on met des élément à 9999 ils seront après les 1 et les 0. Vous avez l’idée. On peut donc avoir autant d’élément avec le même order, ils seront entre eux rangés selon leur ordre HTML. Ici nous allons donc mettre nos .spy à 1 et nos .soldier à 2 comme ça nos catégories se trieront d’elles même:

#type:checked ~ .content .spy {
	order: 1;
}
#type:checked ~ .content .soldier {
	order: 2;
}

Ici on utilise la même logique que pour les labels: on cible un .spy qui est dans un .content qui est au même niveau qu’un #type en checked.

Et voilà, notre datatable est entièrement fonctionnel, et le tout sans JS. Et vous pouvez même cumuler le tri par type et le reverse afin d’avoir les catégories dans le sens inverse ! Sur ce je vous laisse, et on se retrouve bientôt pour parler un peu 3D et animation. Je ne vous en dis pas plus 🤫