27 CSS Calendars05 / 27

CSS + JSMIT licensed

CSS Grid Calendar Layout

An editorial magazine layout showcasing display:grid with grid-template-columns:repeat(7,1fr). A 1px gap over a colored parent fakes clean grid lines; column headers and date grid share the same 7-track system. Playfair Display masthead, rust/sage/sand event labels.

Published

Live Demo
Try it

The code

<div class="cal05">
  <div class="cal05__shell">

    <!-- Masthead -->
    <div class="cal05__masthead">
      <div class="cal05__masthead-left">Vol. VI &nbsp;·&nbsp; Issue 6 &nbsp;·&nbsp; Q2 2026</div>
      <div class="cal05__masthead-center">
        <div class="cal05__title">June<span>.</span></div>
        <div class="cal05__subtitle">CSS Grid Calendar Layout &nbsp;·&nbsp; display: grid; repeat(7, 1fr)</div>
      </div>
      <div class="cal05__masthead-right">
        <div class="cal05__nav">
          <div class="cal05__nav-btn">←</div>
          <div class="cal05__nav-btn">→</div>
        </div>
      </div>
    </div>

    <!-- Column headers — also a 7-col grid -->
    <div class="cal05__col-headers">
      <div class="cal05__col-header cal05__col-header--weekend">
        <div class="cal05__col-day-abbr">Sun</div>
        <div class="cal05__col-day-num">wk</div>
      </div>
      <div class="cal05__col-header">
        <div class="cal05__col-day-abbr">Mon</div>
        <div class="cal05__col-day-num">col 2</div>
      </div>
      <div class="cal05__col-header">
        <div class="cal05__col-day-abbr">Tue</div>
        <div class="cal05__col-day-num">col 3</div>
      </div>
      <div class="cal05__col-header">
        <div class="cal05__col-day-abbr">Wed</div>
        <div class="cal05__col-day-num">col 4</div>
      </div>
      <div class="cal05__col-header">
        <div class="cal05__col-day-abbr">Thu</div>
        <div class="cal05__col-day-num">col 5</div>
      </div>
      <div class="cal05__col-header">
        <div class="cal05__col-day-abbr">Fri</div>
        <div class="cal05__col-day-num">col 6</div>
      </div>
      <div class="cal05__col-header cal05__col-header--weekend">
        <div class="cal05__col-day-abbr">Sat</div>
        <div class="cal05__col-day-num">col 7</div>
      </div>
    </div>

    <!--
      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
        CSS GRID: display:grid; grid-template-columns:repeat(7,1fr)
        Each .cal05__cell auto-places into the next column.
        grid-auto-rows: minmax(100px, auto) — rows expand to fit content.
        gap: 1px + background on parent = visible grid lines.
      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    -->
    <div class="cal05__grid" id="cal05Grid">

      <!-- Row 1: May overflow (grid auto-places, starts col 1 = Sun) -->
      <div class="cal05__cell cal05__cell--other cal05__cell--weekend">
        <div class="cal05__week-tag">W21</div>
        <div class="cal05__cell-num">25</div>
      </div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">26</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">27</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">28</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">29</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">30</div></div>
      <div class="cal05__cell cal05__cell--other cal05__cell--weekend"><div class="cal05__cell-num">31</div></div>

      <!-- Row 2 -->
      <div class="cal05__cell cal05__cell--weekend">
        <div class="cal05__week-tag">W22</div>
        <div class="cal05__cell-num">1</div>
      </div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">2</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--rust">Design Sprint</div>
        </div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">3</div></div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">4</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--sand">Holiday</div>
        </div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">5</div></div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">6</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--sage">Deadline</div>
        </div>
      </div>
      <div class="cal05__cell cal05__cell--weekend"><div class="cal05__cell-num">7</div></div>

      <!-- Row 3: Today = Jun 8 (Sunday) -->
      <div class="cal05__cell cal05__cell--today cal05__cell--weekend" id="cal05Today">
        <div class="cal05__week-tag">W23</div>
        <div class="cal05__cell-num">8</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--rust">Today</div>
        </div>
      </div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">9</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--sage">Sprint</div>
        </div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">10</div></div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">11</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--rust">Launch</div>
          <div class="cal05__event cal05__event--ink">All-hands</div>
        </div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">12</div></div>
      <div class="cal05__cell"><div class="cal05__cell-num">13</div></div>
      <div class="cal05__cell cal05__cell--weekend"><div class="cal05__cell-num">14</div></div>

      <!-- Row 4 -->
      <div class="cal05__cell cal05__cell--weekend">
        <div class="cal05__week-tag">W24</div>
        <div class="cal05__cell-num">15</div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">16</div></div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">17</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--sand">Demo Day</div>
          <div class="cal05__event cal05__event--sage">Q2 Report</div>
        </div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">18</div></div>
      <div class="cal05__cell"><div class="cal05__cell-num">19</div></div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">20</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--rust">Board Mtg</div>
        </div>
      </div>
      <div class="cal05__cell cal05__cell--weekend"><div class="cal05__cell-num">21</div></div>

      <!-- Row 5 -->
      <div class="cal05__cell cal05__cell--weekend">
        <div class="cal05__week-tag">W25</div>
        <div class="cal05__cell-num">22</div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">23</div></div>
      <div class="cal05__cell"><div class="cal05__cell-num">24</div></div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">25</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--ink">Planning</div>
        </div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">26</div></div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">27</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--sage">Retro</div>
        </div>
      </div>
      <div class="cal05__cell cal05__cell--weekend"><div class="cal05__cell-num">28</div></div>

      <!-- Row 6 -->
      <div class="cal05__cell cal05__cell--weekend">
        <div class="cal05__week-tag">W26</div>
        <div class="cal05__cell-num">29</div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">30</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">1</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">2</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">3</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">4</div></div>
      <div class="cal05__cell cal05__cell--other cal05__cell--weekend"><div class="cal05__cell-num">5</div></div>

    </div><!-- /grid -->

    <!-- Annotation strip -->
    <div class="cal05__annotation">
      <div class="cal05__ann-cell">
        <div class="cal05__ann-label">Grid columns</div>
        <div class="cal05__ann-value">7</div>
        <div class="cal05__ann-sub">repeat(7, 1fr)</div>
      </div>
      <div class="cal05__ann-cell">
        <div class="cal05__ann-label">Events this month</div>
        <div class="cal05__ann-value">11</div>
        <div class="cal05__ann-sub">across 30 days</div>
      </div>
      <div class="cal05__ann-cell">
        <div class="cal05__ann-label">Week in year</div>
        <div class="cal05__ann-value">W23</div>
        <div class="cal05__ann-sub">Q2 · Day 159</div>
      </div>
    </div>

    <!-- Legend -->
    <div class="cal05__legend">
      <span class="cal05__legend-label">Legend:</span>
      <div class="cal05__legend-item"><div class="cal05__legend-swatch" style="background:#c94f2c"></div>Priority</div>
      <div class="cal05__legend-item"><div class="cal05__legend-swatch" style="background:#4a7c6f"></div>Milestone</div>
      <div class="cal05__legend-item"><div class="cal05__legend-swatch" style="background:#d4a853"></div>Holiday</div>
      <div class="cal05__legend-item"><div class="cal05__legend-swatch" style="background:#1a1a2e"></div>General</div>
    </div>

  </div>
