16 CSS Two-Column Layouts05 / 16
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
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><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;
}
}.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%. */
/* No JavaScript — repeat(2,1fr) makes two mathematically equal tracks; the seam badge is absolutely positioned at left:50%. */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%. */
```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
gapback 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 movingleftto60%. - The flexbox equivalent is
display:flex+flex:1 1 0on both panels (the explicit0basis is what makes them truly equal). - Swap the hover lift for a background cross-fade by transitioning
background-colorinstead of transform.
Gotchas — read before shipping
- For equal flex columns use
flex:1 1 0, notflex:1alone with content-heavy children — a0basis ignores content size, giving a true 50/50. - Keep the centre badge
pointer-events:noneif it overlaps clickable areas of both panels. - Equal columns ≠ equal text width: cap line length inside each half with
max-width:36chso wide screens stay readable.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 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.