15 CSS Card Grid Layouts02 / 15
CSS Hero Photo Collage Grid
A landing-page hero with a 5-tile asymmetric photo collage on the right and a marketing headline + CTA on the left — the exact pattern Airbnb, Notion, and Linear use to combine narrative copy with visual proof on their homepage hero. Photos are CSS gradient placeholders with location labels and category pills.
Published
The code
<div class="cg-12">
<div class="cg-12__inner">
<div class="cg-12__copy">
<span class="cg-12__kicker">New · 2026 collection</span>
<h2 class="cg-12__title">Stay places that<br><em>feel like home.</em></h2>
<p class="cg-12__lede">Hand-picked stays in 47 cities. Verified by humans. Booked by people who care where they sleep.</p>
<div class="cg-12__actions">
<a href="#" class="cg-12__cta">Browse stays →</a>
<a href="#" class="cg-12__link">How it works</a>
</div>
<div class="cg-12__metrics">
<div><strong>4.9 ★</strong><span>Avg rating</span></div>
<div><strong>12K+</strong><span>Verified stays</span></div>
<div><strong>47</strong><span>Cities</span></div>
</div>
</div>
<div class="cg-12__collage">
<div class="cg-12__photo cg-12__photo--1">
<span class="cg-12__pill">Iceland</span>
<span class="cg-12__label">Black Sand Cabin</span>
</div>
<div class="cg-12__photo cg-12__photo--2">
<span class="cg-12__pill">Tokyo</span>
<span class="cg-12__label">Shibuya Loft</span>
</div>
<div class="cg-12__photo cg-12__photo--3">
<span class="cg-12__pill">Lisbon</span>
<span class="cg-12__label">Alfama Studio</span>
</div>
<div class="cg-12__photo cg-12__photo--4">
<span class="cg-12__pill">Marrakech</span>
<span class="cg-12__label">Medina Riad</span>
</div>
<div class="cg-12__photo cg-12__photo--5">
<span class="cg-12__pill">Brooklyn</span>
<span class="cg-12__label">Williamsburg Flat</span>
</div>
</div>
</div>
</div><div class="cg-12">
<div class="cg-12__inner">
<div class="cg-12__copy">
<span class="cg-12__kicker">New · 2026 collection</span>
<h2 class="cg-12__title">Stay places that<br><em>feel like home.</em></h2>
<p class="cg-12__lede">Hand-picked stays in 47 cities. Verified by humans. Booked by people who care where they sleep.</p>
<div class="cg-12__actions">
<a href="#" class="cg-12__cta">Browse stays →</a>
<a href="#" class="cg-12__link">How it works</a>
</div>
<div class="cg-12__metrics">
<div><strong>4.9 ★</strong><span>Avg rating</span></div>
<div><strong>12K+</strong><span>Verified stays</span></div>
<div><strong>47</strong><span>Cities</span></div>
</div>
</div>
<div class="cg-12__collage">
<div class="cg-12__photo cg-12__photo--1">
<span class="cg-12__pill">Iceland</span>
<span class="cg-12__label">Black Sand Cabin</span>
</div>
<div class="cg-12__photo cg-12__photo--2">
<span class="cg-12__pill">Tokyo</span>
<span class="cg-12__label">Shibuya Loft</span>
</div>
<div class="cg-12__photo cg-12__photo--3">
<span class="cg-12__pill">Lisbon</span>
<span class="cg-12__label">Alfama Studio</span>
</div>
<div class="cg-12__photo cg-12__photo--4">
<span class="cg-12__pill">Marrakech</span>
<span class="cg-12__label">Medina Riad</span>
</div>
<div class="cg-12__photo cg-12__photo--5">
<span class="cg-12__pill">Brooklyn</span>
<span class="cg-12__label">Williamsburg Flat</span>
</div>
</div>
</div>
</div>.cg-12,
.cg-12 *,
.cg-12 *::before,
.cg-12 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cg-12 ::selection {
background: #0f172a;
color: #fff;
}
.cg-12 {
--bg: #fafaf7;
--ink: #0f172a;
--muted: #64748b;
--accent: #dc2626;
--line: #e2e8f0;
min-height: 100vh;
background: var(--bg);
padding: clamp(28px,4vw,56px) clamp(20px,3vw,48px);
font-family: -apple-system,BlinkMacSystemFont,"Inter","Segoe UI",sans-serif;
color: var(--ink);
display: flex;
align-items: center;
justify-content: center;
}
.cg-12__inner {
width: 100%;
max-width: 1200px;
display: grid;
grid-template-columns: 1fr 1.2fr;
gap: clamp(24px,3.4vw,56px);
align-items: center;
}
.cg-12__copy {
display: flex;
flex-direction: column;
gap: 18px;
max-width: 520px;
}
.cg-12__kicker {
display: inline-block;
width: fit-content;
font-size: .72rem;
font-weight: 700;
letter-spacing: .16em;
text-transform: uppercase;
color: var(--accent);
padding: 5px 12px;
border-radius: 999px;
background: rgba(220,38,38,.1);
}
.cg-12__title {
font-size: clamp(2.2rem,4.5vw,3.6rem);
font-weight: 900;
letter-spacing: -.03em;
line-height: 1.02;
}
.cg-12__title em {
font-style: italic;
color: var(--accent);
font-family: Georgia,"Times New Roman",serif;
font-weight: 700;
}
.cg-12__lede {
font-size: clamp(.96rem,1.2vw,1.1rem);
color: var(--muted);
line-height: 1.55;
max-width: 46ch;
}
.cg-12__actions {
display: flex;
align-items: center;
gap: 16px;
flex-wrap: wrap;
margin-top: 6px;
}
.cg-12__cta {
display: inline-block;
background: var(--ink);
color: #fff;
padding: 14px 22px;
border-radius: 10px;
font-weight: 700;
font-size: .96rem;
text-decoration: none;
transition: transform .2s,background .2s;
}
.cg-12__cta:hover {
background: var(--accent);
transform: translateY(-2px);
}
.cg-12__link {
font-size: .94rem;
font-weight: 600;
color: var(--ink);
text-decoration: none;
position: relative;
}
.cg-12__link::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: -3px;
height: 1.5px;
background: currentColor;
}
.cg-12__metrics {
display: flex;
gap: clamp(20px,3vw,40px);
margin-top: 16px;
padding-top: 24px;
border-top: 1px solid var(--line);
}
.cg-12__metrics > div {
display: flex;
flex-direction: column;
gap: 2px;
}
.cg-12__metrics strong {
font-size: 1.5rem;
font-weight: 900;
letter-spacing: -.02em;
}
.cg-12__metrics span {
font-size: .78rem;
color: var(--muted);
font-weight: 600;
}
/* Collage */
.cg-12__collage {
display: grid;
grid-template-columns: repeat(3,1fr);
grid-template-rows: repeat(3,1fr);
gap: clamp(8px,1vw,14px);
aspect-ratio: 1.05/1;
min-height: clamp(320px,42vw,560px);
}
.cg-12__photo {
position: relative;
border-radius: 14px;
overflow: hidden;
display: flex;
align-items: flex-end;
padding: 12px;
isolation: isolate;
}
.cg-12__photo::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(180deg,transparent 45%,rgba(0,0,0,.55));
z-index: 0;
}
.cg-12__pill {
position: absolute;
top: 10px;
right: 10px;
background: rgba(255,255,255,.92);
color: var(--ink);
font-size: .62rem;
font-weight: 700;
letter-spacing: .1em;
text-transform: uppercase;
padding: 4px 9px;
border-radius: 999px;
backdrop-filter: blur(8px);
z-index: 2;
}
.cg-12__label {
position: relative;
z-index: 1;
color: #fff;
font-size: .86rem;
font-weight: 700;
letter-spacing: -.005em;
text-shadow: 0 1px 3px rgba(0,0,0,.4);
}
.cg-12__photo--1 {
grid-column: 1 / span 2;
grid-row: 1 / span 2;
background: linear-gradient(135deg,#1e3a5f,#0f1c2e);
}
.cg-12__photo--2 {
grid-column: 3 / span 1;
grid-row: 1 / span 1;
background: linear-gradient(135deg,#d97a99,#7a3855);
}
.cg-12__photo--3 {
grid-column: 3 / span 1;
grid-row: 2 / span 1;
background: linear-gradient(135deg,#f4a572,#d97f4f);
}
.cg-12__photo--4 {
grid-column: 1 / span 1;
grid-row: 3 / span 1;
background: linear-gradient(135deg,#e6c54a,#a8732d);
}
.cg-12__photo--5 {
grid-column: 2 / span 2;
grid-row: 3 / span 1;
background: linear-gradient(135deg,#7aa852,#3d6a2a);
}
@media (max-width: 900px) {
.cg-12__inner {
grid-template-columns: 1fr;
gap: 32px;
}
.cg-12__copy {
max-width: none;
text-align: center;
align-items: center;
}
.cg-12__kicker {
margin: 0 auto 0 0;
}
.cg-12__collage {
aspect-ratio: 1.4/1;
min-height: 280px;
}
}
@media (max-width: 560px) {
.cg-12__metrics {
gap: 14px;
}
.cg-12__metrics strong {
font-size: 1.25rem;
}
.cg-12__collage {
aspect-ratio: 1/1;
}
}
@media (prefers-reduced-motion: reduce) {
.cg-12__cta {
transition: none;
}
}.cg-12,
.cg-12 *,
.cg-12 *::before,
.cg-12 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cg-12 ::selection {
background: #0f172a;
color: #fff;
}
.cg-12 {
--bg: #fafaf7;
--ink: #0f172a;
--muted: #64748b;
--accent: #dc2626;
--line: #e2e8f0;
min-height: 100vh;
background: var(--bg);
padding: clamp(28px,4vw,56px) clamp(20px,3vw,48px);
font-family: -apple-system,BlinkMacSystemFont,"Inter","Segoe UI",sans-serif;
color: var(--ink);
display: flex;
align-items: center;
justify-content: center;
}
.cg-12__inner {
width: 100%;
max-width: 1200px;
display: grid;
grid-template-columns: 1fr 1.2fr;
gap: clamp(24px,3.4vw,56px);
align-items: center;
}
.cg-12__copy {
display: flex;
flex-direction: column;
gap: 18px;
max-width: 520px;
}
.cg-12__kicker {
display: inline-block;
width: fit-content;
font-size: .72rem;
font-weight: 700;
letter-spacing: .16em;
text-transform: uppercase;
color: var(--accent);
padding: 5px 12px;
border-radius: 999px;
background: rgba(220,38,38,.1);
}
.cg-12__title {
font-size: clamp(2.2rem,4.5vw,3.6rem);
font-weight: 900;
letter-spacing: -.03em;
line-height: 1.02;
}
.cg-12__title em {
font-style: italic;
color: var(--accent);
font-family: Georgia,"Times New Roman",serif;
font-weight: 700;
}
.cg-12__lede {
font-size: clamp(.96rem,1.2vw,1.1rem);
color: var(--muted);
line-height: 1.55;
max-width: 46ch;
}
.cg-12__actions {
display: flex;
align-items: center;
gap: 16px;
flex-wrap: wrap;
margin-top: 6px;
}
.cg-12__cta {
display: inline-block;
background: var(--ink);
color: #fff;
padding: 14px 22px;
border-radius: 10px;
font-weight: 700;
font-size: .96rem;
text-decoration: none;
transition: transform .2s,background .2s;
}
.cg-12__cta:hover {
background: var(--accent);
transform: translateY(-2px);
}
.cg-12__link {
font-size: .94rem;
font-weight: 600;
color: var(--ink);
text-decoration: none;
position: relative;
}
.cg-12__link::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: -3px;
height: 1.5px;
background: currentColor;
}
.cg-12__metrics {
display: flex;
gap: clamp(20px,3vw,40px);
margin-top: 16px;
padding-top: 24px;
border-top: 1px solid var(--line);
}
.cg-12__metrics > div {
display: flex;
flex-direction: column;
gap: 2px;
}
.cg-12__metrics strong {
font-size: 1.5rem;
font-weight: 900;
letter-spacing: -.02em;
}
.cg-12__metrics span {
font-size: .78rem;
color: var(--muted);
font-weight: 600;
}
/* Collage */
.cg-12__collage {
display: grid;
grid-template-columns: repeat(3,1fr);
grid-template-rows: repeat(3,1fr);
gap: clamp(8px,1vw,14px);
aspect-ratio: 1.05/1;
min-height: clamp(320px,42vw,560px);
}
.cg-12__photo {
position: relative;
border-radius: 14px;
overflow: hidden;
display: flex;
align-items: flex-end;
padding: 12px;
isolation: isolate;
}
.cg-12__photo::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(180deg,transparent 45%,rgba(0,0,0,.55));
z-index: 0;
}
.cg-12__pill {
position: absolute;
top: 10px;
right: 10px;
background: rgba(255,255,255,.92);
color: var(--ink);
font-size: .62rem;
font-weight: 700;
letter-spacing: .1em;
text-transform: uppercase;
padding: 4px 9px;
border-radius: 999px;
backdrop-filter: blur(8px);
z-index: 2;
}
.cg-12__label {
position: relative;
z-index: 1;
color: #fff;
font-size: .86rem;
font-weight: 700;
letter-spacing: -.005em;
text-shadow: 0 1px 3px rgba(0,0,0,.4);
}
.cg-12__photo--1 {
grid-column: 1 / span 2;
grid-row: 1 / span 2;
background: linear-gradient(135deg,#1e3a5f,#0f1c2e);
}
.cg-12__photo--2 {
grid-column: 3 / span 1;
grid-row: 1 / span 1;
background: linear-gradient(135deg,#d97a99,#7a3855);
}
.cg-12__photo--3 {
grid-column: 3 / span 1;
grid-row: 2 / span 1;
background: linear-gradient(135deg,#f4a572,#d97f4f);
}
.cg-12__photo--4 {
grid-column: 1 / span 1;
grid-row: 3 / span 1;
background: linear-gradient(135deg,#e6c54a,#a8732d);
}
.cg-12__photo--5 {
grid-column: 2 / span 2;
grid-row: 3 / span 1;
background: linear-gradient(135deg,#7aa852,#3d6a2a);
}
@media (max-width: 900px) {
.cg-12__inner {
grid-template-columns: 1fr;
gap: 32px;
}
.cg-12__copy {
max-width: none;
text-align: center;
align-items: center;
}
.cg-12__kicker {
margin: 0 auto 0 0;
}
.cg-12__collage {
aspect-ratio: 1.4/1;
min-height: 280px;
}
}
@media (max-width: 560px) {
.cg-12__metrics {
gap: 14px;
}
.cg-12__metrics strong {
font-size: 1.25rem;
}
.cg-12__collage {
aspect-ratio: 1/1;
}
}
@media (prefers-reduced-motion: reduce) {
.cg-12__cta {
transition: none;
}
}Here's a working CSS Card Grid 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 Hero Photo Collage Grid
Source: https://codefronts.com/layouts/css-card-grid-layout/css-hero-photo-collage-grid/
A landing-page hero with a 5-tile asymmetric photo collage on the right and a marketing headline + CTA on the left — the exact pattern Airbnb, Notion, and Linear use to combine narrative copy with visual proof on their homepage hero. Photos are CSS gradient placeholders with location labels and category pills.
## HTML
```html
<div class="cg-12">
<div class="cg-12__inner">
<div class="cg-12__copy">
<span class="cg-12__kicker">New · 2026 collection</span>
<h2 class="cg-12__title">Stay places that<br><em>feel like home.</em></h2>
<p class="cg-12__lede">Hand-picked stays in 47 cities. Verified by humans. Booked by people who care where they sleep.</p>
<div class="cg-12__actions">
<a href="#" class="cg-12__cta">Browse stays →</a>
<a href="#" class="cg-12__link">How it works</a>
</div>
<div class="cg-12__metrics">
<div><strong>4.9 ★</strong><span>Avg rating</span></div>
<div><strong>12K+</strong><span>Verified stays</span></div>
<div><strong>47</strong><span>Cities</span></div>
</div>
</div>
<div class="cg-12__collage">
<div class="cg-12__photo cg-12__photo--1">
<span class="cg-12__pill">Iceland</span>
<span class="cg-12__label">Black Sand Cabin</span>
</div>
<div class="cg-12__photo cg-12__photo--2">
<span class="cg-12__pill">Tokyo</span>
<span class="cg-12__label">Shibuya Loft</span>
</div>
<div class="cg-12__photo cg-12__photo--3">
<span class="cg-12__pill">Lisbon</span>
<span class="cg-12__label">Alfama Studio</span>
</div>
<div class="cg-12__photo cg-12__photo--4">
<span class="cg-12__pill">Marrakech</span>
<span class="cg-12__label">Medina Riad</span>
</div>
<div class="cg-12__photo cg-12__photo--5">
<span class="cg-12__pill">Brooklyn</span>
<span class="cg-12__label">Williamsburg Flat</span>
</div>
</div>
</div>
</div>
```
## CSS
```css
.cg-12,
.cg-12 *,
.cg-12 *::before,
.cg-12 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cg-12 ::selection {
background: #0f172a;
color: #fff;
}
.cg-12 {
--bg: #fafaf7;
--ink: #0f172a;
--muted: #64748b;
--accent: #dc2626;
--line: #e2e8f0;
min-height: 100vh;
background: var(--bg);
padding: clamp(28px,4vw,56px) clamp(20px,3vw,48px);
font-family: -apple-system,BlinkMacSystemFont,"Inter","Segoe UI",sans-serif;
color: var(--ink);
display: flex;
align-items: center;
justify-content: center;
}
.cg-12__inner {
width: 100%;
max-width: 1200px;
display: grid;
grid-template-columns: 1fr 1.2fr;
gap: clamp(24px,3.4vw,56px);
align-items: center;
}
.cg-12__copy {
display: flex;
flex-direction: column;
gap: 18px;
max-width: 520px;
}
.cg-12__kicker {
display: inline-block;
width: fit-content;
font-size: .72rem;
font-weight: 700;
letter-spacing: .16em;
text-transform: uppercase;
color: var(--accent);
padding: 5px 12px;
border-radius: 999px;
background: rgba(220,38,38,.1);
}
.cg-12__title {
font-size: clamp(2.2rem,4.5vw,3.6rem);
font-weight: 900;
letter-spacing: -.03em;
line-height: 1.02;
}
.cg-12__title em {
font-style: italic;
color: var(--accent);
font-family: Georgia,"Times New Roman",serif;
font-weight: 700;
}
.cg-12__lede {
font-size: clamp(.96rem,1.2vw,1.1rem);
color: var(--muted);
line-height: 1.55;
max-width: 46ch;
}
.cg-12__actions {
display: flex;
align-items: center;
gap: 16px;
flex-wrap: wrap;
margin-top: 6px;
}
.cg-12__cta {
display: inline-block;
background: var(--ink);
color: #fff;
padding: 14px 22px;
border-radius: 10px;
font-weight: 700;
font-size: .96rem;
text-decoration: none;
transition: transform .2s,background .2s;
}
.cg-12__cta:hover {
background: var(--accent);
transform: translateY(-2px);
}
.cg-12__link {
font-size: .94rem;
font-weight: 600;
color: var(--ink);
text-decoration: none;
position: relative;
}
.cg-12__link::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: -3px;
height: 1.5px;
background: currentColor;
}
.cg-12__metrics {
display: flex;
gap: clamp(20px,3vw,40px);
margin-top: 16px;
padding-top: 24px;
border-top: 1px solid var(--line);
}
.cg-12__metrics > div {
display: flex;
flex-direction: column;
gap: 2px;
}
.cg-12__metrics strong {
font-size: 1.5rem;
font-weight: 900;
letter-spacing: -.02em;
}
.cg-12__metrics span {
font-size: .78rem;
color: var(--muted);
font-weight: 600;
}
/* Collage */
.cg-12__collage {
display: grid;
grid-template-columns: repeat(3,1fr);
grid-template-rows: repeat(3,1fr);
gap: clamp(8px,1vw,14px);
aspect-ratio: 1.05/1;
min-height: clamp(320px,42vw,560px);
}
.cg-12__photo {
position: relative;
border-radius: 14px;
overflow: hidden;
display: flex;
align-items: flex-end;
padding: 12px;
isolation: isolate;
}
.cg-12__photo::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(180deg,transparent 45%,rgba(0,0,0,.55));
z-index: 0;
}
.cg-12__pill {
position: absolute;
top: 10px;
right: 10px;
background: rgba(255,255,255,.92);
color: var(--ink);
font-size: .62rem;
font-weight: 700;
letter-spacing: .1em;
text-transform: uppercase;
padding: 4px 9px;
border-radius: 999px;
backdrop-filter: blur(8px);
z-index: 2;
}
.cg-12__label {
position: relative;
z-index: 1;
color: #fff;
font-size: .86rem;
font-weight: 700;
letter-spacing: -.005em;
text-shadow: 0 1px 3px rgba(0,0,0,.4);
}
.cg-12__photo--1 {
grid-column: 1 / span 2;
grid-row: 1 / span 2;
background: linear-gradient(135deg,#1e3a5f,#0f1c2e);
}
.cg-12__photo--2 {
grid-column: 3 / span 1;
grid-row: 1 / span 1;
background: linear-gradient(135deg,#d97a99,#7a3855);
}
.cg-12__photo--3 {
grid-column: 3 / span 1;
grid-row: 2 / span 1;
background: linear-gradient(135deg,#f4a572,#d97f4f);
}
.cg-12__photo--4 {
grid-column: 1 / span 1;
grid-row: 3 / span 1;
background: linear-gradient(135deg,#e6c54a,#a8732d);
}
.cg-12__photo--5 {
grid-column: 2 / span 2;
grid-row: 3 / span 1;
background: linear-gradient(135deg,#7aa852,#3d6a2a);
}
@media (max-width: 900px) {
.cg-12__inner {
grid-template-columns: 1fr;
gap: 32px;
}
.cg-12__copy {
max-width: none;
text-align: center;
align-items: center;
}
.cg-12__kicker {
margin: 0 auto 0 0;
}
.cg-12__collage {
aspect-ratio: 1.4/1;
min-height: 280px;
}
}
@media (max-width: 560px) {
.cg-12__metrics {
gap: 14px;
}
.cg-12__metrics strong {
font-size: 1.25rem;
}
.cg-12__collage {
aspect-ratio: 1/1;
}
}
@media (prefers-reduced-motion: reduce) {
.cg-12__cta {
transition: none;
}
}
```Here's a working CSS Card Grid 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 Hero Photo Collage Grid
Source: https://codefronts.com/layouts/css-card-grid-layout/css-hero-photo-collage-grid/
A landing-page hero with a 5-tile asymmetric photo collage on the right and a marketing headline + CTA on the left — the exact pattern Airbnb, Notion, and Linear use to combine narrative copy with visual proof on their homepage hero. Photos are CSS gradient placeholders with location labels and category pills.
## HTML
```html
<div class="cg-12">
<div class="cg-12__inner">
<div class="cg-12__copy">
<span class="cg-12__kicker">New · 2026 collection</span>
<h2 class="cg-12__title">Stay places that<br><em>feel like home.</em></h2>
<p class="cg-12__lede">Hand-picked stays in 47 cities. Verified by humans. Booked by people who care where they sleep.</p>
<div class="cg-12__actions">
<a href="#" class="cg-12__cta">Browse stays →</a>
<a href="#" class="cg-12__link">How it works</a>
</div>
<div class="cg-12__metrics">
<div><strong>4.9 ★</strong><span>Avg rating</span></div>
<div><strong>12K+</strong><span>Verified stays</span></div>
<div><strong>47</strong><span>Cities</span></div>
</div>
</div>
<div class="cg-12__collage">
<div class="cg-12__photo cg-12__photo--1">
<span class="cg-12__pill">Iceland</span>
<span class="cg-12__label">Black Sand Cabin</span>
</div>
<div class="cg-12__photo cg-12__photo--2">
<span class="cg-12__pill">Tokyo</span>
<span class="cg-12__label">Shibuya Loft</span>
</div>
<div class="cg-12__photo cg-12__photo--3">
<span class="cg-12__pill">Lisbon</span>
<span class="cg-12__label">Alfama Studio</span>
</div>
<div class="cg-12__photo cg-12__photo--4">
<span class="cg-12__pill">Marrakech</span>
<span class="cg-12__label">Medina Riad</span>
</div>
<div class="cg-12__photo cg-12__photo--5">
<span class="cg-12__pill">Brooklyn</span>
<span class="cg-12__label">Williamsburg Flat</span>
</div>
</div>
</div>
</div>
```
## CSS
```css
.cg-12,
.cg-12 *,
.cg-12 *::before,
.cg-12 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cg-12 ::selection {
background: #0f172a;
color: #fff;
}
.cg-12 {
--bg: #fafaf7;
--ink: #0f172a;
--muted: #64748b;
--accent: #dc2626;
--line: #e2e8f0;
min-height: 100vh;
background: var(--bg);
padding: clamp(28px,4vw,56px) clamp(20px,3vw,48px);
font-family: -apple-system,BlinkMacSystemFont,"Inter","Segoe UI",sans-serif;
color: var(--ink);
display: flex;
align-items: center;
justify-content: center;
}
.cg-12__inner {
width: 100%;
max-width: 1200px;
display: grid;
grid-template-columns: 1fr 1.2fr;
gap: clamp(24px,3.4vw,56px);
align-items: center;
}
.cg-12__copy {
display: flex;
flex-direction: column;
gap: 18px;
max-width: 520px;
}
.cg-12__kicker {
display: inline-block;
width: fit-content;
font-size: .72rem;
font-weight: 700;
letter-spacing: .16em;
text-transform: uppercase;
color: var(--accent);
padding: 5px 12px;
border-radius: 999px;
background: rgba(220,38,38,.1);
}
.cg-12__title {
font-size: clamp(2.2rem,4.5vw,3.6rem);
font-weight: 900;
letter-spacing: -.03em;
line-height: 1.02;
}
.cg-12__title em {
font-style: italic;
color: var(--accent);
font-family: Georgia,"Times New Roman",serif;
font-weight: 700;
}
.cg-12__lede {
font-size: clamp(.96rem,1.2vw,1.1rem);
color: var(--muted);
line-height: 1.55;
max-width: 46ch;
}
.cg-12__actions {
display: flex;
align-items: center;
gap: 16px;
flex-wrap: wrap;
margin-top: 6px;
}
.cg-12__cta {
display: inline-block;
background: var(--ink);
color: #fff;
padding: 14px 22px;
border-radius: 10px;
font-weight: 700;
font-size: .96rem;
text-decoration: none;
transition: transform .2s,background .2s;
}
.cg-12__cta:hover {
background: var(--accent);
transform: translateY(-2px);
}
.cg-12__link {
font-size: .94rem;
font-weight: 600;
color: var(--ink);
text-decoration: none;
position: relative;
}
.cg-12__link::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: -3px;
height: 1.5px;
background: currentColor;
}
.cg-12__metrics {
display: flex;
gap: clamp(20px,3vw,40px);
margin-top: 16px;
padding-top: 24px;
border-top: 1px solid var(--line);
}
.cg-12__metrics > div {
display: flex;
flex-direction: column;
gap: 2px;
}
.cg-12__metrics strong {
font-size: 1.5rem;
font-weight: 900;
letter-spacing: -.02em;
}
.cg-12__metrics span {
font-size: .78rem;
color: var(--muted);
font-weight: 600;
}
/* Collage */
.cg-12__collage {
display: grid;
grid-template-columns: repeat(3,1fr);
grid-template-rows: repeat(3,1fr);
gap: clamp(8px,1vw,14px);
aspect-ratio: 1.05/1;
min-height: clamp(320px,42vw,560px);
}
.cg-12__photo {
position: relative;
border-radius: 14px;
overflow: hidden;
display: flex;
align-items: flex-end;
padding: 12px;
isolation: isolate;
}
.cg-12__photo::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(180deg,transparent 45%,rgba(0,0,0,.55));
z-index: 0;
}
.cg-12__pill {
position: absolute;
top: 10px;
right: 10px;
background: rgba(255,255,255,.92);
color: var(--ink);
font-size: .62rem;
font-weight: 700;
letter-spacing: .1em;
text-transform: uppercase;
padding: 4px 9px;
border-radius: 999px;
backdrop-filter: blur(8px);
z-index: 2;
}
.cg-12__label {
position: relative;
z-index: 1;
color: #fff;
font-size: .86rem;
font-weight: 700;
letter-spacing: -.005em;
text-shadow: 0 1px 3px rgba(0,0,0,.4);
}
.cg-12__photo--1 {
grid-column: 1 / span 2;
grid-row: 1 / span 2;
background: linear-gradient(135deg,#1e3a5f,#0f1c2e);
}
.cg-12__photo--2 {
grid-column: 3 / span 1;
grid-row: 1 / span 1;
background: linear-gradient(135deg,#d97a99,#7a3855);
}
.cg-12__photo--3 {
grid-column: 3 / span 1;
grid-row: 2 / span 1;
background: linear-gradient(135deg,#f4a572,#d97f4f);
}
.cg-12__photo--4 {
grid-column: 1 / span 1;
grid-row: 3 / span 1;
background: linear-gradient(135deg,#e6c54a,#a8732d);
}
.cg-12__photo--5 {
grid-column: 2 / span 2;
grid-row: 3 / span 1;
background: linear-gradient(135deg,#7aa852,#3d6a2a);
}
@media (max-width: 900px) {
.cg-12__inner {
grid-template-columns: 1fr;
gap: 32px;
}
.cg-12__copy {
max-width: none;
text-align: center;
align-items: center;
}
.cg-12__kicker {
margin: 0 auto 0 0;
}
.cg-12__collage {
aspect-ratio: 1.4/1;
min-height: 280px;
}
}
@media (max-width: 560px) {
.cg-12__metrics {
gap: 14px;
}
.cg-12__metrics strong {
font-size: 1.25rem;
}
.cg-12__collage {
aspect-ratio: 1/1;
}
}
@media (prefers-reduced-motion: reduce) {
.cg-12__cta {
transition: none;
}
}
```How this works
The hero uses a 2-column outer grid: grid-template-columns: 1fr 1.2fr giving the right collage slightly more visual weight. The collage itself is a nested 3x3 CSS grid where each photo declares its own grid-column: span N; grid-row: span N for irregular bento sizing.
Each photo card is a flex column with align-items: flex-end so the location label pins to the bottom-left. Category pills sit at top-right via position: absolute. The 5 photo gradients all use 135deg linear-gradient with distinct colour pairs sampled from the warm/cool palette — when swapped for real images, the location labels and category pills stay in place.
A subtle linear-gradient(180deg, transparent 50%, rgba(0,0,0,.5)) overlay on each photo via ::after ensures the white location labels stay readable on any photo brightness — the production gradient overlay every photo grid in 2026 ships.
Make it yours
- Replace gradient photos with real images by swapping
background: linear-gradient(...)forbackground: url('/path.jpg') center/coveron each.cg-12__photo--N. - Resize the collage by changing the outer grid's
grid-template-columns: 1fr 1.2frto1fr 1.6frfor collage-dominant or1.2fr 1frfor copy-dominant. - Add more photos by extending the nested grid's
grid-template-columns: repeat(3, 1fr)torepeat(4, 1fr)and giving photos differentspanvalues. - Recolour CTAs by editing
--accenton.cg-12— every button + pill + accent inherits. - Change category pill text per tile by editing each
.cg-12__pill's text content.
Gotchas — read before shipping
- When swapping gradients for real images, ensure each image has at least 800x600 source resolution — the largest collage tiles span 2x2 of the 3x3 nested grid and look blocky if undersized.
- The dark gradient overlay (
::afterat bottom 50%) can darken bright photos too much — adjust the overlay's stop position from50%to70%to keep more of the photo visible. - On mobile, the side-by-side becomes stacked — make sure your headline doesn't end with a long unbreakable word, or it'll overflow the mobile column at the narrowest breakpoint.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 76+ | 9+ | 103+ | 76+ |
Floor set by backdrop-filter as this demo is written. The core technique itself goes back further — Chrome 57+.
Baseline CSS Grid + Flexbox. CSS gradients have universal browser support.