P
imvdmolen.nl
Blog

Hoe ik CSS Grid subgrid ontdekte voor complexe layoutstructuren in Tailwind

Tijdens het bouwen van een dashboard voor een klant kwam ik tegen een frustrerende situatie. Ik wilde kaarten met verschillende content lengtes netjes uitlijnen in een grid, maar de interne elementen van elke kaart wilden maar niet mooi op één lijn komen. Flexbox hielp niet, en gewone CSS Grid maakte het alleen maar ingewikkelder omdat elke kaart zijn eigen grid-context creëerde. Totdat ik CSS Grid subgrid tegenkwam, een eigenschap die het probleem van geneste grids elegant oplost.

Subgrid werkt fundamenteel anders dan wat je misschien verwacht van CSS Grid. In plaats van een volledig nieuwe grid-context te creëren, erft een subgrid de kolom- of rijstructuur van zijn parent grid. Dit betekent dat je eindelijk content in geneste containers kunt uitlijnen met de hoofdstructuur van je layout. De browser ondersteuning is inmiddels solide: Firefox ondersteunt het al jaren, Safari en Chrome hebben het toegevoegd, en zelfs oudere browsers kunnen ermee overweg door graceful degradation.

Parent grid opzetten met Tailwind utilities

Tailwind CSS heeft nog geen ingebouwde utilities voor subgrid, dus ik werk met custom CSS classes die ik in mijn stylesheet definieer. Voor de parent container zet ik een standaard grid op met een flexibel aantal kolommen. In mijn dashboard gebruik ik vaak een responsive grid die op desktop drie kolommen toont en op mobiel één kolom.

.dashboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 1.5rem;
}

.card-subgrid {
  display: subgrid;
  grid-template-rows: subgrid;
  gap: inherit;
}

De HTML structuur blijft relatief simpel. Elke kaart krijgt de card-subgrid class, waardoor deze automatisch de rijstructuur van de parent overneemt. Dit zorgt ervoor dat de headers, content en footers van alle kaarten netjes op dezelfde hoogte komen te staan, ongeacht de lengte van de individuele content.

<div class="dashboard-grid p-6">
  <div class="card-subgrid bg-white rounded-lg shadow-md p-4">
    <h3 class="text-lg font-bold mb-2">Verkoopcijfers</h3>
    <div class="text-3xl font-bold text-green-600 mb-4">€24.531</div>
    <p class="text-sm text-gray-600">Toename van 12% ten opzichte van vorige maand</p>
  </div>
  
  <div class="card-subgrid bg-white rounded-lg shadow-md p-4">
    <h3 class="text-lg font-bold mb-2">Nieuwe klanten</h3>
    <div class="text-3xl font-bold text-blue-600 mb-4">47</div>
    <p class="text-sm text-gray-600">Nieuw record dit kwartaal</p>
  </div>
</div>

Complexe kaartstructuren synchroon houden

Waar subgrid echt tot zijn recht komt is bij kaarten met meerdere contentblokken die over verschillende kaarten heen moeten uitlijnen. Stel je voor dat elke kaart een header, hoofdcontent, statistieken en een footer heeft. Zonder subgrid zou je nooit alle elementen netjes uitgelijnd krijgen.

De trick is om de parent grid meerdere rijen te laten definiëren, en vervolgens elke kaart deze rijstructuur te laten overnemen. Ik definieer meestal vier vaste rijen: header, content, stats en footer. Door grid-template-rows expliciet te definiëren in de parent en subgrid in de children, blijven alle elementen perfect uitgelijnd.

.complex-dashboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
  grid-template-rows: min-content 1fr min-content min-content;
  gap: 1.5rem;
}

.complex-card {
  display: subgrid;
  grid-template-rows: subgrid;
  background: white;
  border-radius: 0.5rem;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
  padding: 1.5rem;
}

.card-header {
  grid-row: 1;
}

.card-content {
  grid-row: 2;
}

.card-stats {
  grid-row: 3;
}

.card-footer {
  grid-row: 4;
}

Deze aanpak werkt briljant voor productkaarten, teammember profielen of welke kaartstructuur dan ook waar je consistent wilt dat elementen op dezelfde hoogte staan. De content kan variëren in lengte, maar de structurele elementen blijven altijd netjes uitgelijnd.

<div class="complex-dashboard-grid">
  <div class="complex-card">
    <div class="card-header">
      <h3 class="text-xl font-bold text-gray-900">Product Analytics</h3>
      <p class="text-sm text-gray-500">Real-time data overzicht</p>
    </div>
    
    <div class="card-content">
      <div class="space-y-4">
        <div class="h-32 bg-gradient-to-r from-blue-400 to-purple-500 rounded"></div>
        <p class="text-gray-600">Verkopen stijgen gestaag met een piek in het weekend. De conversie rate blijft stabiel rond de 3.2%.</p>
      </div>
    </div>
    
    <div class="card-stats">
      <div class="flex justify-between text-sm text-gray-600">
        <span>Conversie: 3.2%</span>
        <span>Bezoekers: 1,247</span>
      </div>
    </div>
    
    <div class="card-footer">
      <button class="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700">
        Bekijk details
      </button>
    </div>
  </div>
</div>

Subgrid combineren met Tailwind's responsive features

Een van de krachtige aspecten van subgrid is hoe het samenwerkt met responsive design. Tailwind's responsive utilities blijven gewoon werken, maar nu kun je ook de grid structuur zelf responsive maken terwijl subgrid de uitlijning behoudt.

Op mobiele schermen schakel ik vaak over naar een enkele kolom layout, maar behoud ik de rijstructuur voor consistentie. Op desktop gebruik ik meerdere kolommen waarbij subgrid ervoor zorgt dat alle kaarten hun interne elementen synchroon houden.

@media (min-width: 768px) {
  .responsive-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .responsive-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

Voor projecten waar Tailwind's JIT compiler actief is, definieer ik vaak custom utilities door deze toe te voegen aan mijn Tailwind configuratie. Dit maakt de HTML schoner en zorgt ervoor dat het subgrid gedrag herbruikbaar wordt across componenten.

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      gridTemplateRows: {
        'subgrid': 'subgrid',
      },
    },
  },
  plugins: [
    function({ addUtilities }) {
      addUtilities({
        '.subgrid-rows': {
          'display': 'subgrid',
          'grid-template-rows': 'subgrid',
        },
        '.subgrid-cols': {
          'display': 'subgrid',
          'grid-template-columns': 'subgrid',
        }
      })
    }
  ]
}

Browser fallbacks zijn essentieel als je subgrid in productie wilt gebruiken. Browsers die subgrid niet ondersteunen behandelen het als een onbekende waarde en vallen terug op de standaard grid behavior. Dit betekent dat je layout nog steeds functioneert, alleen zonder de perfecte uitlijning.

Feature detection met CSS @supports helpt om verschillende stijlen te leveren aan browsers met en zonder subgrid ondersteuning. Moderne browsers krijgen de verbeterde ervaring, oudere browsers krijgen een functionele maar minder verfijnde layout. Persoonlijk test ik altijd in Firefox Developer Edition omdat deze de meest complete subgrid implementatie heeft, en valideer ik vervolgens in andere browsers om er zeker van te zijn dat de fallback goed werkt. Het is een game changer voor complexe layouts waar traditionele CSS Grid tekortschiet, en ik verwacht dat we subgrid steeds meer gaan zien in moderne webapplicaties.