08受賞・メディア掲載
매체 이름을 클릭하면 aria-expanded 가 바뀌며 그 매체의 인용 문구가 실제로 펼쳐지고, 한 번에 하나만 열립니다.
使いどころ
aria-expandedgrid-template-rowsclick

<main class="stage">
<section class="ap">
<p class="ap__title">
<span class="ap__ic" aria-hidden="true"><svg viewBox="0 0 256 256" width="18" height="18"><g fill="currentColor"><path d="M200 48v63.1c0 39.7-31.75 72.6-71.45 72.9A72 72 0 0 1 56 112V48Z" opacity=".2"/><path d="M232 64h-24V48a8 8 0 0 0-8-8H56a8 8 0 0 0-8 8v16H24A16 16 0 0 0 8 80v16a40 40 0 0 0 40 40h3.65A80.13 80.13 0 0 0 120 191.61V216H96a8 8 0 0 0 0 16h64a8 8 0 0 0 0-16h-24v-24.42c31.94-3.23 58.44-25.64 68.08-55.58H208a40 40 0 0 0 40-40V80a16 16 0 0 0-16-16M48 120a24 24 0 0 1-24-24V80h24v32q0 4 .39 8Zm144-8.9c0 35.52-29 64.64-64 64.9a64 64 0 0 1-64-64V56h128ZM232 96a24 24 0 0 1-24 24h-.5a82 82 0 0 0 .5-8.9V80h24Z"/></g></svg></span>
3つのメディアで紹介されました
</p>
<ul class="ap__grid">
<li class="ap__badge">
<button type="button" class="ap__btn" aria-expanded="false">
<span class="ap__ic-sm" aria-hidden="true"><svg viewBox="0 0 256 256" width="14" height="14"><g fill="currentColor"><path d="M224 64v120a16 16 0 0 1-16 16H32a16 16 0 0 1 16-16V64a8 8 0 0 1 8-8h160a8 8 0 0 1 8 8" opacity=".2"/><path d="M88 112a8 8 0 0 1 8-8h80a8 8 0 0 1 0 16H96a8 8 0 0 1-8-8m8 40h80a8 8 0 0 0 0-16H96a8 8 0 0 0 0 16m136-88v120a24 24 0 0 1-24 24H32a24 24 0 0 1-24-23.89V88a8 8 0 0 1 16 0v96a8 8 0 0 0 16 0V64a16 16 0 0 1 16-16h160a16 16 0 0 1 16 16m-16 0H56v120a23.8 23.8 0 0 1-1.37 8H208a8 8 0 0 0 8-8Z"/></g></svg></span>
THE DAILY BRIEF
</button>
<div class="ap__reveal"><p class="ap__cap">「今年一番実用的なCSSツール」</p></div>
</li>
<li class="ap__badge">
<button type="button" class="ap__btn" aria-expanded="false">
<span class="ap__ic-sm" aria-hidden="true"><svg viewBox="0 0 256 256" width="14" height="14"><g fill="currentColor"><path d="M224 64v120a16 16 0 0 1-16 16H32a16 16 0 0 1 16-16V64a8 8 0 0 1 8-8h160a8 8 0 0 1 8 8" opacity=".2"/><path d="M88 112a8 8 0 0 1 8-8h80a8 8 0 0 1 0 16H96a8 8 0 0 1-8-8m8 40h80a8 8 0 0 0 0-16H96a8 8 0 0 0 0 16m136-88v120a24 24 0 0 1-24 24H32a24 24 0 0 1-24-23.89V88a8 8 0 0 1 16 0v96a8 8 0 0 0 16 0V64a16 16 0 0 1 16-16h160a16 16 0 0 1 16 16m-16 0H56v120a23.8 23.8 0 0 1-1.37 8H208a8 8 0 0 0 8-8Z"/></g></svg></span>
TECH WEEKLY
</button>
<div class="ap__reveal"><p class="ap__cap">「バイブコーダー必見の逸品」</p></div>
</li>
<li class="ap__badge">
<button type="button" class="ap__btn" aria-expanded="false">
<span class="ap__ic-sm" aria-hidden="true"><svg viewBox="0 0 256 256" width="14" height="14"><g fill="currentColor"><path d="M224 64v120a16 16 0 0 1-16 16H32a16 16 0 0 1 16-16V64a8 8 0 0 1 8-8h160a8 8 0 0 1 8 8" opacity=".2"/><path d="M88 112a8 8 0 0 1 8-8h80a8 8 0 0 1 0 16H96a8 8 0 0 1-8-8m8 40h80a8 8 0 0 0 0-16H96a8 8 0 0 0 0 16m136-88v120a24 24 0 0 1-24 24H32a24 24 0 0 1-24-23.89V88a8 8 0 0 1 16 0v96a8 8 0 0 0 16 0V64a16 16 0 0 1 16-16h160a16 16 0 0 1 16 16m-16 0H56v120a23.8 23.8 0 0 1-1.37 8H208a8 8 0 0 0 8-8Z"/></g></svg></span>
STARTUP REVIEW
</button>
<div class="ap__reveal"><p class="ap__cap">「圧倒的なデモの完成度」</p></div>
</li>
</ul>
</section>
</main>@use "../../../../site/static/demo-tokens" as *;
// ── 변수 3개 ──────────────────────────────────────────
$duration: $dur-enter;
$easing: $ease-spring;
$color: $subject-blue;
@include stage($stage-yellow);
.ap { width: min(320px, 94vw); }
.ap__title { display: flex; align-items: center; gap: $sp-1; margin: 0 0 $sp-3; font-weight: 800; font-size: 13px; line-height: 1.2; font-family: inherit; color: $subject-ink; }
.ap__ic { display: grid; place-items: center; color: #a89053; }
.ap__grid { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: $sp-2; }
.ap__badge { border: 1px solid rgba(23, 20, 26, .1); border-radius: $r-control; background: $stage-paper; overflow: hidden; }
.ap__btn {
display: flex; align-items: center; gap: $sp-2; width: 100%;
padding: $sp-2 $sp-3;
border: 0; background: transparent; cursor: pointer; text-align: left;
color: $subject-ink; font-weight: 800; font-size: 11px; line-height: 1.2; letter-spacing: .02em;
}
.ap__ic-sm { display: grid; place-items: center; color: $color; flex: 0 0 auto; }
.ap__reveal { display: grid; grid-template-rows: 0fr; transition: grid-template-rows $duration $easing; }
.ap__badge.is-open .ap__reveal { grid-template-rows: 1fr; }
.ap__cap { margin: 0; overflow: hidden; padding: 0 $sp-3; font-size: 11px; line-height: 1.5; color: rgba(23, 20, 26, .72); font-family: inherit; } // 옐로 무대 위 6.06:1
.ap__badge.is-open .ap__cap { padding: 0 $sp-3 $sp-2; }
// ── 접근성 ──────────────────────────────────────────
@media (prefers-reduced-motion: reduce) {
.ap__cap { transition: none !important; }
}
// ── 반응형(320px) ────────────────────────────────────
@media (max-width: 340px), (max-height: 220px) {
.ap__btn { padding: $sp-1 $sp-2; font-size: 10px; }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #ffd23f;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.ap {
width: min(320px, 94vw);
}
.ap__title {
display: flex;
align-items: center;
gap: 4px;
margin: 0 0 12px;
font-weight: 800;
font-size: 13px;
line-height: 1.2;
font-family: inherit;
color: #17141a;
}
.ap__ic {
display: grid;
place-items: center;
color: #a89053;
}
.ap__grid {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 8px;
}
.ap__badge {
border: 1px solid rgba(23, 20, 26, 0.1);
border-radius: 12px;
background: #ffffff;
overflow: hidden;
}
.ap__btn {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
padding: 8px 12px;
border: 0;
background: transparent;
cursor: pointer;
text-align: left;
color: #17141a;
font-weight: 800;
font-size: 11px;
line-height: 1.2;
letter-spacing: 0.02em;
}
.ap__ic-sm {
display: grid;
place-items: center;
color: #2f6df6;
flex: 0 0 auto;
}
.ap__reveal {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 600ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.ap__badge.is-open .ap__reveal {
grid-template-rows: 1fr;
}
.ap__cap {
margin: 0;
overflow: hidden;
padding: 0 12px;
font-size: 11px;
line-height: 1.5;
color: rgba(23, 20, 26, 0.72);
font-family: inherit;
}
.ap__badge.is-open .ap__cap {
padding: 0 12px 8px;
}
@media (prefers-reduced-motion: reduce) {
.ap__cap {
transition: none !important;
}
}
@media (max-width: 340px), (max-height: 220px) {
.ap__btn {
padding: 4px 8px;
font-size: 10px;
}
}// 실제 동작: 매체 이름을 클릭하거나 Enter 를 누르면 aria-expanded 가 바뀌며 그 매체의 인용 문구가 실제로 펼쳐진다. 한 번에 하나만 열린다.
// .is-demo 자동 再生: 900ms 마다 다음 매체를 돌아가며 펼쳐 보여준다.
var btns = document.querySelectorAll('.ap__btn');
function openOnly(idx) {
btns.forEach(function (b, n) {
var on = n === idx;
b.setAttribute('aria-expanded', String(on));
b.closest('.ap__badge').classList.toggle('is-open', on);
});
}
btns.forEach(function (btn, idx) {
btn.addEventListener('click', function () {
var open = btn.getAttribute('aria-expanded') === 'true';
openOnly(open ? -1 : idx);
restart();
});
});
var ai = 0, timer = null;
function tick() { ai = (ai + 1) % btns.length; openOnly(ai); }
function restart() { if (timer) clearInterval(timer); timer = setInterval(tick, 900); }
openOnly(0);
restart();import { useEffect, useState } from "react";
import type { CSSProperties } from "react";
import styles from "./AwardsPress.module.scss";
export type AwardsPressProps = { duration?: number; easing?: string; color?: string };
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
const OUTLETS = [
{ name: "THE DAILY BRIEF", quote: `"올해 나온 CSS 도구 중 가장 실용적"` },
{ name: "TECH WEEKLY", quote: `"바이브코더를 위한 최고의 발견"` },
{ name: "STARTUP REVIEW", quote: `"압도적인 실측 데모 품질"` },
];
export default function AwardsPress({ duration = 600, easing = "cubic-bezier(.2,.8,.2,1)", color = "#2f6df6" }: AwardsPressProps) {
const [open, setOpen] = useState<number | null>(0);
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing, "--color": color };
// 자동 재생: 900ms 마다 다음 매체를 돌아가며 펼쳐 보여준다
useEffect(() => {
const id = setInterval(() => setOpen((o) => ((o ?? -1) + 1) % OUTLETS.length), 900);
return () => clearInterval(id);
}, []);
return (
<section className={styles.ap} style={vars}>
<p className={styles.title}>
<span className={styles.ic} aria-hidden="true">
<svg viewBox="0 0 256 256" width="18" height="18">
<g fill="currentColor">
<path d="M200 48v63.1c0 39.7-31.75 72.6-71.45 72.9A72 72 0 0 1 56 112V48Z" opacity=".2" />
<path d="M232 64h-24V48a8 8 0 0 0-8-8H56a8 8 0 0 0-8 8v16H24A16 16 0 0 0 8 80v16a40 40 0 0 0 40 40h3.65A80.13 80.13 0 0 0 120 191.61V216H96a8 8 0 0 0 0 16h64a8 8 0 0 0 0-16h-24v-24.42c31.94-3.23 58.44-25.64 68.08-55.58H208a40 40 0 0 0 40-40V80a16 16 0 0 0-16-16M48 120a24 24 0 0 1-24-24V80h24v32q0 4 .39 8Zm144-8.9c0 35.52-29 64.64-64 64.9a64 64 0 0 1-64-64V56h128ZM232 96a24 24 0 0 1-24 24h-.5a82 82 0 0 0 .5-8.9V80h24Z" />
</g>
</svg>
</span>
3개 매체가 소개했어요
</p>
<ul className={styles.grid}>
{OUTLETS.map((o, i) => {
const isOpen = open === i;
return (
<li key={o.name} className={`${styles.badge} ${isOpen ? styles.isOpen : ""}`}>
<button type="button" className={styles.btn} aria-expanded={isOpen} onClick={() => setOpen(isOpen ? null : i)}>
<span className={styles.icSm} aria-hidden="true">
<svg viewBox="0 0 256 256" width="14" height="14">
<g fill="currentColor">
<path d="M224 64v120a16 16 0 0 1-16 16H32a16 16 0 0 1 16-16V64a8 8 0 0 1 8-8h160a8 8 0 0 1 8 8" opacity=".2" />
<path d="M88 112a8 8 0 0 1 8-8h80a8 8 0 0 1 0 16H96a8 8 0 0 1-8-8m8 40h80a8 8 0 0 0 0-16H96a8 8 0 0 0 0 16m136-88v120a24 24 0 0 1-24 24H32a24 24 0 0 1-24-23.89V88a8 8 0 0 1 16 0v96a8 8 0 0 0 16 0V64a16 16 0 0 1 16-16h160a16 16 0 0 1 16 16m-16 0H56v120a23.8 23.8 0 0 1-1.37 8H208a8 8 0 0 0 8-8Z" />
</g>
</svg>
</span>
{o.name}
</button>
<div className={styles.reveal}><p className={styles.cap}>{o.quote}</p></div>
</li>
);
})}
</ul>
</section>
);
}08 受賞・メディア掲載 — 計測 累積面積 20.544% · 動いたフレーム 11/23GODRICH オリジナル · SCSS と React は zip に同梱 · 【コピペOK】信頼を作るLPパーツ9選
このデモが属する記事
【コピペOK】信頼を作るLPパーツ9選LPパーツは、統計カウンターやロゴバーから比較表・問い合わせフォームまで、ランディングページのあちこちに散らばっていた信頼づくりの部品をひとまとめにしたコード集です。LPにそのまま貼れる九つのうち一つは、ページが開いた瞬間に数字が実際に0か この記事のデモをすべて見る


