12 CSS Masonry Layouts10 / 12

CSS onlyMIT licensed

CSS Masonry Dashboard Widget Layout

An analytics board where KPI tiles, a bar chart, a conic-gradient donut, a clip-path sparkline and an activity feed each claim 1–3 units of a fixed 108px row lattice, and grid-auto-flow: dense keeps the board airtight as widgets reflow across container widths. Every chart is pure CSS — gradients, conic slices and clip-path polygons — so the whole dashboard costs zero script and one paint. Quantized masonry is what dashboards actually want.

Published

Live Demo
Try it

The code

<section class="msn-10" aria-label="CSS masonry dashboard widget layout demo">
  <div class="msn-10__stage" tabindex="0">
    <header class="msn-10__head">
      <div><h2>Deploy Ops</h2><p>Production · last 7 days</p></div>
      <div class="msn-10__range" role="group" aria-label="Date range"><a href="#7d" aria-current="true">7d</a><a href="#30d">30d</a><a href="#90d">90d</a></div>
    </header>
    <div class="msn-10__board">
      <article class="msn-10__w msn-10__w--1"><h3>Deploys</h3><p class="msn-10__kpi">312</p><span class="msn-10__delta msn-10__delta--up">▲ 18% vs last week</span></article>
      <article class="msn-10__w msn-10__w--1"><h3>Change fail rate</h3><p class="msn-10__kpi">2.1%</p><span class="msn-10__delta msn-10__delta--up">▲ healthy · under 5% target</span></article>
      <article class="msn-10__w msn-10__w--2"><h3>Deploys per day</h3><div class="msn-10__bars" role="img" aria-label="Bar chart: deploys per day, Monday 34 to Sunday 52, peaking Thursday at 61"><i style="--v:56%" data-d="M"></i><i style="--v:72%" data-d="T"></i><i style="--v:64%" data-d="W"></i><i style="--v:100%" data-d="T"></i><i style="--v:82%" data-d="F"></i><i style="--v:38%" data-d="S"></i><i style="--v:85%" data-d="S"></i></div></article>
      <article class="msn-10__w msn-10__w--2"><h3>Build minutes by runner</h3><div class="msn-10__donutRow"><div class="msn-10__donut" role="img" aria-label="Donut chart: Linux 58%, macOS 27%, Windows 15%"></div><ul class="msn-10__legend"><li><i style="--c:var(--acc)"></i>Linux <b>58%</b></li><li><i style="--c:oklch(0.75 0.12 85)"></i>macOS <b>27%</b></li><li><i style="--c:oklch(0.65 0.1 300)"></i>Windows <b>15%</b></li></ul></div></article>
      <article class="msn-10__w msn-10__w--1"><h3>p95 pipeline</h3><p class="msn-10__kpi">6m 12s</p><span class="msn-10__delta msn-10__delta--down">▼ 41s slower than 30d avg</span></article>
      <article class="msn-10__w msn-10__w--2"><h3>Queue latency</h3><div class="msn-10__spark" role="img" aria-label="Sparkline: queue latency trending down from 90 seconds to 22 seconds over the week"></div><p class="msn-10__sparkCap"><b>22s</b> now · 90s peak Tue</p></article>
      <article class="msn-10__w msn-10__w--3"><h3>Activity</h3><ul class="msn-10__feed"><li><i style="--a:oklch(0.75 0.11 300);--b:oklch(0.5 0.13 330)"></i><div><strong>rhea</strong> promoted <a href="#rel">v2.41.0</a> to prod<span>4 min ago</span></div></li><li><i style="--a:oklch(0.8 0.1 150);--b:oklch(0.55 0.12 170)"></i><div><strong>devon</strong> quarantined flaky <a href="#t">checkout.spec</a><span>26 min ago</span></div></li><li><i style="--a:oklch(0.78 0.1 40);--b:oklch(0.55 0.13 20)"></i><div><strong>ada</strong> rotated deploy keys<span>1 h ago</span></div></li><li><i style="--a:oklch(0.72 0.09 220);--b:oklch(0.48 0.11 240)"></i><div><strong>sam</strong> merged <a href="#pr">#4182 cache warmup</a><span>2 h ago</span></div></li><li><i style="--a:oklch(0.82 0.08 90);--b:oklch(0.6 0.11 70)"></i><div><strong>mia</strong> muted alerts for maint. window<span>3 h ago</span></div></li></ul><a class="msn-10__more" href="#audit">Open audit log</a></article>
      <article class="msn-10__w msn-10__w--1"><h3>MTTR</h3><p class="msn-10__kpi">14m</p><span class="msn-10__delta msn-10__delta--up">▲ best week this quarter</span></article>
      <article class="msn-10__w msn-10__w--1 msn-10__w--flag"><h3>Error budget</h3><p class="msn-10__kpi">72%</p><span class="msn-10__delta">remaining · resets in 9 days</span></article>
    </div>
  </div>
