Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions fundamentals/a11y/ja/alt-text/image-alt.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,23 +100,23 @@

代替テキストは、その画像が伝える意味を正確に説明するべきです。あいまいな言葉や抽象的な表現は、ユーザーが画像から得るべき情報を理解しづらくします。

| 区分 | 例 | 説明 |
| ---------- | -------------------- | ------------------------------------------------------ |
| ❌ 悪い例 | "アイコン" | アイコンの用途や機能に関する情報がありません。 |
| 区分 | 例 | 説明 |
| --------- | -------------------- | ------------------------------------------------ |
| ❌ 悪い例 | "アイコン" | アイコンの用途や機能に関する情報がありません。 |
| ✅ 良い例 | "検索" | アイコンが何を意味するかを明確に伝えます。 |
| ❌ 悪い例 | "グラフ" | このグラフが何を示すのか分かりません。 |
| ❌ 悪い例 | "グラフ" | このグラフが何を示すのか分かりません。 |
| ✅ 良い例 | "2023年の売上グラフ" | グラフがどのデータを示すかを具体的に説明します。 |

### 2. 不要な語を省く

代替テキストはスクリーンリーダーが読むためのものなので、「アイコン」「ボタン」のような語はたいてい冗長です。スクリーンリーダーは、画像を含む要素の役割(ボタンなど)を既に理解しているため、代替テキストでは情報だけを簡潔に伝えるのが望ましいです。

| 区分 | 例 | 説明 |
| ---------- | ------------- | --------------------------------------------------------------------------------------- |
| ✅ 良い例 | "検索" | |
| 区分 | 例 | 説明 |
| --------- | -------------- | -------------------------------------------------------------------------------- |
| ✅ 良い例 | "検索" | |
| ❌ 悪い例 | "検索アイコン" | スクリーンリーダーは「検索、ボタン」と読むため、「アイコン」は重複して不要です。 |
| ✅ 良い例 | "閉じる" | |
| ❌ 悪い例 | "閉じるボタン" | ボタンという役割は既に明らかなので、テキストでは省略したほうがすっきりします。 |
| ✅ 良い例 | "閉じる" | |
| ❌ 悪い例 | "閉じるボタン" | ボタンという役割は既に明らかなので、テキストでは省略したほうがすっきりします。 |

### 3. 画像の目的と文脈を考慮する

