در این فصل چه میسازی#
این آخرین فصلِ ترمِ «تعامل و جزئیات» است و مفهومِ تازهای ندارد. کارِ امروز ترکیب است: یک آکاردئون میسازی — یک فهرست از پرسشها که هر کدام با یک کلیک باز و بسته میشوند — و همهاش بدونِ یک خط JavaScript. هر ابزاری که این ترم ساختی اینجا نقشی دارد: :checked برای حالت، :has() برای واکنشِ والد، ::after برای علامتِ باز/بسته، transform و transition برای چرخشِ نرمِ آن علامت، :hover و :focus-visible برای واکنش، و از همه مهمتر، یک تعاملِ قابلِ استفاده با صفحهکلید.

آخر این فصل میتوانی:
- یک آکاردئونِ کاملاً بیجاوااسکریپت با
:checkedو:has()بسازی - علامتِ باز/بسته را با
::afterوtransformنرم بچرخانی - یک checkbox را طوری پنهان کنی که دیده نشود ولی با صفحهکلید هنوز کار کند
قبل از شروع#
- از فصل ۵:
:checked. از فصل ۹::has(). از فصل ۳:::afterوcontent. - از فصل ۱:
:hoverو:focus-visible. از فصل ۶:rotate. از فصل ۷:transition.
فقط یک مرورگر لازم داری، یا همین آزمایشگاه.
۱. اسکلت: هر ردیف یک checkbox پنهان دارد#
هر ردیف سه چیز دارد: یک <input type="checkbox"> که حالتِ باز/بسته را نگه میدارد، یک <label> که همان سؤال است و با کلیک آن checkbox را میزند، و یک پنلِ پاسخ. label با for به checkbox وصل است، پس کلیک روی سؤال، تیک را میزند — همان چیزی که در فصل ۵ دیدی.
۲. باز و بسته با :has()#
پنل پیشفرض بسته است (max-height: 0 و overflow: hidden). حالا با :has() از فصل ۹ میگوییم: «ردیفی که checkbox اش تیک خورده، پنلش باز شود». چون از فصل ۷ روی پنل transition گذاشتهایم، این باز شدن نرم است، نه ناگهانی. علامتِ + هم که با ::after ساختهایم، با rotate(45deg) به یک × میچرخد تا بگوید «حالا بازم، دوباره بزن تا ببندم».
۳. اشتباهِ رایج: پنهانکردنی که صفحهکلید را میکُشد#
checkbox واقعی زشت است و میخواهیم پنهانش کنیم. سادهترین راهی که به ذهن میرسد این است:
.q-input {
display: none;
}
با ماوس همهچیز عالی بهنظر میرسد: روی سؤال کلیک میکنی، باز و بسته میشود. ولی یک آزمایش کن: ماوس را کنار بگذار و فقط با کلیدِ Tab روی صفحه بگرد. به هیچ سؤالی نمیرسی، و با صفحهکلید هیچکدام باز نمیشوند. برای کسی که ماوس ندارد، این آکاردئون کاملاً مرده است.
🔧 اگر کار نکرد:
display: noneفقط چیزی را پنهان نمیکند — آن را از ترتیبِ Tab و از دسترسِ صفحهکلید هم حذف میکند. راهِ درست این است که checkbox را طوری پنهان کنی که دیده نشود ولی هنوز focusable بماند: باposition: absoluteاز جریان درش بیاور و باopacity: 0و اندازهٔ یکپیکسلی نامرئیاش کن. حالا هنوز آنجاست، فقط دیده نمیشود:
.q-input {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
}
بعد با :focus-visible (فصل ۱) و :has() یک حلقهٔ focus روی خودِ سؤال نشان میدهیم تا کاربرِ صفحهکلید ببیند الان روی کدام ردیف است. حالا هم ماوس کار میکند، هم Tab و Space.
✅ چک کن: با ماوس ردیفها باز و بسته میشوند و علامتِ + نرم به × میچرخد. حالا Tab بزن: روی هر سؤال یک حلقهٔ آبی میآید، و با Space همان ردیف باز میشود. هر دو راه کار میکنند.
۴. کد کاملِ پروژه#
اول index.html:
<!-- index.html -->
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>آکاردئون بدون JavaScript</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<main class="page">
<section class="faq">
<h1>پرسشهای پرتکرار</h1>
<ul class="faq-list">
<li class="item">
<input class="q-input" type="checkbox" id="q1">
<label class="q-label" for="q1">CSS بدون JavaScript چقدر تعاملی میشود؟</label>
<p class="panel">خیلی بیشتر از چیزی که فکر میکنی — همین آکاردئون مثالش است.</p>
</li>
<li class="item">
<input class="q-input" type="checkbox" id="q2">
<label class="q-label" for="q2">چرا از checkbox استفاده کردیم؟</label>
<p class="panel">چون checkbox دو حالت دارد و مرورگر خودش این حالت را نگه میدارد.</p>
</li>
<li class="item">
<input class="q-input" type="checkbox" id="q3">
<label class="q-label" for="q3">با صفحهکلید هم باز میشود؟</label>
<p class="panel">اگر checkbox را درست پنهان کنیم، بله: با Tab میرسی و با Space بازش میکنی.</p>
</li>
</ul>
</section>
</main>
</body>
</html>
و styles.css:
/* styles.css */
* {
box-sizing: border-box;
}
:root {
--bg: #f6edda;
--card: #ffffff;
--ink: #2c2114;
--muted: #6b6150;
--brand: #2a6b93;
--line: #d8ccae;
--open: #eaf1f6;
}
body {
margin: 0;
font-family: Tahoma, sans-serif;
background-color: var(--bg);
color: var(--ink);
padding: 40px 20px;
line-height: 1.9;
}
.faq {
max-width: 460px;
margin-inline: auto;
}
.faq h1 {
margin-block: 0 16px;
font-size: 1.5rem;
}
.faq-list {
list-style: none;
margin: 0;
padding: 0;
}
.item {
background-color: var(--card);
border: 1px solid var(--line);
border-radius: 12px;
margin-block-end: 10px;
overflow: hidden;
}
/* checkbox penhan ast vali focusable mimanad */
.q-input {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
}
.q-label {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
padding: 14px 16px;
cursor: pointer;
font-weight: 700;
transition: background-color 0.2s;
}
.q-label:hover {
background-color: var(--open);
}
/* alamat-e + ba ::after (fasl 3), ba charkhesh-e narm (fasl 6 + 7) */
.q-label::after {
content: "+";
color: var(--brand);
font-size: 1.4rem;
line-height: 1;
transition: transform 0.2s;
}
.panel {
max-height: 0;
margin: 0;
padding: 0 16px;
overflow: hidden;
color: var(--muted);
transition: max-height 0.25s ease, padding 0.25s ease;
}
/* :has() -> vaghti item baz ast (checkbox checked): panel baz shavad */
.item:has(.q-input:checked) .panel {
max-height: 200px;
padding-block: 8px 16px;
}
.item:has(.q-input:checked) .q-label {
background-color: var(--open);
}
/* + -> x */
.item:has(.q-input:checked) .q-label::after {
transform: rotate(45deg);
}
/* focus-visible ba safhe-kelid: halghe rooye label */
.item:has(.q-input:focus-visible) .q-label {
outline: 3px solid var(--brand);
outline-offset: -3px;
}

