16 CSS Two-Column Layouts05 / 16

Pure CSSMIT licensed

CSS Two Column Layout 50 50

A perfect 50 50 split layout with repeat(2, 1fr) — two equal halves meeting at a crisp centre seam, styled as a comparison landing ("Design" vs "Engineer") with mirrored panels, contrasting themes and hover states. The go-to pattern for comparisons, dual CTAs and split cards.

Published

Live Demo
Try it

The code

<section class="tcl-05" aria-label="50 50 split two column layout demo">
  <div class="tcl-05__split">
    <a class="tcl-05__half tcl-05__half--light" href="#design">
      <span class="tcl-05__num">50%</span>
      <h2>Design</h2>
      <p>Tokens, type scales and motion specs — explore the visual system behind the product.</p>
      <span class="tcl-05__go">Explore design →</span>
    </a>
    <span class="tcl-05__seam" aria-hidden="true">repeat(2, 1fr)</span>
    <a class="tcl-05__half tcl-05__half--dark" href="#engineering">
      <span class="tcl-05__num">50%</span>
      <h2>Engineer</h2>
      <p>Components, APIs and performance budgets — see how the system ships to production.</p>
      <span class="tcl-05__go">Explore engineering →</span>
    </a>
  </div>
</section>
.tcl-05,
.tcl-05 *,
.tcl-05 *::before,
.tcl-05 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.tcl-05 {
  width: 100%;
  min-height: 100vh;
  --warm: oklch(0.68 0.15 60);
  --cool: oklch(0.68 0.14 250);
  background: linear-gradient(90deg,oklch(0.96 0.03 60) 50%,oklch(0.96 0.03 250) 50%);
  font-family: 'Segoe UI',system-ui,sans-serif;
}

.tcl-05__split {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2,1fr);
  min-height: 460px;
}

.tcl-05__half {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 14px;
  padding: clamp(28px,5vw,64px);
  text-decoration: none;
  overflow: hidden;
  transition: transform .3s cubic-bezier(.2,.9,.2,1);
}

.tcl-05__half h2 {
  font-size: clamp(30px,4.5vw,52px);
  letter-spacing: -.03em;
  line-height: 1;
}

.tcl-05__half p {
  font-size: 14.5px;
  line-height: 1.6;
  max-width: 36ch;
  text-wrap: pretty;
}

.tcl-05__num {
  font: 700 clamp(64px,9vw,120px)/1 inherit;
  letter-spacing: -.05em;
  opacity: .1;
  position: absolute;
  top: 12px;
  right: 20px;
  pointer-events: none;
}

.tcl-05__go {
  font: 600 14px/1 inherit;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
  transition: gap .2s;
}

.tcl-05__half:hover .tcl-05__go {
  gap: 12px;
}

.tcl-05__half:hover {
  transform: translateY(-4px);
}

.tcl-05__half:focus-visible {
  outline: 3px solid currentColor;
  outline-offset: -6px;
}

.tcl-05__half--light {
  background: linear-gradient(160deg,oklch(0.96 0.02 70),oklch(0.9 0.06 60));
  color: oklch(0.3 0.06 50);
}

.tcl-05__half--light .tcl-05__go {
  color: oklch(0.5 0.14 45);
}

.tcl-05__half--dark {
  background: linear-gradient(200deg,oklch(0.28 0.05 260),oklch(0.2 0.04 265));
  color: oklch(0.93 0.02 250);
}

.tcl-05__half--dark .tcl-05__go {
  color: var(--cool);
}

.tcl-05__seam {
  position: absolute;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  z-index: 2;
  font: 600 11px/1 ui-monospace,monospace;
  background: #fff;
  color: oklch(0.35 0.03 260);
  border: 1px solid oklch(0.85 0.02 260);
  border-radius: 99px;
  padding: 8px 14px;
  box-shadow: 0 8px 20px -8px rgba(0,0,0,.35);
  pointer-events: none;
  white-space: nowrap;
}