</div>
.cal05,
.cal05 *,
.cal05 *::before,
.cal05 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cal05 ::selection {
  background: #1a1a2e;
  color: #f5e6c8;
}

.cal05 {
  --cream: #f8f4ed;
  --warm: #ede5d5;
  --ink: #1a1a2e;
  --ink2: #4a4a6a;
  --ink3: #8a8aaa;
  --rust: #c94f2c;
  --sage: #4a7c6f;
  --sand: #d4a853;
  --grid-gap: 1px;
  --border: rgba(26,26,46,0.1);
  font-family: 'Barlow', sans-serif;
  background: var(--cream);
  min-height: 100vh;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 40px 20px;
  color: var(--ink);
}

@keyframes cal05-enter {
  from {
    opacity: 0;
    transform: translateY(20px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes cal05-highlight {
  from {
    background: rgba(201,79,44,0.15);
  }

  to {
    background: transparent;
  }
}
/* ── Shell ── */

.cal05__shell {
  width: 100%;
  max-width: 900px;
  animation: cal05-enter 0.5s ease both;
}
/* ── Masthead ── */

.cal05__masthead {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: end;
  padding-bottom: 20px;
  border-bottom: 3px double var(--ink);
  margin-bottom: 0;
}

.cal05__masthead-left {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--ink3);
  align-self: center;
}

.cal05__masthead-center {
  text-align: center;
  padding: 0 32px;
}

.cal05__title {
  font-family: 'Playfair Display', serif;
  font-size: 80px;
  font-weight: 900;
  font-style: italic;
  line-height: 0.9;
  letter-spacing: -0.02em;
  color: var(--ink);
}

.cal05__title span {
  color: var(--rust);
}

.cal05__subtitle {
  font-size: 11px;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  color: var(--ink3);
  margin-top: 8px;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  padding: 6px 0;
}

.cal05__masthead-right {
  text-align: right;
  align-self: center;
}

.cal05__nav {
  display: flex;
  gap: 4px;
  justify-content: flex-end;
}

.cal05__nav-btn {
  width: 36px;
  height: 36px;
  border: 1.5px solid var(--ink);
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 16px;
  color: var(--ink);
  transition: all 0.15s;
  font-family: 'Barlow', sans-serif;
  user-select: none;
}

.cal05__nav-btn:hover {
  background: var(--ink);
  color: var(--cream);
}
/* ── Column headers ── */

.cal05__col-headers {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--grid-gap);
  background: var(--border);
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  margin-top: 24px;
}

.cal05__col-header {
  background: var(--warm);
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.cal05__col-day-abbr {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink3);
}

.cal05__col-day-num {
  font-family: 'Playfair Display', serif;
  font-size: 22px;
  font-weight: 700;
  color: var(--ink);
  line-height: 1;
}
/* Highlight the current day column header */

.cal05__col-header--today .cal05__col-day-abbr {
  color: var(--rust);
}

.cal05__col-header--today .cal05__col-day-num {
  color: var(--rust);
}

.cal05__col-header--weekend .cal05__col-day-abbr {
  color: var(--sage);
  opacity: 0.7;
}
/* ── Main CSS Grid: The Star of the Show ── */
/*
  Core technique:
  - display: grid
  - grid-template-columns: repeat(7, 1fr) — 7 equal columns for 7 days
  - gap creates the gutters; background on the container "fakes" visible grid lines
  - Each cell: grid-column auto-places days correctly
  - named grid areas optionally mark special rows
*/

.cal05__grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-auto-rows: minmax(100px, auto);
  gap: var(--grid-gap);
  background: var(--border);
  /* gap shows through as grid lines */
  border: 1px solid var(--border);
  border-top: none;
}
/* ── Individual date cells ── */

