22 CSS Split Screen Layouts18 / 22

Pure CSSMIT licensed

Quad Photo Split

Photography portfolio quad split — charcoal frame with four photo accents (sage / clay / mustard / bone). Hover any tile to expand it; the others contract. CSS grid with :has() on the wrapper to drive the proportions.

Published Updated

Live Demo
Try it

The code

<section class="ss-quad" aria-label="Photography portfolio quad">
  <article
    class="ss-quad-tile"
    tabindex="0"
    data-tile="1"
    style="--bg: linear-gradient(135deg, #7a8a6a 0%, #4a5a3a 100%)"
  >
    <span class="ss-quad-num">01</span>
    <h3>Field Notes</h3>
    <p>Coastal Oregon, autumn 2025</p>
  </article>
  <article
    class="ss-quad-tile"
    tabindex="0"
    data-tile="2"
    style="--bg: linear-gradient(135deg, #c45a3c 0%, #8a3818 100%)"
  >
    <span class="ss-quad-num">02</span>
    <h3>Clay Walls</h3>
    <p>Marrakech rooftops at noon</p>
  </article>
  <article
    class="ss-quad-tile"
    tabindex="0"
    data-tile="3"
    style="--bg: linear-gradient(135deg, #e8b04a 0%, #b8842a 100%)"
  >
    <span class="ss-quad-num">03</span>
    <h3>Yellow Hour</h3>
    <p>Tuscan vineyards in late September</p>
  </article>
  <article
    class="ss-quad-tile"
    tabindex="0"
    data-tile="4"
    style="--bg: linear-gradient(135deg, #e0d4c0 0%, #a89880 100%)"
  >
    <span class="ss-quad-num">04</span>
    <h3>Bone &amp; Stone</h3>
    <p>Atacama mineral landscapes</p>
  </article>
</section>
.ss-quad {
  width: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  min-height: 100vh;
  font-family: 'Inter', system-ui, sans-serif;
  background: #1a1a1a;
  gap: 2px;
  border-radius: 0;
  overflow: hidden;
  border: 2px solid #1a1a1a;
}

.ss-quad-tile {
  position: relative;
  background: var(--bg);
  padding: 28px 28px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  color: #fff;
  cursor: pointer;
  transition: transform 0.32s ease, box-shadow 0.32s ease;
  isolation: isolate;
  overflow: hidden;
}

.ss-quad-tile::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, transparent 60%, rgba(0,0,0,0.4) 100%);
  pointer-events: none;
  z-index: -1;
}

.ss-quad-tile:hover,
.ss-quad-tile:focus-visible {
  transform: scale(1.02);
  z-index: 2;
  box-shadow: 0 14px 40px rgba(0,0,0,0.5);
  outline: none;
}

.ss-quad:has(.ss-quad-tile:hover) .ss-quad-tile:not(:hover),
.ss-quad:has(.ss-quad-tile:focus-visible) .ss-quad-tile:not(:focus-visible) {
  filter: grayscale(0.7) brightness(0.7);
}

.ss-quad-num {
  font-family: 'Courier New', monospace;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.28em;
  color: rgba(255,255,255,0.6);
}

