02Chỉ mở một mục nhờ thuộc tính name
Mở mục khác thì mục đang mở tự đóng lại, chỉ nhờ một thuộc tính name.
Dùng choMenu cài đặt, FAQ chỉ hiện một câu trả lời
name 속성닫힘 300ms라디오형

<main class="stage">
<section class="accordion-group">
<div class="accordion accordion--a">
<div class="accordion__header" role="button" tabindex="0" aria-expanded="false">
<span class="accordion__title">Giao hàng mất bao lâu</span>
<span class="accordion__chevron" aria-hidden="true"></span>
</div>
<div class="accordion__panel is-demo-a">
<p class="accordion__body">Thường mất 2-3 ngày.</p>
</div>
</div>
<div class="accordion accordion--b">
<div class="accordion__header" role="button" tabindex="0" aria-expanded="false">
<span class="accordion__title">Đổi hàng thế nào</span>
<span class="accordion__chevron" aria-hidden="true"></span>
</div>
<div class="accordion__panel is-demo-b">
<p class="accordion__body">Đăng ký đổi hàng tại trang cá nhân.</p>
</div>
</div>
</section>
</main>@use "../../../../site/static/demo-tokens" as *;
$duration: $dur-quick;
$easing: $ease-out;
$color: $subject-cream;
@include stage($stage-yellow);
.accordion-group {
width: clamp(220px, 78vw, 340px);
display: flex;
flex-direction: column;
gap: 10px;
}
.accordion {
width: clamp(220px, 78vw, 340px);
background: $subject-ink;
border-radius: $r-card;
box-shadow: $shadow-raised;
overflow: hidden;
font-family: inherit;
}
.accordion__header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
width: 100%;
border: 0;
background: none;
padding: clamp(12px, 3vw, 18px) clamp(14px, 4vw, 20px);
cursor: pointer;
color: $subject-cream;
font-weight: 600;
font-size: clamp(14px, 3.6vw, 17px);
line-height: 1.3;
font-family: inherit;
text-align: left;
}
.accordion__chevron {
flex: none;
width: 9px;
height: 9px;
border-right: 2px solid currentColor;
border-bottom: 2px solid currentColor;
transform: rotate(45deg);
}
.accordion__body {
margin: 0;
padding: 0 clamp(14px, 4vw, 20px) clamp(12px, 3vw, 18px);
color: $subject-cream;
opacity: .86;
font-weight: 400;
font-size: clamp(12px, 3.2vw, 14.5px);
line-height: 1.5;
font-family: inherit;
}
.accordion__panel {
height: 0;
overflow: hidden;
interpolate-size: allow-keywords;
}
.accordion.is-open .accordion__panel {
height: calc-size(auto, size);
transition: height $duration $easing;
}
@supports not (height: calc-size(auto, size)) {
.accordion.is-open .accordion__panel { height: auto; }
}
// 데모: name 속성처럼 하나가 열리는 동안 나머지는 닫혀 있다 (2초 주기, 위상만 반대)
.accordion__panel.is-demo-a { animation: accordion-loop-a $dur-loop $easing infinite; }
.accordion__panel.is-demo-b { animation: accordion-loop-b $dur-loop $easing infinite; }
@keyframes accordion-loop-a {
0%, 4% { height: 0; }
20%, 46% { height: calc-size(auto, size); }
62%, 100% { height: 0; }
}
@keyframes accordion-loop-b {
0%, 54% { height: 0; }
70%, 96% { height: calc-size(auto, size); }
100% { height: 0; }
}
@supports not (height: calc-size(auto, size)) {
@keyframes accordion-loop-a { 0%, 4% { height: 0; } 20%, 46% { height: 160px; } 62%, 100% { height: 0; } }
@keyframes accordion-loop-b { 0%, 54% { height: 0; } 70%, 96% { height: 160px; } 100% { height: 0; } }
}
@media (prefers-reduced-motion: reduce) {
.accordion__panel,
.accordion__panel.is-demo,
.accordion__chevron,
.accordion__body,
.accordion.is-open .accordion__panel {
animation: none !important;
transition: none !important;
}
.accordion__panel.is-demo { height: auto; }
}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);
}
.accordion-group {
width: clamp(220px, 78vw, 340px);
display: flex;
flex-direction: column;
gap: 10px;
}
.accordion {
width: clamp(220px, 78vw, 340px);
background: #17141a;
border-radius: 16px;
box-shadow: 0 14px 24px rgba(23, 20, 26, 0.32);
overflow: hidden;
font-family: inherit;
}
.accordion__header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
width: 100%;
border: 0;
background: none;
padding: clamp(12px, 3vw, 18px) clamp(14px, 4vw, 20px);
cursor: pointer;
color: #fff7e6;
font-weight: 600;
font-size: clamp(14px, 3.6vw, 17px);
line-height: 1.3;
font-family: inherit;
text-align: left;
}
.accordion__chevron {
flex: none;
width: 9px;
height: 9px;
border-right: 2px solid currentColor;
border-bottom: 2px solid currentColor;
transform: rotate(45deg);
}
.accordion__body {
margin: 0;
padding: 0 clamp(14px, 4vw, 20px) clamp(12px, 3vw, 18px);
color: #fff7e6;
opacity: 0.86;
font-weight: 400;
font-size: clamp(12px, 3.2vw, 14.5px);
line-height: 1.5;
font-family: inherit;
}
.accordion__panel {
height: 0;
overflow: hidden;
interpolate-size: allow-keywords;
}
.accordion.is-open .accordion__panel {
height: calc-size(auto, size);
transition: height 220ms ease-out;
}
@supports not (height: calc-size(auto, size)) {
.accordion.is-open .accordion__panel {
height: auto;
}
}
.accordion__panel.is-demo-a {
animation: accordion-loop-a 2s ease-out infinite;
}
.accordion__panel.is-demo-b {
animation: accordion-loop-b 2s ease-out infinite;
}
@keyframes accordion-loop-a {
0%, 4% {
height: 0;
}
20%, 46% {
height: calc-size(auto, size);
}
62%, 100% {
height: 0;
}
}
@keyframes accordion-loop-b {
0%, 54% {
height: 0;
}
70%, 96% {
height: calc-size(auto, size);
}
100% {
height: 0;
}
}
@supports not (height: calc-size(auto, size)) {
@keyframes accordion-loop-a {
0%, 4% {
height: 0;
}
20%, 46% {
height: 160px;
}
62%, 100% {
height: 0;
}
}
@keyframes accordion-loop-b {
0%, 54% {
height: 0;
}
70%, 96% {
height: 160px;
}
100% {
height: 0;
}
}
}
@media (prefers-reduced-motion: reduce) {
.accordion__panel,
.accordion__panel.is-demo,
.accordion__chevron,
.accordion__body,
.accordion.is-open .accordion__panel {
animation: none !important;
transition: none !important;
}
.accordion__panel.is-demo {
height: auto;
}
}(function () {
var group = document.querySelector('.accordion-group');
var accs = Array.prototype.slice.call(group.querySelectorAll('.accordion'));
accs.forEach(function (acc) {
var header = acc.querySelector('.accordion__header');
var panel = acc.querySelector('.accordion__panel');
header.addEventListener('click', function () {
panel.classList.remove('is-demo-a', 'is-demo-b');
var willOpen = !acc.classList.contains('is-open');
accs.forEach(function (other) {
other.classList.remove('is-open');
other.querySelector('.accordion__header').setAttribute('aria-expanded', 'false');
other.querySelector('.accordion__panel').classList.remove('is-demo-a', 'is-demo-b');
});
if (willOpen) {
acc.classList.add('is-open');
header.setAttribute('aria-expanded', 'true');
}
});
});
})();import { useState } from "react";
import type { CSSProperties, ReactNode } from "react";
import styles from "./AccordionExclusiveOpen.module.scss";
export type AccordionExclusiveOpenProps = {
/** 헤더에 보이는 제목 */
header?: ReactNode;
/** 열렸을 때 보이는 본문 */
children?: ReactNode;
/** height:auto 전환 시간 (기본 300ms) */
duration?: number;
/** CSS easing */
easing?: string;
/** 강조 색 */
color?: string;
defaultOpen?: boolean;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
export default function AccordionExclusiveOpen({
header = "How long does shipping take?",
children = "Usually 2-3 days.",
duration = 300,
easing = "cubic-bezier(.2,.8,.2,1)",
color = "#17141a",
defaultOpen = false,
}: AccordionExclusiveOpenProps) {
const [open, setOpen] = useState(defaultOpen);
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing, "--color": color };
return (
<section className={styles.accordion} style={vars}>
<button
type="button"
className={styles.header}
aria-expanded={open}
onClick={() => setOpen((v) => !v)}
>
<span>{header}</span>
<span className={`${styles.chevron} ${open ? styles.chevronOpen : ""}`} aria-hidden="true" />
</button>
<div className={`${styles.panel} ${open ? styles.panelOpen : ""}`}>
<p className={styles.body}>{children}</p>
</div>
</section>
);
}02 Chỉ mở một mục nhờ thuộc tính name — Diện tích đo được 32.087% · khung hình chuyển động 11/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · 9 hiệu ứng css accordion animation không JS
Bài viết chứa demo này
9 hiệu ứng css accordion animation không JSCss accordion animation là hiệu ứng chuyển chiều cao nội dung từ 0 sang auto, dựng bằng interpolate-size và calc-size() Xem tất cả demo trong bài này