</section>
.msn-10,
.msn-10 *,
.msn-10 *::before,
.msn-10 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.msn-10 {
  --bg: oklch(0.97 0.005 250);
  --card: oklch(0.995 0.002 250);
  --ink: oklch(0.23 0.015 260);
  --mut: oklch(0.52 0.015 260);
  --line: oklch(0.89 0.008 250);
  --acc: oklch(0.58 0.16 250);
  --up: oklch(0.55 0.15 155);
  --down: oklch(0.55 0.19 25);
  font-family: 'Segoe UI',system-ui,sans-serif;
  color: var(--ink);
  container-type: inline-size;
  display: block;
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  background: var(--bg);
}

.msn-10__stage {
  width: 100%;
  container: msn10/inline-size;
  height: 100vh;
  height: 100svh;
  overflow-y: auto;
  background: var(--bg);
}

.msn-10__head {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px clamp(16px,3cqi,26px);
  background: color-mix(in oklch,var(--bg) 84%,transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}

.msn-10__head h2 {
  font-size: clamp(16px,2.3cqi,21px);
  letter-spacing: -.02em;
}

.msn-10__head p {
  font-size: 11.5px;
  color: var(--mut);
  margin-top: 2px;
}

.msn-10__range {
  display: flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--card);
}

.msn-10__range a {
  display: grid;
  place-items: center;
  min-height: 32px;
  min-width: 44px;
  padding: 0 10px;
  border-radius: 7px;
  font-size: 12px;
  font-weight: 700;
  text-decoration: none;
  color: var(--mut);
  transition: background .2s,color .2s;
}

.msn-10__range a:hover,
.msn-10__range a:focus-visible {
  color: var(--ink);
}

.msn-10__range a[aria-current] {
  background: var(--ink);
  color: var(--card);
}

.msn-10__range a:focus-visible {
  outline: 2px solid var(--acc);
  outline-offset: 1px;
}

.msn-10__board {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit,minmax(min(230px,100%),1fr));
  grid-auto-rows: 108px;
  grid-auto-flow: row dense;
  padding: clamp(14px,3cqi,26px);
}

.msn-10__w {
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--card);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 0;
  overflow: clip;
  transition: border-color .2s,box-shadow .2s;
}

.msn-10__w:hover {
  border-color: oklch(0.8 0.01 250);
  box-shadow: 0 8px 22px -14px oklch(0.4 0.03 250/.35);
}

.msn-10__w--1 {
  grid-row: span 1;
}

.msn-10__w--2 {
  grid-row: span 2;
}

.msn-10__w--3 {
  grid-row: span 3;
}

.msn-10__w h3 {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--mut);
}

.msn-10__kpi {
  font-size: clamp(26px,3cqi,34px);
  font-weight: 800;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.msn-10__delta {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--mut);
  margin-top: auto;
}