.cal05__cell {
  background: var(--cream);
  padding: 10px 12px 8px;
  cursor: pointer;
  transition: background 0.15s;
  display: flex;
  flex-direction: column;
  gap: 4px;
  position: relative;
  min-height: 100px;
}

.cal05__cell:hover {
  background: rgba(212,168,83,0.08);
}

.cal05__cell--other {
  background: var(--warm);
  opacity: 0.5;
  pointer-events: none;
}

.cal05__cell--weekend {
  background: #f5f0e6;
}

.cal05__cell--today {
  background: #fff9f0;
}

.cal05__cell--today::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: var(--rust);
}

.cal05__cell--selected {
  background: rgba(201,79,44,0.06);
  outline: 2px solid var(--rust);
  outline-offset: -2px;
  z-index: 2;
}
/* Cell number */

.cal05__cell-num {
  font-family: 'Playfair Display', serif;
  font-size: 20px;
  font-weight: 700;
  line-height: 1;
  color: var(--ink);
}

.cal05__cell--today .cal05__cell-num {
  color: var(--rust);
}

.cal05__cell--other .cal05__cell-num {
  color: var(--ink3);
}

.cal05__cell--weekend:not(.cal05__cell--today) .cal05__cell-num {
  color: var(--sage);
}
/* Week number annotation */

.cal05__week-tag {
  position: absolute;
  top: 10px;
  right: 10px;
  font-size: 9px;
  letter-spacing: 0.1em;
  color: var(--ink3);
  opacity: 0.5;
}
/* Events inside cells */