@media (max-width: 700px) {
  .tcl-05__split {
    grid-template-columns: 1fr;
  }

  .tcl-05__half {
    min-height: 230px;
  }

  .tcl-05__seam {
    top: 50%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .tcl-05__half {
    transition: none;
  }
}
/* No JavaScript — repeat(2,1fr) makes two mathematically equal tracks; the seam badge is absolutely positioned at left:50%. */
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 Two-Column 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 Two Column Layout 50 50
Source: https://codefronts.com/layouts/css-two-column-layout/css-two-column-layout-50-50/

A perfect 50 50 split layout with repeat(2, 1fr) — two equal halves meeting at a crisp centre seam, styled as a comparison landing ("Design" vs "Engineer") with mirrored panels, contrasting themes and hover states. The go-to pattern for comparisons, dual CTAs and split cards.
## HTML
```html
<section class="tcl-05" aria-label="50 50 split two column layout demo">
  <div class="tcl-05__split">
    <a class="tcl-05__half tcl-05__half--light" href="#design">
      <span class="tcl-05__num">50%</span>
      <h2>Design</h2>
      <p>Tokens, type scales and motion specs — explore the visual system behind the product.</p>
      <span class="tcl-05__go">Explore design →</span>
    </a>
    <span class="tcl-05__seam" aria-hidden="true">repeat(2, 1fr)</span>
    <a class="tcl-05__half tcl-05__half--dark" href="#engineering">
      <span class="tcl-05__num">50%</span>
      <h2>Engineer</h2>
      <p>Components, APIs and performance budgets — see how the system ships to production.</p>
      <span class="tcl-05__go">Explore engineering →</span>
    </a>
  </div>
</section>
```
## CSS
```css
.tcl-05,
.tcl-05 *,
.tcl-05 *::before,
.tcl-05 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.tcl-05 {
  width: 100%;
  min-height: 100vh;
  --warm: oklch(0.68 0.15 60);
  --cool: oklch(0.68 0.14 250);
  background: linear-gradient(90deg,oklch(0.96 0.03 60) 50%,oklch(0.96 0.03 250) 50%);
  font-family: 'Segoe UI',system-ui,sans-serif;
}

.tcl-05__split {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2,1fr);
  min-height: 460px;
}

.tcl-05__half {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 14px;
  padding: clamp(28px,5vw,64px);
  text-decoration: none;
  overflow: hidden;
  transition: transform .3s cubic-bezier(.2,.9,.2,1);
}

.tcl-05__half h2 {
  font-size: clamp(30px,4.5vw,52px);
  letter-spacing: -.03em;
  line-height: 1;
}

.tcl-05__half p {
  font-size: 14.5px;
  line-height: 1.6;
  max-width: 36ch;
  text-wrap: pretty;
}

.tcl-05__num {
  font: 700 clamp(64px,9vw,120px)/1 inherit;
  letter-spacing: -.05em;
  opacity: .1;
  position: absolute;
  top: 12px;
  right: 20px;
  pointer-events: none;
}

.tcl-05__go {
  font: 600 14px/1 inherit;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
  transition: gap .2s;
}

.tcl-05__half:hover .tcl-05__go {
  gap: 12px;
}

.tcl-05__half:hover {
  transform: translateY(-4px);
}

.tcl-05__half:focus-visible {
  outline: 3px solid currentColor;
  outline-offset: -6px;
}

.tcl-05__half--light {
  background: linear-gradient(160deg,oklch(0.96 0.02 70),oklch(0.9 0.06 60));
  color: oklch(0.3 0.06 50);
}

.tcl-05__half--light .tcl-05__go {
  color: oklch(0.5 0.14 45);
}

.tcl-05__half--dark {
  background: linear-gradient(200deg,oklch(0.28 0.05 260),oklch(0.2 0.04 265));
  color: oklch(0.93 0.02 250);
}

.tcl-05__half--dark .tcl-05__go {
  color: var(--cool);
}

.tcl-05__seam {
  position: absolute;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  z-index: 2;
  font: 600 11px/1 ui-monospace,monospace;
  background: #fff;
  color: oklch(0.35 0.03 260);
  border: 1px solid oklch(0.85 0.02 260);
  border-radius: 99px;
  padding: 8px 14px;
  box-shadow: 0 8px 20px -8px rgba(0,0,0,.35);
  pointer-events: none;
  white-space: nowrap;
}

@media (max-width: 700px) {
  .tcl-05__split {
    grid-template-columns: 1fr;
  }

  .tcl-05__half {
    min-height: 230px;
  }

  .tcl-05__seam {
    top: 50%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .tcl-05__half {
    transition: none;
  }
}
```

## JavaScript
```js
/* No JavaScript — repeat(2,1fr) makes two mathematically equal tracks; the seam badge is absolutely positioned at left:50%. */
```

How this works

grid-template-columns:repeat(2,1fr) guarantees a mathematically equal split — both tracks receive identical shares of free space regardless of content, which percentages + borders never quite achieved. Here gap:0 lets the two themed panels butt together into a single seam, and a centred badge sits on the divider with position:absolute; left:50%.

Each half is its own self-contained theme (light vs dark) sharing one internal layout, so the symmetry reads instantly. On hover a panel’s background lifts subtly — transform/opacity only, so it stays compositor-friendly. Under 700px the halves stack and the seam badge tucks between them.

Make it yours

  • Want breathing room between halves? Add gap back and round the outer corners of each panel.
  • Turn it into a 60/40 comparison with grid-template-columns:3fr 2fr — the seam badge still centres by moving left to 60%.
  • The flexbox equivalent is display:flex + flex:1 1 0 on both panels (the explicit 0 basis is what makes them truly equal).
  • Swap the hover lift for a background cross-fade by transitioning background-color instead of transform.

Gotchas — read before shipping

  • For equal flex columns use flex:1 1 0, not flex:1 alone with content-heavy children — a 0 basis ignores content size, giving a true 50/50.
  • Keep the centre badge pointer-events:none if it overlaps clickable areas of both panels.
  • Equal columns ≠ equal text width: cap line length inside each half with max-width:36ch so wide screens stay readable.

Browser support

ChromeSafariFirefoxEdge
114+17.5+121+114+

Floor set by oklch(), text-wrap as this demo is written. The core technique itself goes back further — Chrome 57+.

repeat() with fr units is baseline grid; every effect here (transform hover, clamp type) is equally universal.

Techniques used in this demo

Search CodeFronts

Loading…