Un casse-tête en intégration à base de grille

J’aime bien les casse-tête. Et quand je dis j’aime bien, je veux en fait dire que ça a le don de m’énerver et de me rendre complètement fou. Il y a quelques temps j’avais posté un joli casse-tête en intégration. Raphaël Goetter avait aussi publié sur son blog trois défi « T’es pas cap ! » (un, deux, trois). Hier soir, je suis tombé sur un nouveau problème bien casse-tête en intégration. Je l’ai posté sur Twitter afin de m’assurer que je n’étais pas passé à côté d’une solution évidente. En voyant ce matin le titre d’une solution inachevée proposée par Kaelig ou certains tweets nocturnes, j’ai ma confirmation que c’est bien un nouveau joli casse-tête.

Voici le casse-tête en question :

Une grille casse-tête en CSS

  1. Les éléments (ici en orange) ont une largeur fixe de 200px.
  2. La grille est fluide et contient 4 éléments par ligne.
  3. Les « cellules » de la grille (ici en gris) ont une marge de 10px à gauche et à droite, sauf :
    • La première cellule de chaque ligne, qui n’a pas de marge à gauche
    • La dernière cellule de chaque ligne, qui n’a pas de marge à droite
  4. Les éléments sont centrés horizontalement dans leur cellule, sauf :
    • Le premier élément de chaque ligne, qui est aligné à gauche
    • Le dernier élément de chaque ligne, qui est aligné à droite
  5. Les éléments sont répartis équitablement sur chaque ligne. Les rectangles gris sont de la même largeur partout.
  6. Le premier élément et le dernier élément de chaque ligne sont collés respectivement à gauche et à droite de la grille.
  7. Toutes les cellules ont le même parent direct. Le code HTML doit donc ressembler à quelque chose comme : .grille > .cellule > .element. Vous pouvez ajouter des classes spécifiques en plus si besoin.
  8. Pas de JavaScript, que du HTML et CSS.
  9. La solution doit fonctionner à partir d’IE9 (et se dégrader gracieusement pour les plus vieux navigateurs).

Pour vous aider à démarrer, j’ai mis à votre disposition un exemple de code HTML et CSS sur CodePen. Vous êtes libre de modifier le code HTML et CSS, tant que vous respectez les règles ci-dessus.