.msn-10__delta--up {
  color: var(--up);
}

.msn-10__delta--down {
  color: var(--down);
}

.msn-10__w--flag {
  background: linear-gradient(150deg,color-mix(in oklch,var(--acc) 14%,var(--card)),var(--card));
  border-color: color-mix(in oklch,var(--acc) 35%,var(--line));
}

.msn-10__bars {
  flex: 1;
  display: flex;
  align-items: end;
  gap: 8px;
  min-height: 0;
}

.msn-10__bars i {
  flex: 1;
  height: var(--v);
  border-radius: 6px 6px 3px 3px;
  background: linear-gradient(180deg,var(--acc),color-mix(in oklch,var(--acc) 55%,var(--card)));
  position: relative;
  transition: filter .2s;
}

.msn-10__bars i:hover {
  filter: brightness(1.12);
}

.msn-10__bars i::after {
  content: attr(data-d);
  position: absolute;
  left: 50%;
  translate: -50% 0;
  bottom: -16px;
  font-size: 9.5px;
  font-weight: 700;
  color: var(--mut);
}

.msn-10__bars {
  padding-bottom: 18px;
}

.msn-10__donutRow {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 0;
}

.msn-10__donut {
  width: min(108px,38cqi);
  aspect-ratio: 1;
  border-radius: 50%;
  background: conic-gradient(var(--acc) 0 58%,oklch(0.75 0.12 85) 58% 85%,oklch(0.65 0.1 300) 85% 100%);
  mask: radial-gradient(circle,transparent 44%,#000 45%);
  flex: none;
}

.msn-10__legend {
  list-style: none;
  display: grid;
  gap: 7px;
}

.msn-10__legend li {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12px;
  color: var(--mut);
}

.msn-10__legend li b {
  color: var(--ink);
  margin-left: auto;
  font-variant-numeric: tabular-nums;
}

.msn-10__legend i {
  width: 9px;
  height: 9px;
  border-radius: 3px;
  background: var(--c);
}

.msn-10__spark {
  flex: 1;
  min-height: 0;
  border-radius: 8px;
  background: linear-gradient(180deg,color-mix(in oklch,var(--acc) 55%,var(--card)),color-mix(in oklch,var(--acc) 10%,var(--card)));
  clip-path: polygon(0 62%,9% 48%,18% 71%,27% 90%,36% 60%,45% 52%,54% 68%,63% 42%,72% 48%,81% 30%,90% 34%,100% 22%,100% 100%,0 100%);
}

.msn-10__sparkCap {
  font-size: 11.5px;
  color: var(--mut);
}

.msn-10__sparkCap b {
  color: var(--ink);
}

.msn-10__feed {
  list-style: none;
  display: grid;
  gap: 12px;
  overflow: hidden;
}

.msn-10__feed li {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}

.msn-10__feed i {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  flex: none;
  background: linear-gradient(140deg,var(--a),var(--b));
}

.msn-10__feed div {
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--mut);
}

.msn-10__feed strong {
  color: var(--ink);
  font-weight: 700;
}

.msn-10__feed a {
  color: var(--acc);
  text-decoration: none;
  font-weight: 600;
}

