L'affichage en grid de ce site

My profile picture

Comment s'assurer que la taille d'une div soit toujours un multiple de 40 ?

Durant l'intégration de ce site CV/Blog, je voulais que mes blocs restent alignés Pixel Perfect avec mon quadrillage de fond.

Essayez donc de redimensionner cette page, la taille du container va toujours suivre son quadrillage derrière. Ce qui fait que le rendu n'est pas symétrique... Maintenant que vous le savez, ça risque de vous énerver :).

CSS Grid ?

Ma première intuition était d'utiliser les grilles CSS. Pour moi, il suffisait de fractionner ma zone en n colonnes et avoir un gap de 39px entre chacune. Le problème est que : ma zone de contenu n'a pas de taille fixe, le navigateur dicte sa largeur, j'applique juste un padding fixe à droite et à gauche de ma page, je ne limite pas la largeur. Ce qui rend ma zone pas forcément découpable en carré de 40px.

Flex un peu plus prometteur

Pour la page d'accueil, rien de plus simple. C'est moi qui décide de la taille de mes cartes, il me suffit de multiplier par 40 le nombre de colonnes ou de ligne que je souhaite et d'y rajouter 1px pour la bordure. Je laisse le flex-wrap s'occuper du ... wrap s'il n'y a pas la place, et utiliser le gap qui permet de m'assurer que chaque fenêtre soit bien à 39px l'une de l'autre.

---
interface Props {
  title: string;
  row: number;
  col: number;
}

const { title, col, row } = Astro.props;

const width = `${40 * col + 1}px`;
const height = `${40 * row + 1}px`;
---

<div class="window">
  <h1>
    <slot name="icon" />{title}
  </h1>
  <div class="body"><slot /></div>
</div>

<style define:vars={{ width, height }}>
  .window {
    width: var(--width);
    min-width: var(--width);
    max-width: var(--width);
    height: var(--height);
    min-height: var(--height);
    max-height: var(--height);
  }
</style>
Effectivement rien de bien compliqué ici...

Mais pour le blog...

Sur mes pages de Blog, je souhaite que mon container prenne le maximum de place tout en restant un multiple de 40. Je pourrais utiliser du JavaScript en écoutant l'événement resize, venir calculer la bonne largeur de mon container et l'appliquer.

Mais nous on veut une solution sans Javascript. calc permet de rendre une valeur dynamique en CSS. On peut donc effectuer des opérations tel qu'une soustraction à une valeur en px ou vw. Mais comment récupérer le nombre de pixel en trop ? L'opérateur % nous serait bien utile pour soustraire le reste, mais il n'est pas disponible dans la fonction calc.

Fort heureusement pour nous, la fonction round nous permet de pallier ce soucis. Il nous suffit de diviser la taille de notre container par 40, et d'arrondir à l'entier inférieur. Cela nous permet d'avoir la taille maximum de notre container en multipliant par 40.

---
import { Image } from "astro:assets";
import profilePng from "../../public/me.png";

interface Props {
  title: string;
}

const { title } = Astro.props;
---

<div class="window">
  <h1>
    <a href="javascript:history.back()"><slot name="icon" /></a>{title}
  </h1>
  <div class="window-body">
    <Image class="float" src={profilePng} alt="My profile picture" />
    <slot />
  </div>
</div>

<style>
  .window {
    --x: calc(100% / 40);
    --y: calc(100% / 40);
    --round-x: round(down, var(--x), 1px);
    --round-y: round(down, var(--y), 1px);

    width: calc(var(--round-x) * 40);
    height: calc(var(--round-y) * 40);
  }
</style>
Plus simple de lire le code, non ?

La problématique n'est pas vraiment commune, et j'aurais très certainement fini par utiliser du JavaScript pour ça. Mais il est toujours bon si possible de se baser sur une version uniquement CSS.