Expand Down
2 changes: 1 addition & 1 deletion fundamentals/a11y/ja/eslint/design-system.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,4 @@ export default [

---

このほかにも、デザインシステムにはさまざまなコンポーネントや prop パターンが存在します。詳細は[eslint-plugin-jsx-a11y 공식 문서](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y)のsettingsとrulesのオプションを参照し、要件に合わせてカスタマイズしてください。
このほかにも、デザインシステムにはさまざまなコンポーネントや prop パターンが存在します。詳細は[eslint-plugin-jsx-a11y 공식 문서](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y)のsettingsとrulesのオプションを参照し、要件に合わせてカスタマイズしてください。
2 changes: 1 addition & 1 deletion fundamentals/a11y/ja/playground.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ PCではマウスのクリックとドラッグでタッチ操作を代替でき
<ScreenReaderExperience
url="https://service.toss.im/accessibility/screen-reader-experience"
title="スクリーンリーダー体験ページへ"
/>
/>
2 changes: 1 addition & 1 deletion fundamentals/a11y/ja/predictability/fake-button.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

```jsx
<div class="button-style" style="cursor: pointer" onclick="handleAnything()">
お問い合わせ
お問い合わせ
</div>
```

Expand Down
37 changes: 19 additions & 18 deletions fundamentals/a11y/ja/structure/button-inside-button.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@

次のように`<a>`タグの中に`<button>`を出力するコンポーネントを入れるのは間違いです。HTMLでは、インタラクティブな要素の中に別のインタラクティブ要素を入れることは許可されていないためです[^1].この構造ではアクセシビリティの問題が発生し、ブラウザで予期しない動作が起きる可能性があります。

[^1]: https://www.w3.org/TR/2011/WD-html5-20110405/text-level-semantics.html#the-a-element
のContent model項目を参考にしてください。
[^1]:
https://www.w3.org/TR/2011/WD-html5-20110405/text-level-semantics.html#the-a-element
のContent model項目を参考にしてください。

```jsx
<a href="/go-to">
Expand Down Expand Up @@ -109,20 +110,20 @@ UIの構成上、ボタンのように見えるカードの中に別のボタン

以下の要素はいずれもインタラクティブ要素です。これらのいずれかを含む要素の中に、さらに別のインタラクティブ要素を入れてはいけません。

| 요소 | 조건 |
| ------------ | ------------------------------------ |
| `<a>` | - |
| `<audio>` | controls属性がある場合 |
| `<button>` | - |
| `<details>` | - |
| `<embed>` | - |
| `<iframe>` | - |
| `<img>` | usemap属性がある場合 |
| 요소 | 조건 |
| ------------ | ---------------------------------- |
| `<a>` | - |
| `<audio>` | controls属性がある場合 |
| `<button>` | - |
| `<details>` | - |
| `<embed>` | - |
| `<iframe>` | - |
| `<img>` | usemap属性がある場合 |
| `<input>` | type属性が Hidden state でない場合 |
| `<keygen>` | - |
| `<label>` | - |
| `<menu>` | type属性が toolbar 状態の場合 |
| `<object>` | usemap属性がある場合 |
| `<select>` | - |
| `<textarea>` | - |
| `<video>` | controls属性がある場合 |
| `<keygen>` | - |
| `<label>` | - |
| `<menu>` | type属性が toolbar 状態の場合 |
| `<object>` | usemap属性がある場合 |
| `<select>` | - |
| `<textarea>` | - |
| `<video>` | controls属性がある場合 |
Original file line number Diff line number Diff line change
Expand Up @@ -25,54 +25,55 @@ const MONTH_NAMES = [
"12월"
];

const COLORS = [
css({
backgroundColor: "rgba(0, 0, 0, 0.1)",
color: "rgba(0, 0, 0, 0.4)"
}),
css({
backgroundColor: "rgba(188, 233, 233, 0.2)",
color: "#58C7C7"
}),
css({
backgroundColor: "rgba(237, 204, 248, 0.4)",
color: "#DA9BEF"
}),
css({
backgroundColor: "rgba(255, 239, 191, 0.6)",
color: "#FFC342"
}),
css({
backgroundColor: "rgba(255, 212, 214, 0.2)",
color: "#FB8890"
}),
css({
backgroundColor: "rgba(188, 233, 233, 0.2)",
color: "#58C7C7"
}),
css({
backgroundColor: "rgba(188, 233, 233, 0.2)",
color: "#58C7C7"
}),
css({
backgroundColor: "rgba(255, 212, 214, 0.2)",
color: "#FB8890"
}),
css({
backgroundColor: "rgba(255, 239, 191, 0.6)",
color: "#FFC342"
}),
css({
backgroundColor: "rgba(0, 0, 0, 0.1)",
color: "rgba(0, 0, 0, 0.4)"
})
];

function ChallengeDayItem({ day }: { day: ChallengeDay }) {
const getDayStyle = () => {
switch (day.status) {
case "completed":
const colors = [
css({
backgroundColor: "rgba(0, 0, 0, 0.1)",
color: "rgba(0, 0, 0, 0.4)"
}),
css({
backgroundColor: "rgba(188, 233, 233, 0.2)",
color: "#58C7C7"
}),
css({
backgroundColor: "rgba(237, 204, 248, 0.4)",
color: "#DA9BEF"
}),
css({
backgroundColor: "rgba(255, 239, 191, 0.6)",
color: "#FFC342"
}),
css({
backgroundColor: "rgba(255, 212, 214, 0.2)",
color: "#FB8890"
}),
css({
backgroundColor: "rgba(188, 233, 233, 0.2)",
color: "#58C7C7"
}),
css({
backgroundColor: "rgba(188, 233, 233, 0.2)",
color: "#58C7C7"
}),
css({
backgroundColor: "rgba(255, 212, 214, 0.2)",
color: "#FB8890"
}),
css({
backgroundColor: "rgba(255, 239, 191, 0.6)",
color: "#FFC342"
}),
css({
backgroundColor: "rgba(0, 0, 0, 0.1)",
color: "rgba(0, 0, 0, 0.4)"
})
];
const colorIndex = (day.day - 1) % colors.length;
return colors[colorIndex];
const colorIndex = (day.day - 1) % COLORS.length;
return COLORS[colorIndex];
case "posted":
return postedDayStyle;
case "today":
Expand Down Expand Up @@ -196,12 +197,6 @@ export function MonthlyChallenge({ challenge }: MonthlyChallengeProps) {
);
}

// 7x5 그리드로 배치 (주단위)
const weeks = [];
for (let i = 0; i < displayData.days.length; i += 7) {
weeks.push(displayData.days.slice(i, i + 7));
}

return (
<div className={challengeContainer}>
<div className={headerSection}>
Expand All @@ -210,18 +205,10 @@ export function MonthlyChallenge({ challenge }: MonthlyChallengeProps) {
{displayData.year}년 {monthName} 한 달 기록
</p>
</div>
<Card variant="bordered" padding="md" className="w-full">
<Card variant="bordered" padding="md" className={cardContainer}>
<div className={cardContent}>
{weeks.map((week, weekIndex) => (
<div key={weekIndex} className={calendarGrid}>
{week.map((day) => (
<ChallengeDayItem key={day.day} day={day} />
))}
{week.length < 7 &&
Array.from({ length: 7 - week.length }).map((_, emptyIndex) => (
<div key={`empty-${emptyIndex}`} className={emptyCell} />
))}
</div>
{displayData.days.map((day) => (
<ChallengeDayItem key={day.day} day={day} />
))}
</div>
</Card>
Expand All @@ -233,6 +220,7 @@ export function MonthlyChallenge({ challenge }: MonthlyChallengeProps) {
const challengeContainer = css({
display: "flex",
flexDirection: "column",
padding: "1rem",
gap: "1.5rem"
});

Expand All @@ -257,10 +245,14 @@ const subtitle = css({
letterSpacing: "-0.025em"
});

const cardContainer = css({
maxWidth: "32rem"
});

const cardContent = css({
display: "flex",
flexDirection: "column",
gap: "1rem"
display: "grid",
gridTemplateColumns: "repeat(7, 1fr)",
gap: "0.75rem"
});

const calendarGrid = css({
Expand All @@ -275,12 +267,14 @@ const dayItemContainer = css({
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "0.75rem"
gap: "0.5rem"
});

const dayCircle = css({
width: "3.5rem",
height: "3.5rem",
minWidth: "1.5rem",
minHeight: "1.5rem",
width: "100%",
aspectRatio: "1/1",
borderRadius: "50%",
display: "flex",
alignItems: "center",
Expand Down
Loading