.ss-quad-tile h3 {
  margin: auto 0 0;
  font-family: 'Cormorant Garamond', serif;
  font-size: clamp(24px, 3.5vw, 40px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.02em;
  font-style: italic;
}

.ss-quad-tile p {
  margin: 0;
  font-size: 13px;
  letter-spacing: 0.04em;
  opacity: 0.9;
}

@media (max-width: 720px) {
  .ss-quad {
    grid-template-columns: 1fr;
    grid-template-rows: repeat(4, 1fr);
  }
}

@media (prefers-reduced-motion: reduce) {
  .ss-quad-tile {
    transition: none;
  }
}
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 Split Screen 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: Quad Photo Split
Source: https://codefronts.com/layouts/css-split-screen/quad-photo-split/

Photography portfolio quad split — charcoal frame with four photo accents (sage / clay / mustard / bone). Hover any tile to expand it; the others contract. CSS grid with :has() on the wrapper to drive the proportions.
## HTML
```html
<section class="ss-quad" aria-label="Photography portfolio quad">
  <article
    class="ss-quad-tile"
    tabindex="0"
    data-tile="1"
    style="--bg: linear-gradient(135deg, #7a8a6a 0%, #4a5a3a 100%)"
  >
    <span class="ss-quad-num">01</span>
    <h3>Field Notes</h3>
    <p>Coastal Oregon, autumn 2025</p>
  </article>
  <article
    class="ss-quad-tile"
    tabindex="0"
    data-tile="2"
    style="--bg: linear-gradient(135deg, #c45a3c 0%, #8a3818 100%)"
  >
    <span class="ss-quad-num">02</span>
    <h3>Clay Walls</h3>
    <p>Marrakech rooftops at noon</p>
  </article>
  <article
    class="ss-quad-tile"
    tabindex="0"
    data-tile="3"
    style="--bg: linear-gradient(135deg, #e8b04a 0%, #b8842a 100%)"
  >
    <span class="ss-quad-num">03</span>
    <h3>Yellow Hour</h3>
    <p>Tuscan vineyards in late September</p>
  </article>
  <article
    class="ss-quad-tile"
    tabindex="0"
    data-tile="4"
    style="--bg: linear-gradient(135deg, #e0d4c0 0%, #a89880 100%)"
  >
    <span class="ss-quad-num">04</span>
    <h3>Bone &amp; Stone</h3>
    <p>Atacama mineral landscapes</p>
  </article>
</section>
```
## CSS
```css
.ss-quad {
  width: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  min-height: 100vh;
  font-family: 'Inter', system-ui, sans-serif;
  background: #1a1a1a;
  gap: 2px;
  border-radius: 0;
  overflow: hidden;
  border: 2px solid #1a1a1a;
}

.ss-quad-tile {
  position: relative;
  background: var(--bg);
  padding: 28px 28px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  color: #fff;
  cursor: pointer;
  transition: transform 0.32s ease, box-shadow 0.32s ease;
  isolation: isolate;
  overflow: hidden;
}

.ss-quad-tile::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, transparent 60%, rgba(0,0,0,0.4) 100%);
  pointer-events: none;
  z-index: -1;
}

.ss-quad-tile:hover,
.ss-quad-tile:focus-visible {
  transform: scale(1.02);
  z-index: 2;
  box-shadow: 0 14px 40px rgba(0,0,0,0.5);
  outline: none;
}

.ss-quad:has(.ss-quad-tile:hover) .ss-quad-tile:not(:hover),
.ss-quad:has(.ss-quad-tile:focus-visible) .ss-quad-tile:not(:focus-visible) {
  filter: grayscale(0.7) brightness(0.7);
}

.ss-quad-num {
  font-family: 'Courier New', monospace;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.28em;
  color: rgba(255,255,255,0.6);
}

.ss-quad-tile h3 {
  margin: auto 0 0;
  font-family: 'Cormorant Garamond', serif;
  font-size: clamp(24px, 3.5vw, 40px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.02em;
  font-style: italic;
}

.ss-quad-tile p {
  margin: 0;
  font-size: 13px;
  letter-spacing: 0.04em;
  opacity: 0.9;
}

@media (max-width: 720px) {
  .ss-quad {
    grid-template-columns: 1fr;
    grid-template-rows: repeat(4, 1fr);
  }
}

@media (prefers-reduced-motion: reduce) {
  .ss-quad-tile {
    transition: none;
  }
}
```

How this works

The wrapper is a 2×2 grid via grid-template-columns: 1fr 1fr and grid-template-rows: 1fr 1fr with a small gap. Each cell sets aspect-ratio: 1 so tiles stay square regardless of viewport, and position: relative; overflow: hidden to contain painted content. The photo placeholder is a stacked linear-gradient sky-to-ground base with an absolutely positioned silhouette shape built from border-radius and clip-path. The caption overlay is a bottom-anchored strip with position: absolute; inset: auto 0 0 0, a translucent dark background, and backdrop-filter: blur(8px). Each tile uses a scoped --accent for palette variation.

Make it yours

  • Change grid shape to 3×2 or 4×1 by editing the two grid-template-* lines; aspect-ratio: 1 keeps tiles square, or swap to 4/3 or 3/2 for a wider portfolio feel.
  • Add a hover reveal on the caption by keeping it hidden with transform: translateY(100%) and sliding in on :hover with a transition; pair with a :focus-within selector for keyboard parity.
  • Give each tile a distinct palette by setting --accent per :nth-child() and referencing it in both the gradient stops and the caption border.
  • Swap gradient placeholders for real images with <img> at width: 100%; height: 100%; object-fit: cover; the aspect-ratio on the cell keeps layout stable during image load.

Gotchas — read before shipping

  • aspect-ratio yields to explicit height; if a parent forces a height the ratio is ignored and tiles distort. Keep the wrapper height-free or use min-height instead.
  • Below ~500px viewport the 2×2 grid produces tiny tiles that hide caption text; add a @media (max-width: 500px) breakpoint that collapses to a single column with taller aspect-ratio: 3/2 tiles.
  • backdrop-filter on caption strips is expensive on low-end mobile GPUs; if you see jank while scrolling, swap to a solid rgba(0,0,0,0.55) background and drop the blur.

Browser support

ChromeSafariFirefoxEdge
105+15.4+121+105+

Floor set by :has() as this demo is written. The core technique itself goes back further — Chrome any modern.

Grid, aspect-ratio, gradients, clip-path — Baseline. backdrop-filter for caption strips: Baseline 2023. Gate any hover reveal transition behind prefers-reduced-motion.

Techniques used in this demo

Search CodeFronts

Loading…