.cal05__cell-events {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin-top: auto;
}

.cal05__event {
  font-size: 10px;
  font-weight: 500;
  padding: 3px 6px;
  border-left: 3px solid transparent;
  letter-spacing: 0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  background: rgba(26,26,46,0.04);
}

.cal05__event--rust {
  border-left-color: var(--rust);
  color: var(--rust);
  background: rgba(201,79,44,0.06);
}

.cal05__event--sage {
  border-left-color: var(--sage);
  color: var(--sage);
  background: rgba(74,124,111,0.08);
}

.cal05__event--sand {
  border-left-color: var(--sand);
  color: #8b6914;
  background: rgba(212,168,83,0.1);
}

.cal05__event--ink {
  border-left-color: var(--ink);
  color: var(--ink2);
}
/* ── Grid annotation panel below ── */

.cal05__annotation {
  margin-top: 20px;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
}

.cal05__ann-cell {
  background: var(--cream);
  padding: 16px 20px;
}

.cal05__ann-label {
  font-size: 9px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--ink3);
  margin-bottom: 6px;
}

.cal05__ann-value {
  font-family: 'Playfair Display', serif;
  font-size: 28px;
  font-weight: 700;
  color: var(--ink);
  line-height: 1;
}

.cal05__ann-sub {
  font-size: 11px;
  color: var(--ink3);
  margin-top: 4px;
}
/* ── Legend ── */

.cal05__legend {
  margin-top: 16px;
  display: flex;
  gap: 20px;
  align-items: center;
  padding: 12px 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}

.cal05__legend-label {
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink3);
  margin-right: 4px;
}

.cal05__legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--ink2);
}

.cal05__legend-swatch {
  width: 16px;
  height: 3px;
  border-radius: 1px;
}