✅ چک کن: سه ردیف داری که مستقل باز و بسته میشوند، علامتشان نرم میچرخد، با ماوس و با صفحهکلید هر دو کار میکنند — و در کلِ فایل یک خط JavaScript نیست. این کلِ ترمِ ۵ در یک component است.
🤖 با AI: آکاردئونِ کاملت را به دستیار AI ات بده و بپرس «این از نظرِ دسترسپذیری و کار با صفحهکلید چه ضعفی دارد؟». جوابش را یک فهرستِ کارها ببین، نه حکمِ نهایی — هر موردش را همانجا در آزمایشگاه با
TabوSpaceخودت چک کن.
واژههای تازهٔ این فصل#
این فصل یک فصلِ پروژهای است و واژهٔ فنیِ تازهای ندارد؛ فقط ابزارهای این ترم — :checked، :has()، ::after، transform، transition و :focus-visible — را کنارِ هم بهکار میگیرد.
تمرینها
اول خودت فکر کن یا امتحان کن — بعد اینجا را باز کن.
در فصل بعد#
اینجا آخرِ ترمِ «تعامل و جزئیات» است. حالا میتوانی صفحه را با حالتها، pseudo-element، فرمِ استایلخورده، transform، animation و :has() زنده و تعاملی کنی — همه بدونِ JavaScript. تا اینجا هر فصل یک تکه بود؛ ترمِ بعد — حرفهای و واقعی — یاد میگیری این تکهها را مثلِ یک حرفهای سازماندهی کنی: CSS را تمیز و مقیاسپذیر بنویسی، مثلِ component فکر کنی، یک design system کوچکِ خودت بسازی، دسترسپذیری را عمیقتر بگیری، و بالاخره یک سایتِ چندصفحهایِ واقعی را روی اینترنت منتشر کنی.
به آخر این فصل رسیدی!
اگر ساختی و جواب داد، این دکمه مال توست.