.msn-10__feed a:hover,
.msn-10__feed a:focus-visible {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.msn-10__feed a:focus-visible {
  outline: 2px solid var(--acc);
  outline-offset: 2px;
  border-radius: 3px;
}

.msn-10__feed span {
  display: block;
  font-size: 10.5px;
  margin-top: 2px;
}

.msn-10__more {
  margin-top: auto;
  display: grid;
  place-items: center;
  min-height: 38px;
  border: 1px solid var(--line);
  border-radius: 9px;
  font-size: 12px;
  font-weight: 700;
  text-decoration: none;
  color: var(--ink);
  transition: background .2s,border-color .2s;
}

.msn-10__more:hover,
.msn-10__more:focus-visible {
  background: oklch(0.95 0.005 250);
  border-color: oklch(0.8 0.01 250);
}

.msn-10__more:focus-visible {
  outline: 2px solid var(--acc);
  outline-offset: 2px;
}

@container msn10 (width < 460px) {
  .msn-10__board {
    grid-auto-rows: 100px;
    gap: 9px;
  }

  .msn-10__range {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .msn-10 * {
    transition-duration: .01ms !important;
  }
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Masonry Layout from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Masonry Dashboard Widget Layout
Source: https://codefronts.com/layouts/css-masonry-layouts/css-masonry-dashboard-widget-layout/

An analytics board where KPI tiles, a bar chart, a conic-gradient donut, a clip-path sparkline and an activity feed each claim 1–3 units of a fixed 108px row lattice, and grid-auto-flow: dense keeps the board airtight as widgets reflow across container widths. Every chart is pure CSS — gradients, conic slices and clip-path polygons — so the whole dashboard costs zero script and one paint. Quantized masonry is what dashboards actually want.
## HTML
```html
<section class="msn-10" aria-label="CSS masonry dashboard widget layout demo">
  <div class="msn-10__stage" tabindex="0">
    <header class="msn-10__head">
      <div><h2>Deploy Ops</h2><p>Production · last 7 days</p></div>
      <div class="msn-10__range" role="group" aria-label="Date range"><a href="#7d" aria-current="true">7d</a><a href="#30d">30d</a><a href="#90d">90d</a></div>
    </header>
    <div class="msn-10__board">
      <article class="msn-10__w msn-10__w--1"><h3>Deploys</h3><p class="msn-10__kpi">312</p><span class="msn-10__delta msn-10__delta--up">▲ 18% vs last week</span></article>
      <article class="msn-10__w msn-10__w--1"><h3>Change fail rate</h3><p class="msn-10__kpi">2.1%</p><span class="msn-10__delta msn-10__delta--up">▲ healthy · under 5% target</span></article>
      <article class="msn-10__w msn-10__w--2"><h3>Deploys per day</h3><div class="msn-10__bars" role="img" aria-label="Bar chart: deploys per day, Monday 34 to Sunday 52, peaking Thursday at 61"><i style="--v:56%" data-d="M"></i><i style="--v:72%" data-d="T"></i><i style="--v:64%" data-d="W"></i><i style="--v:100%" data-d="T"></i><i style="--v:82%" data-d="F"></i><i style="--v:38%" data-d="S"></i><i style="--v:85%" data-d="S"></i></div></article>
      <article class="msn-10__w msn-10__w--2"><h3>Build minutes by runner</h3><div class="msn-10__donutRow"><div class="msn-10__donut" role="img" aria-label="Donut chart: Linux 58%, macOS 27%, Windows 15%"></div><ul class="msn-10__legend"><li><i style="--c:var(--acc)"></i>Linux <b>58%</b></li><li><i style="--c:oklch(0.75 0.12 85)"></i>macOS <b>27%</b></li><li><i style="--c:oklch(0.65 0.1 300)"></i>Windows <b>15%</b></li></ul></div></article>
      <article class="msn-10__w msn-10__w--1"><h3>p95 pipeline</h3><p class="msn-10__kpi">6m 12s</p><span class="msn-10__delta msn-10__delta--down">▼ 41s slower than 30d avg</span></article>
      <article class="msn-10__w msn-10__w--2"><h3>Queue latency</h3><div class="msn-10__spark" role="img" aria-label="Sparkline: queue latency trending down from 90 seconds to 22 seconds over the week"></div><p class="msn-10__sparkCap"><b>22s</b> now · 90s peak Tue</p></article>
      <article class="msn-10__w msn-10__w--3"><h3>Activity</h3><ul class="msn-10__feed"><li><i style="--a:oklch(0.75 0.11 300);--b:oklch(0.5 0.13 330)"></i><div><strong>rhea</strong> promoted <a href="#rel">v2.41.0</a> to prod<span>4 min ago</span></div></li><li><i style="--a:oklch(0.8 0.1 150);--b:oklch(0.55 0.12 170)"></i><div><strong>devon</strong> quarantined flaky <a href="#t">checkout.spec</a><span>26 min ago</span></div></li><li><i style="--a:oklch(0.78 0.1 40);--b:oklch(0.55 0.13 20)"></i><div><strong>ada</strong> rotated deploy keys<span>1 h ago</span></div></li><li><i style="--a:oklch(0.72 0.09 220);--b:oklch(0.48 0.11 240)"></i><div><strong>sam</strong> merged <a href="#pr">#4182 cache warmup</a><span>2 h ago</span></div></li><li><i style="--a:oklch(0.82 0.08 90);--b:oklch(0.6 0.11 70)"></i><div><strong>mia</strong> muted alerts for maint. window<span>3 h ago</span></div></li></ul><a class="msn-10__more" href="#audit">Open audit log</a></article>
      <article class="msn-10__w msn-10__w--1"><h3>MTTR</h3><p class="msn-10__kpi">14m</p><span class="msn-10__delta msn-10__delta--up">▲ best week this quarter</span></article>
      <article class="msn-10__w msn-10__w--1 msn-10__w--flag"><h3>Error budget</h3><p class="msn-10__kpi">72%</p><span class="msn-10__delta">remaining · resets in 9 days</span></article>
    </div>
  </div>
</section>
```
## CSS
```css
.msn-10,
.msn-10 *,
.msn-10 *::before,
.msn-10 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.msn-10 {
  --bg: oklch(0.97 0.005 250);
  --card: oklch(0.995 0.002 250);
  --ink: oklch(0.23 0.015 260);
  --mut: oklch(0.52 0.015 260);
  --line: oklch(0.89 0.008 250);
  --acc: oklch(0.58 0.16 250);
  --up: oklch(0.55 0.15 155);
  --down: oklch(0.55 0.19 25);
  font-family: 'Segoe UI',system-ui,sans-serif;
  color: var(--ink);
  container-type: inline-size;
  display: block;
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  background: var(--bg);
}

.msn-10__stage {
  width: 100%;
  container: msn10/inline-size;
  height: 100vh;
  height: 100svh;
  overflow-y: auto;
  background: var(--bg);
}

.msn-10__head {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px clamp(16px,3cqi,26px);
  background: color-mix(in oklch,var(--bg) 84%,transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}

.msn-10__head h2 {
  font-size: clamp(16px,2.3cqi,21px);
  letter-spacing: -.02em;
}

.msn-10__head p {
  font-size: 11.5px;
  color: var(--mut);
  margin-top: 2px;
}

.msn-10__range {
  display: flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--card);
}

.msn-10__range a {
  display: grid;
  place-items: center;
  min-height: 32px;
  min-width: 44px;
  padding: 0 10px;
  border-radius: 7px;
  font-size: 12px;
  font-weight: 700;
  text-decoration: none;
  color: var(--mut);
  transition: background .2s,color .2s;
}

.msn-10__range a:hover,
.msn-10__range a:focus-visible {
  color: var(--ink);
}

.msn-10__range a[aria-current] {
  background: var(--ink);
  color: var(--card);
}

.msn-10__range a:focus-visible {
  outline: 2px solid var(--acc);
  outline-offset: 1px;
}

.msn-10__board {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit,minmax(min(230px,100%),1fr));
  grid-auto-rows: 108px;
  grid-auto-flow: row dense;
  padding: clamp(14px,3cqi,26px);
}

.msn-10__w {
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--card);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 0;
  overflow: clip;
  transition: border-color .2s,box-shadow .2s;
}

.msn-10__w:hover {
  border-color: oklch(0.8 0.01 250);
  box-shadow: 0 8px 22px -14px oklch(0.4 0.03 250/.35);
}

.msn-10__w--1 {
  grid-row: span 1;
}

.msn-10__w--2 {
  grid-row: span 2;
}

.msn-10__w--3 {
  grid-row: span 3;
}

.msn-10__w h3 {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--mut);
}

.msn-10__kpi {
  font-size: clamp(26px,3cqi,34px);
  font-weight: 800;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.msn-10__delta {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--mut);
  margin-top: auto;
}

.msn-10__delta--up {
  color: var(--up);
}

.msn-10__delta--down {
  color: var(--down);
}

.msn-10__w--flag {
  background: linear-gradient(150deg,color-mix(in oklch,var(--acc) 14%,var(--card)),var(--card));
  border-color: color-mix(in oklch,var(--acc) 35%,var(--line));
}

.msn-10__bars {
  flex: 1;
  display: flex;
  align-items: end;
  gap: 8px;
  min-height: 0;
}

.msn-10__bars i {
  flex: 1;
  height: var(--v);
  border-radius: 6px 6px 3px 3px;
  background: linear-gradient(180deg,var(--acc),color-mix(in oklch,var(--acc) 55%,var(--card)));
  position: relative;
  transition: filter .2s;
}

.msn-10__bars i:hover {
  filter: brightness(1.12);
}

.msn-10__bars i::after {
  content: attr(data-d);
  position: absolute;
  left: 50%;
  translate: -50% 0;
  bottom: -16px;
  font-size: 9.5px;
  font-weight: 700;
  color: var(--mut);
}

.msn-10__bars {
  padding-bottom: 18px;
}

.msn-10__donutRow {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 0;
}

.msn-10__donut {
  width: min(108px,38cqi);
  aspect-ratio: 1;
  border-radius: 50%;
  background: conic-gradient(var(--acc) 0 58%,oklch(0.75 0.12 85) 58% 85%,oklch(0.65 0.1 300) 85% 100%);
  mask: radial-gradient(circle,transparent 44%,#000 45%);
  flex: none;
}

.msn-10__legend {
  list-style: none;
  display: grid;
  gap: 7px;
}

.msn-10__legend li {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12px;
  color: var(--mut);
}

.msn-10__legend li b {
  color: var(--ink);
  margin-left: auto;
  font-variant-numeric: tabular-nums;
}

.msn-10__legend i {
  width: 9px;
  height: 9px;
  border-radius: 3px;
  background: var(--c);
}

.msn-10__spark {
  flex: 1;
  min-height: 0;
  border-radius: 8px;
  background: linear-gradient(180deg,color-mix(in oklch,var(--acc) 55%,var(--card)),color-mix(in oklch,var(--acc) 10%,var(--card)));
  clip-path: polygon(0 62%,9% 48%,18% 71%,27% 90%,36% 60%,45% 52%,54% 68%,63% 42%,72% 48%,81% 30%,90% 34%,100% 22%,100% 100%,0 100%);
}

.msn-10__sparkCap {
  font-size: 11.5px;
  color: var(--mut);
}

.msn-10__sparkCap b {
  color: var(--ink);
}

.msn-10__feed {
  list-style: none;
  display: grid;
  gap: 12px;
  overflow: hidden;
}

.msn-10__feed li {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}

.msn-10__feed i {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  flex: none;
  background: linear-gradient(140deg,var(--a),var(--b));
}

.msn-10__feed div {
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--mut);
}

.msn-10__feed strong {
  color: var(--ink);
  font-weight: 700;
}

.msn-10__feed a {
  color: var(--acc);
  text-decoration: none;
  font-weight: 600;
}

.msn-10__feed a:hover,
.msn-10__feed a:focus-visible {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.msn-10__feed a:focus-visible {
  outline: 2px solid var(--acc);
  outline-offset: 2px;
  border-radius: 3px;
}

.msn-10__feed span {
  display: block;
  font-size: 10.5px;
  margin-top: 2px;
}

.msn-10__more {
  margin-top: auto;
  display: grid;
  place-items: center;
  min-height: 38px;
  border: 1px solid var(--line);
  border-radius: 9px;
  font-size: 12px;
  font-weight: 700;
  text-decoration: none;
  color: var(--ink);
  transition: background .2s,border-color .2s;
}

.msn-10__more:hover,
.msn-10__more:focus-visible {
  background: oklch(0.95 0.005 250);
  border-color: oklch(0.8 0.01 250);
}

.msn-10__more:focus-visible {
  outline: 2px solid var(--acc);
  outline-offset: 2px;
}

@container msn10 (width < 460px) {
  .msn-10__board {
    grid-auto-rows: 100px;
    gap: 9px;
  }

  .msn-10__range {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .msn-10 * {
    transition-duration: .01ms !important;
  }
}
```

How this works

Dashboards should NOT free-pack like photo walls — operators scan by alignment, so heights snap to a coarse lattice and dense backfills the seams:

.board{ display:grid; gap:12px;
  grid-template-columns: repeat(auto-fit, minmax(min(230px,100%),1fr));
  grid-auto-rows: 108px; grid-auto-flow: row dense; }
.w-1{ grid-row: span 1; }  /* KPI      */
.w-2{ grid-row: span 2; }  /* charts   */
.w-3{ grid-row: span 3; }  /* feeds    */

Three sizes, nothing else — the coarse quantum is the design system. auto-fit (vs demo 03's auto-fill) collapses empty tracks so a narrow sidebar embed gets full-width widgets instead of ghost columns. When the column count changes, dense re-knits the board with no holes; DOM order = announcement order stays untouched, and since widgets are self-contained cards, the visual shuffle is harmless here in a way it wouldn't be for prose.

The charts are the flex: bars are a flex row of gradient divs with per-bar --v heights; the donut is one conic-gradient with a punched center (radial mask) and real legend text; the sparkline is a gradient block clipped by a clip-path: polygon() whose points ARE the data. Each chart carries a visually-hidden sentence ('Deploy frequency up 18% week over week') because a div-painting is decoration to a screen reader — the sentence is the chart. Numbers use font-variant-numeric: tabular-nums so KPIs don't wiggle when they tick.

Make it yours

  • Row quantum: 108px fits a KPI with delta chip; 96px tightens ops-density, 128px breathes for exec views. All spans scale because they're units, not pixels.
  • New widget recipe: pick a span class, drop your content in a .msn-10__w card — the board places it. Pin something to a region with grid-column:1/-1 for a full-width alert strip.
  • Sparkline data: the polygon's x-coords are evenly spaced samples, y-coords are 100−value; regenerate the point list server-side and the chart updates with zero chart library.
  • Theme: the board reads tokens from the root — swapping --bg/--card/--ink to the dark set in a prefers-color-scheme block is a 6-line dark mode.

Gotchas — read before shipping

  • auto-FIT collapses unused tracks, auto-FILL keeps them — dashboards want fit (widgets grow), photo feeds want fill (density holds). Mixing them up is the #1 'why is there a gap' report.
  • Pure-CSS charts are for glanceable shapes, not analysis — no tooltips, no keyboard data table. Pair each with a visually-hidden summary or a real table behind a details element.
  • Don't span KPIs to 'fill space' — a stretched number card reads as more important, and operators rank by size. Size = information hierarchy, always.
  • conic-gradient donuts need a mask, not a nested circle div — the inner-circle hack breaks the moment the card background isn't flat.

Browser support

ChromeSafariFirefoxEdge
111+16.4+113+111+

conic-gradient, clip-path and mask are all 2020-universal; oklch, color-mix and container queries set the stated floor. tabular-nums is cosmetic and safe everywhere.

Techniques used in this demo

Search CodeFronts

Loading…