@media (max-width: 640px) {
  .cal05__title {
    font-size: 48px;
  }

  .cal05__masthead {
    grid-template-columns: 1fr;
    gap: 12px;
  }

  .cal05__masthead-right {
    text-align: left;
  }

  .cal05__grid {
    grid-auto-rows: minmax(70px, auto);
  }

  .cal05__cell {
    padding: 6px 8px;
  }

  .cal05__cell-num {
    font-size: 15px;
  }

  .cal05__event {
    display: none;
  }

  .cal05__annotation {
    grid-template-columns: 1fr 1fr;
  }

  .cal05__ann-cell:last-child {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cal05 * {
    animation: none !important;
    transition: none !important;
  }
}
document.querySelectorAll('#cal05Grid .cal05__cell:not(.cal05__cell--other)').forEach(cell => {
  cell.addEventListener('click', function() {
    document.querySelectorAll('#cal05Grid .cal05__cell').forEach(c => c.classList.remove('cal05__cell--selected'));
    this.classList.add('cal05__cell--selected');
  });
});
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 Calendar 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 Grid Calendar Layout
Source: https://codefronts.com/components/css-calendar-designs/css-grid-calendar-layout/

An editorial magazine layout showcasing display:grid with grid-template-columns:repeat(7,1fr). A 1px gap over a colored parent fakes clean grid lines; column headers and date grid share the same 7-track system. Playfair Display masthead, rust/sage/sand event labels.
## HTML
```html
<div class="cal05">
  <div class="cal05__shell">

    <!-- Masthead -->
    <div class="cal05__masthead">
      <div class="cal05__masthead-left">Vol. VI &nbsp;·&nbsp; Issue 6 &nbsp;·&nbsp; Q2 2026</div>
      <div class="cal05__masthead-center">
        <div class="cal05__title">June<span>.</span></div>
        <div class="cal05__subtitle">CSS Grid Calendar Layout &nbsp;·&nbsp; display: grid; repeat(7, 1fr)</div>
      </div>
      <div class="cal05__masthead-right">
        <div class="cal05__nav">
          <div class="cal05__nav-btn">←</div>
          <div class="cal05__nav-btn">→</div>
        </div>
      </div>
    </div>

    <!-- Column headers — also a 7-col grid -->
    <div class="cal05__col-headers">
      <div class="cal05__col-header cal05__col-header--weekend">
        <div class="cal05__col-day-abbr">Sun</div>
        <div class="cal05__col-day-num">wk</div>
      </div>
      <div class="cal05__col-header">
        <div class="cal05__col-day-abbr">Mon</div>
        <div class="cal05__col-day-num">col 2</div>
      </div>
      <div class="cal05__col-header">
        <div class="cal05__col-day-abbr">Tue</div>
        <div class="cal05__col-day-num">col 3</div>
      </div>
      <div class="cal05__col-header">
        <div class="cal05__col-day-abbr">Wed</div>
        <div class="cal05__col-day-num">col 4</div>
      </div>
      <div class="cal05__col-header">
        <div class="cal05__col-day-abbr">Thu</div>
        <div class="cal05__col-day-num">col 5</div>
      </div>
      <div class="cal05__col-header">
        <div class="cal05__col-day-abbr">Fri</div>
        <div class="cal05__col-day-num">col 6</div>
      </div>
      <div class="cal05__col-header cal05__col-header--weekend">
        <div class="cal05__col-day-abbr">Sat</div>
        <div class="cal05__col-day-num">col 7</div>
      </div>
    </div>

    <!--
      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
        CSS GRID: display:grid; grid-template-columns:repeat(7,1fr)
        Each .cal05__cell auto-places into the next column.
        grid-auto-rows: minmax(100px, auto) — rows expand to fit content.
        gap: 1px + background on parent = visible grid lines.
      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    -->
    <div class="cal05__grid" id="cal05Grid">

      <!-- Row 1: May overflow (grid auto-places, starts col 1 = Sun) -->
      <div class="cal05__cell cal05__cell--other cal05__cell--weekend">
        <div class="cal05__week-tag">W21</div>
        <div class="cal05__cell-num">25</div>
      </div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">26</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">27</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">28</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">29</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">30</div></div>
      <div class="cal05__cell cal05__cell--other cal05__cell--weekend"><div class="cal05__cell-num">31</div></div>

      <!-- Row 2 -->
      <div class="cal05__cell cal05__cell--weekend">
        <div class="cal05__week-tag">W22</div>
        <div class="cal05__cell-num">1</div>
      </div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">2</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--rust">Design Sprint</div>
        </div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">3</div></div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">4</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--sand">Holiday</div>
        </div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">5</div></div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">6</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--sage">Deadline</div>
        </div>
      </div>
      <div class="cal05__cell cal05__cell--weekend"><div class="cal05__cell-num">7</div></div>

      <!-- Row 3: Today = Jun 8 (Sunday) -->
      <div class="cal05__cell cal05__cell--today cal05__cell--weekend" id="cal05Today">
        <div class="cal05__week-tag">W23</div>
        <div class="cal05__cell-num">8</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--rust">Today</div>
        </div>
      </div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">9</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--sage">Sprint</div>
        </div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">10</div></div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">11</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--rust">Launch</div>
          <div class="cal05__event cal05__event--ink">All-hands</div>
        </div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">12</div></div>
      <div class="cal05__cell"><div class="cal05__cell-num">13</div></div>
      <div class="cal05__cell cal05__cell--weekend"><div class="cal05__cell-num">14</div></div>

      <!-- Row 4 -->
      <div class="cal05__cell cal05__cell--weekend">
        <div class="cal05__week-tag">W24</div>
        <div class="cal05__cell-num">15</div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">16</div></div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">17</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--sand">Demo Day</div>
          <div class="cal05__event cal05__event--sage">Q2 Report</div>
        </div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">18</div></div>
      <div class="cal05__cell"><div class="cal05__cell-num">19</div></div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">20</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--rust">Board Mtg</div>
        </div>
      </div>
      <div class="cal05__cell cal05__cell--weekend"><div class="cal05__cell-num">21</div></div>

      <!-- Row 5 -->
      <div class="cal05__cell cal05__cell--weekend">
        <div class="cal05__week-tag">W25</div>
        <div class="cal05__cell-num">22</div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">23</div></div>
      <div class="cal05__cell"><div class="cal05__cell-num">24</div></div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">25</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--ink">Planning</div>
        </div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">26</div></div>
      <div class="cal05__cell">
        <div class="cal05__cell-num">27</div>
        <div class="cal05__cell-events">
          <div class="cal05__event cal05__event--sage">Retro</div>
        </div>
      </div>
      <div class="cal05__cell cal05__cell--weekend"><div class="cal05__cell-num">28</div></div>

      <!-- Row 6 -->
      <div class="cal05__cell cal05__cell--weekend">
        <div class="cal05__week-tag">W26</div>
        <div class="cal05__cell-num">29</div>
      </div>
      <div class="cal05__cell"><div class="cal05__cell-num">30</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">1</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">2</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">3</div></div>
      <div class="cal05__cell cal05__cell--other"><div class="cal05__cell-num">4</div></div>
      <div class="cal05__cell cal05__cell--other cal05__cell--weekend"><div class="cal05__cell-num">5</div></div>

    </div><!-- /grid -->

    <!-- Annotation strip -->
    <div class="cal05__annotation">
      <div class="cal05__ann-cell">
        <div class="cal05__ann-label">Grid columns</div>
        <div class="cal05__ann-value">7</div>
        <div class="cal05__ann-sub">repeat(7, 1fr)</div>
      </div>
      <div class="cal05__ann-cell">
        <div class="cal05__ann-label">Events this month</div>
        <div class="cal05__ann-value">11</div>
        <div class="cal05__ann-sub">across 30 days</div>
      </div>
      <div class="cal05__ann-cell">
        <div class="cal05__ann-label">Week in year</div>
        <div class="cal05__ann-value">W23</div>
        <div class="cal05__ann-sub">Q2 · Day 159</div>
      </div>
    </div>

    <!-- Legend -->
    <div class="cal05__legend">
      <span class="cal05__legend-label">Legend:</span>
      <div class="cal05__legend-item"><div class="cal05__legend-swatch" style="background:#c94f2c"></div>Priority</div>
      <div class="cal05__legend-item"><div class="cal05__legend-swatch" style="background:#4a7c6f"></div>Milestone</div>
      <div class="cal05__legend-item"><div class="cal05__legend-swatch" style="background:#d4a853"></div>Holiday</div>
      <div class="cal05__legend-item"><div class="cal05__legend-swatch" style="background:#1a1a2e"></div>General</div>
    </div>

  </div>
</div>
```
## CSS
```css
.cal05,
.cal05 *,
.cal05 *::before,
.cal05 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cal05 ::selection {
  background: #1a1a2e;
  color: #f5e6c8;
}

.cal05 {
  --cream: #f8f4ed;
  --warm: #ede5d5;
  --ink: #1a1a2e;
  --ink2: #4a4a6a;
  --ink3: #8a8aaa;
  --rust: #c94f2c;
  --sage: #4a7c6f;
  --sand: #d4a853;
  --grid-gap: 1px;
  --border: rgba(26,26,46,0.1);
  font-family: 'Barlow', sans-serif;
  background: var(--cream);
  min-height: 100vh;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 40px 20px;
  color: var(--ink);
}

@keyframes cal05-enter {
  from {
    opacity: 0;
    transform: translateY(20px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes cal05-highlight {
  from {
    background: rgba(201,79,44,0.15);
  }

  to {
    background: transparent;
  }
}
/* ── Shell ── */

.cal05__shell {
  width: 100%;
  max-width: 900px;
  animation: cal05-enter 0.5s ease both;
}
/* ── Masthead ── */

.cal05__masthead {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: end;
  padding-bottom: 20px;
  border-bottom: 3px double var(--ink);
  margin-bottom: 0;
}

.cal05__masthead-left {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--ink3);
  align-self: center;
}

.cal05__masthead-center {
  text-align: center;
  padding: 0 32px;
}

.cal05__title {
  font-family: 'Playfair Display', serif;
  font-size: 80px;
  font-weight: 900;
  font-style: italic;
  line-height: 0.9;
  letter-spacing: -0.02em;
  color: var(--ink);
}

.cal05__title span {
  color: var(--rust);
}

.cal05__subtitle {
  font-size: 11px;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  color: var(--ink3);
  margin-top: 8px;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  padding: 6px 0;
}

.cal05__masthead-right {
  text-align: right;
  align-self: center;
}

.cal05__nav {
  display: flex;
  gap: 4px;
  justify-content: flex-end;
}

.cal05__nav-btn {
  width: 36px;
  height: 36px;
  border: 1.5px solid var(--ink);
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 16px;
  color: var(--ink);
  transition: all 0.15s;
  font-family: 'Barlow', sans-serif;
  user-select: none;
}

.cal05__nav-btn:hover {
  background: var(--ink);
  color: var(--cream);
}
/* ── Column headers ── */

.cal05__col-headers {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--grid-gap);
  background: var(--border);
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  margin-top: 24px;
}

.cal05__col-header {
  background: var(--warm);
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.cal05__col-day-abbr {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink3);
}

.cal05__col-day-num {
  font-family: 'Playfair Display', serif;
  font-size: 22px;
  font-weight: 700;
  color: var(--ink);
  line-height: 1;
}
/* Highlight the current day column header */

.cal05__col-header--today .cal05__col-day-abbr {
  color: var(--rust);
}

.cal05__col-header--today .cal05__col-day-num {
  color: var(--rust);
}

.cal05__col-header--weekend .cal05__col-day-abbr {
  color: var(--sage);
  opacity: 0.7;
}
/* ── Main CSS Grid: The Star of the Show ── */
/*
  Core technique:
  - display: grid
  - grid-template-columns: repeat(7, 1fr) — 7 equal columns for 7 days
  - gap creates the gutters; background on the container "fakes" visible grid lines
  - Each cell: grid-column auto-places days correctly
  - named grid areas optionally mark special rows
*/

.cal05__grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-auto-rows: minmax(100px, auto);
  gap: var(--grid-gap);
  background: var(--border);
  /* gap shows through as grid lines */
  border: 1px solid var(--border);
  border-top: none;
}
/* ── Individual date cells ── */

.cal05__cell {
  background: var(--cream);
  padding: 10px 12px 8px;
  cursor: pointer;
  transition: background 0.15s;
  display: flex;
  flex-direction: column;
  gap: 4px;
  position: relative;
  min-height: 100px;
}

.cal05__cell:hover {
  background: rgba(212,168,83,0.08);
}

.cal05__cell--other {
  background: var(--warm);
  opacity: 0.5;
  pointer-events: none;
}

.cal05__cell--weekend {
  background: #f5f0e6;
}

.cal05__cell--today {
  background: #fff9f0;
}

.cal05__cell--today::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: var(--rust);
}

.cal05__cell--selected {
  background: rgba(201,79,44,0.06);
  outline: 2px solid var(--rust);
  outline-offset: -2px;
  z-index: 2;
}
/* Cell number */

.cal05__cell-num {
  font-family: 'Playfair Display', serif;
  font-size: 20px;
  font-weight: 700;
  line-height: 1;
  color: var(--ink);
}

.cal05__cell--today .cal05__cell-num {
  color: var(--rust);
}

.cal05__cell--other .cal05__cell-num {
  color: var(--ink3);
}

.cal05__cell--weekend:not(.cal05__cell--today) .cal05__cell-num {
  color: var(--sage);
}
/* Week number annotation */

.cal05__week-tag {
  position: absolute;
  top: 10px;
  right: 10px;
  font-size: 9px;
  letter-spacing: 0.1em;
  color: var(--ink3);
  opacity: 0.5;
}
/* Events inside cells */

.cal05__cell-events {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin-top: auto;
}

.cal05__event {
  font-size: 10px;
  font-weight: 500;
  padding: 3px 6px;
  border-left: 3px solid transparent;
  letter-spacing: 0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  background: rgba(26,26,46,0.04);
}

.cal05__event--rust {
  border-left-color: var(--rust);
  color: var(--rust);
  background: rgba(201,79,44,0.06);
}

.cal05__event--sage {
  border-left-color: var(--sage);
  color: var(--sage);
  background: rgba(74,124,111,0.08);
}

.cal05__event--sand {
  border-left-color: var(--sand);
  color: #8b6914;
  background: rgba(212,168,83,0.1);
}

.cal05__event--ink {
  border-left-color: var(--ink);
  color: var(--ink2);
}
/* ── Grid annotation panel below ── */

.cal05__annotation {
  margin-top: 20px;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
}

.cal05__ann-cell {
  background: var(--cream);
  padding: 16px 20px;
}

.cal05__ann-label {
  font-size: 9px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--ink3);
  margin-bottom: 6px;
}

.cal05__ann-value {
  font-family: 'Playfair Display', serif;
  font-size: 28px;
  font-weight: 700;
  color: var(--ink);
  line-height: 1;
}

.cal05__ann-sub {
  font-size: 11px;
  color: var(--ink3);
  margin-top: 4px;
}
/* ── Legend ── */

.cal05__legend {
  margin-top: 16px;
  display: flex;
  gap: 20px;
  align-items: center;
  padding: 12px 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}

.cal05__legend-label {
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink3);
  margin-right: 4px;
}

.cal05__legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--ink2);
}

.cal05__legend-swatch {
  width: 16px;
  height: 3px;
  border-radius: 1px;
}

@media (max-width: 640px) {
  .cal05__title {
    font-size: 48px;
  }

  .cal05__masthead {
    grid-template-columns: 1fr;
    gap: 12px;
  }

  .cal05__masthead-right {
    text-align: left;
  }

  .cal05__grid {
    grid-auto-rows: minmax(70px, auto);
  }

  .cal05__cell {
    padding: 6px 8px;
  }

  .cal05__cell-num {
    font-size: 15px;
  }

  .cal05__event {
    display: none;
  }

  .cal05__annotation {
    grid-template-columns: 1fr 1fr;
  }

  .cal05__ann-cell:last-child {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cal05 * {
    animation: none !important;
    transition: none !important;
  }
}
```

## JavaScript
```js
document.querySelectorAll('#cal05Grid .cal05__cell:not(.cal05__cell--other)').forEach(cell => {
  cell.addEventListener('click', function() {
    document.querySelectorAll('#cal05Grid .cal05__cell').forEach(c => c.classList.remove('cal05__cell--selected'));
    this.classList.add('cal05__cell--selected');
  });
});
```

How this works

The textbook CSS Grid calendar. Parent grid sets grid-template-columns:repeat(7, 1fr) for 7 equal-width columns, grid-auto-rows:1fr for equal-height rows, and gap:1px for a hairline divider between cells (backed by a coloured parent background so the gap reads as a line).

Above the grid, a header row uses Flexbox for the month name + prev/next arrows — CSS Grid for the 2D date matrix, Flexbox for the 1D chrome. Modifier classes on individual cells (.other-month, .today, .weekend, .has-event) handle visual state without touching the layout.

The magazine-editorial aesthetic uses a bold display font for the month, subtle body sans for dates, and a warm cream background — reads as premium print layout applied to UI.

Make it yours

  • Change the column count from 7 (weekly) to 5 (business-week only) via grid-template-columns:repeat(5, 1fr).
  • Adjust gap thickness — 1px hairline reads as editorial, 4px reads as chunky/modern.
  • Rebrand the accent via --accent for today / selected cells.
  • Add a status pill for events via a positioned ::after pseudo-element.
  • Swap the display font for a serif (Fraunces, Cormorant) for editorial feel or a mono (JetBrains Mono, Geist Mono) for developer/schedule feel.

Gotchas — read before shipping

  • grid-auto-rows:1fr only creates equal-height rows if the parent has an explicit height — otherwise rows collapse to content. Set height:100% or a specific min-height on the grid.
  • The gap-as-divider trick requires the parent to have background: var(--divider-color) — cells sit on top with their own background, and the gap between them reveals the parent colour.
  • For dynamic calendars, JS generates the 42 cells per month with the correct day numbers, first-day-of-week offset, and modifier classes.
  • CSS Grid is the correct tool for calendars — do NOT reach for Flexbox with flex-basis:calc(100%/7) and wrap; it can't guarantee row alignment when content varies.
  • Ensure role="grid" or role="table" semantics for screen-reader parity if this is an interactive calendar (not just a display).

Browser support

ChromeSafariFirefoxEdge
57+10.1+52+57+

CSS Grid with repeat(), 1fr units, and gap is universally supported since 2017.

Techniques used in this demo

Search CodeFronts

Loading…