Je vous invite à partager vos réalisations dans les commentaires. Je publierais la solution que j’ai trouvé dans le courant de la semaine. Amusez-vous bien !

  1. Nico, le

    En gros, la grille fluide du premier et dernier élément doit compenser l’absence de marge. sinon, je vois pas comment on peut avoir les mêmes marges, & les mêmes largeurs.

    Joli casse-tête. Dommage que j’ai pas le temps :-\

  2. Pascal (@eQRoeil), le

    Bonjour,
    tu as déjà vu ma solution sur Twitter, je la poste ici
    fullpage : http://codepen.io/eQRoeil/full/flczb
    editor : http://codepen.io/eQRoeil/pen/flczb

    Une grille en inline-block, les alignements à gauche et à droite avec nth-child()
    Pour conserver une marge quasi identique j’ai utilisé les media-queries en jouant sur la largeur des .
    C’est une ébauche rapide, il faudrait ajouter quelques media-queries pour limiter encore les différences de marge…

    Le js n’est là que pour mesurer largeur des li et marges en temps réel au redimensionnement.

  3. Victor Brito, le

    Est-ce que ma solution se rapproche du résultat que tu souhaites obtenir ? http://codepen.io/victorbritopro/pen/jbvGy

  4. Hugo Giraudel, le

    Fait en turbo : http://codepen.io/HugoGiraudel/pen/tivIj.

  5. Ludo, le

    Ma proposition: http://codepen.io/smith40/pen/yKzBn

    Sympa le casse-tête ceci dit ;)

  6. Kocal, le

    Salut. ^^
    J’ai trouvé deux solutions à ton problème.

    La première solution consiste à utiliser la fonction calc() pour attribuer une valeur dynamique à la largeur des .grid li.
    Elle fonctionne parfaitement sur les navigateurs (PC) supportant la fonction calc() => http://codepen.io/anon/pen/BtCxI

    Bien sûr, IE9 ne supporte pas cette fonction, j’ai donc un peu triché, et j’ai attribué la valeur « 23% » (au pifomètre), aux .grid li. Cette méthode est un peu barbare, car il y a une marge sur la droite qu’il est impossible d’enlever. => http://codepen.io/anon/pen/gysqz

  7. Thomas Moreira, le

    Voici ma version : http://codepen.io/anon/pen/bhjoI

  8. theo, le

    Salut, voici ma contribution :)
    http://codepen.io/anon/pen/iHsxJ

  9. Nicolas, le

    C’est impossible sans faire usage de calc() ? en jouant avec border-box ? (j’ai pas réussi)

    :(

  10. Jean-marc, le

    Et hop un peu plus de boulot de vérif pour le monsieur :P

    http://codepen.io/marlb/pen/LzxuK

  11. Thomas LEBEAU, le

    ma contrib => http://codepen.io/thomaslebeau/pen/IcuiJ

  12. Jean-Baptiste, le

    Voici la version:
    http://codepen.io/jean-baptiste/pen/pnkvA

  13. pauland, le

    http://codepen.io/anon/pen/rxdEg

  14. shavounet, le

    (zut le temps que j’essaye ya plein de posts)
    Néanmoins je suis fier de mon résultat (non testé, et j’ai aucune idée de la compat IE8-), n’étant pas frontend pour deux sous :-)

    http://codepen.io/anon/pen/yzrKh

  15. punkadelic, le

    Pas trop de temps, donc j’ai fait l’impasse sur la dégradation gracieuse (un petit coup de selectivizr et l’affaire est dans le sac (mais c’est du JS)) et sur les cas où width<860px.

    http://codepen.io/punkadelic/pen/ACvhd :)

  16. GammaNu, le

    J’ai bien joué avec calc et ça marche nickel !
    http://codepen.io/GammaNu/pen/Bjzme

  17. mh_nichts, le

    j’aime les casse-têtes!
    voici mon idée :
    http://codepen.io/mh-nichts/pen/vLJzp
    j’ai pas encore regardé le code des autres contributions, mais je vois que je ne suis pas la seule à avoir pensé à calc()…
    (il y a probablement moyen de dégrader plus gracieusement en faisant l’impasse sur la partie « les rectangles gris sont de la même largeur » ou « le premier et le dernier de chaque ligne sont collés à gauche/droite », mais pour ça j’utiliserais modernizr)

  18. GammaNu, le

    http://codepen.io/GammaNu/pen/Bjzme
    Je viens de commenter mon css pour expliqué en bon français chaque ligne un peu compliquée.

  19. Shinze, le

    Voilà une solution, rien d’original et ça fonctionne sur IE9 et se dégrade simplement sur les version antérieures.
    http://codepen.io/gaetanark/full/CneoJ

    Je crée simplement un padding régulier dans chaque unité de la grille.
    Le calcul du padding se fait de la manière suivante avec la propriété «calc» : (100% – 860px) / 6. (La totalité – la dimension totale des largeurs de boite +total des margins) / le nombre de paddings à distribuer.

  20. Simosky, le

    J’arrive à ça : http://codepen.io/Simosky/pen/xfAcs
    Sinon, les solutions de Hugo, de Thomas, ainsi que celle de punkadelic semblent très efficace.

  21. GammaNu, le

    Version sans commentaire : 40 lignes de css, 0 js, html minimaliste, sans id ni classe.
    Resultat responsive qui passe correctement de 4 à 3 puis 2 puis 1 colonnes selon la taille d’écran :
    http://codepen.io/GammaNu/pen/ydsIE
    Et la version avec préprocesseur, qui propose via 3 variables ces réglages :
    $TailleBloc: 200px;
    $TailleMarge: 20px;
    $NombreCollonnesMax: 4;

    http://codepen.io/GammaNu/pen/hipqa

    Amusez-vous avec !

  22. Florent Requin, le

    Une première solution imparfait sans calc : les premières et 4ème li de chaque ligne sont 10px plus grands que les autres => http://codepen.io/frequin/pen/xLekG

    Sinon deux solutions qui fonctionnent bien :
    avec les li en inline-block : http://codepen.io/frequin/pen/glqzc
    ou en float : http://codepen.io/frequin/pen/mxvJi

    le float permet de se passer des problèmes d’espaces supplémentaires entres les inline-blocks mais peut ajouter des problèmes au conteneur parent. Éventuellement ajouter un petit clearfix qui va bien :)

  23. Rey, le

    Pas le temps de tester sous IE9 (à priori ça passe). A mon avis, pas grand chose à faire pour rendre la chose gracieuse sous IE<9…
    http://codepen.io/CedRey/pen/vjFrk
    A base d'inline-block et nth(); ce qui me semble à priori la solution la plus simple, la plus facile et la plus légère.
    Ne pas oublier de passer le font à 0 pour la grille et la remettre à 1rem pour les LI.

  24. Erwan Hesry, le

    J’ai une solution, mais dans les petites dimensions de fenêtre (< 200px), c'est pas tip top :
    http://codepen.io/ErwanHesry/pen/nmLev
    J'ai utilisé la propriété calc pour calculer la largeur des li, puis spécifié un peu pour le nth-child 1, 4, 5 et 8. Margin 0 auto pour centrer les éléments dans le li et spécification aussi pour nth-child 1, 4, 5 et 8.

  25. Guénaël Labois, le

    Ma solution, avec compass + susy. J’ai du louper un truc, car ca m’a pris 10 minutes.

    http://www.h4o-studio/uploads/puzzle/puzzle.zip

  26. Simosky, le

    Et si on faisait simplement déborder l’excédent et qu’on le masquait avec un « overflow: hidden » sur le parent?
    http://codepen.io/Simosky/pen/mgfrx

  27. gregoire dierendonck, le

    Je ne sais pas si j’ai raté quelque chose, mais voilà ma solution…
    http://codepen.io/gregoiredierendonck/full/DxLtv

  28. Rémi, le

    Vous ne l’attendiez plus ? Voici mon compte-rendu de ce casse-tête. La difficulté de ce casse-tête ne réside pas dans le fait d’aligner à gauche ou à droite les premiers et derniers éléments de chaque ligne. Mais plutôt dans le fait de répartir équitablement les éléments sur une ligne, en ayant la même largeur de zone grise partout (règle N°5).

    Pour arriver à ce résultat, ça signifie que la première et la dernière cellule de chaque ligne ont une largeur différente de la deuxième et troisième cellule. Pour arriver à ça, je n’ai pas trouvé d’autres solutions que d’utiliser la propriété CSS calc(), qui permet de faire des calculs en CSS. C’est supporté à partir d’IE9, ce qui répond bien à la règle N°9 (comme par hasard). Une fois qu’on est sur cette piste, il faut juste se creuser les méninges quelques minutes pour arriver à faire le bon calcul.

    Hugo Giraudel a écrit un bon article (en anglais) détaillant tous ces calculs. J’ai posté ma solution initiale sur CodePen.

    Bravo à Hugo, Thomas M, Punkadelic, shavounet, GammaNu, mh-nichts, Shinze, Simosky qui sont parvenus à un résultat équivalent basé sur calc.

    Mention « vous êtiez bien partis sur calc mais vous vous êtes plantés vos calculs » à Theo, Kocal, Jean-Baptiste, Rey, Erwan Hesry.

    Et merci d’avoir participé à eQRoeil (avec une solution basée sur un background-clip:content-box), Victor, Ludo, Kocal, Jean-Marc, Thomas L, Pauland, Florent R, Gregoire. On était bien parti, mais la règle N°5 n’était pas respectée.

    Merci à tous d’avoir participé !