diff --git a/.github/scripts/update-changelog.js b/.github/scripts/update-changelog.js index 0c5a6430ff..b0dd9ec0bf 100644 --- a/.github/scripts/update-changelog.js +++ b/.github/scripts/update-changelog.js @@ -1,61 +1,87 @@ -const fs = require('fs') - -const addedContent = fs.readFileSync('added-content.txt').toString().split('\n') - -const currentDate = new Date() -const currentYear = currentDate.getFullYear() -const monthNames = ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'] -const currentMonth = monthNames[currentDate.getMonth()] -const header = `## ${currentMonth} ${currentYear}` - -const contentList = addedContent - .map((fileName) => { - if (fs.existsSync(fileName)) { - const url = `https://doka.guide/${fileName.replace('index.md', '')}` - const date = process.argv[2] - - const content = fs.readFileSync(fileName).toString() - - const title = content - .match(/title: ('|"|).*('|"|)\n/)[0] - .replace(/title: ('|"|)/, '') - .replace(/('|"|)\n/, '') - - const authorsSelection = /authors:\n( - .*\n)+(contributors|cover|editors|keywords|related|tags):/ - const authors = content - .match(authorsSelection)[0] - .split('\n') - .slice(1, -1) - .map((s) => s.replace(' - ', '')) - .map((a) => { - const authorFileName = `./people/${a}/index.md` - if (fs.existsSync(authorFileName)) { - return fs.readFileSync(authorFileName) - .toString() - .match(/name: ('|"|).*('|"|)\n/)[0] - .replace(/name: ('|"|)/, '') - .replace(/('|"|)\n/, '') - } - return authorFileName - }) - - return `- ${date}, [${title}](${url}), ${authors.join(', ')}` +const fs = require("fs"); + +const addedContent = fs + .readFileSync("added-content.txt") + .toString() + .split("\n"); + +if ( + addedContent.length === 0 || + (addedContent.length > 0 && addedContent[0] === "") +) { + return; +} + +const currentDate = new Date(); +const currentYear = currentDate.getFullYear(); +const monthNames = [ + "Январь", + "Февраль", + "Март", + "Апрель", + "Май", + "Июнь", + "Июль", + "Август", + "Сентябрь", + "Октябрь", + "Ноябрь", + "Декабрь", +]; +const currentMonth = monthNames[currentDate.getMonth()]; +const header = `## ${currentMonth} ${currentYear}`; + +const contentList = addedContent.map((fileName) => { + if (fs.existsSync(fileName)) { + const url = `https://doka.guide/${fileName.replace("index.md", "")}`; + const date = process.argv[2]; + + const content = fs.readFileSync(fileName).toString(); + + const title = content + .match(/title: ('|"|).*('|"|)\n/)[0] + .replace(/title: ('|"|)/, "") + .replace(/('|"|)\n/, ""); + + const authorsSelection = + /authors:\n( - .*\n)+(contributors|cover|editors|keywords|related|tags):/; + const authors = content + .match(authorsSelection)[0] + .split("\n") + .slice(1, -1) + .map((s) => s.replace(" - ", "")) + .map((a) => { + const authorFileName = `./people/${a}/index.md`; + if (fs.existsSync(authorFileName)) { + return fs + .readFileSync(authorFileName) + .toString() + .match(/name: ('|"|).*('|"|)\n/)[0] + .replace(/name: ('|"|)/, "") + .replace(/('|"|)\n/, ""); + } + return authorFileName; + }); + + return `- ${date}, [${title}](${url}), ${authors.join(", ")}`; + } +}); + +if (contentList.length > 0) { + const changelogFileName = "./CHANGELOG.md"; + if (fs.existsSync(changelogFileName)) { + const changelog = fs.readFileSync(changelogFileName).toString().split("\n"); + if (changelog.filter((s) => s.startsWith("## ")).includes(header)) { + const headerPosition = changelog.findIndex((s) => s === header); + changelog.splice(headerPosition + 2, 0, ...contentList); + } else { + const headerPosition = 4; + changelog.splice(headerPosition, 0, ...[header, "", ""]); + changelog.splice(headerPosition + 2, 0, ...contentList); } - }) - -const changelogFileName = './CHANGELOG.md' -if (fs.existsSync(changelogFileName)) { - const changelog = fs.readFileSync(changelogFileName).toString().split('\n') - if (changelog.filter((s) => s.startsWith('## ')).includes(header)) { - const headerPosition = changelog.findIndex((s) => s === header) - changelog.splice(headerPosition + 2, 0, ...contentList) - } else { - const headerPosition = 4 - changelog.splice(headerPosition, 0, ...[header, '', '']) - changelog.splice(headerPosition + 2, 0, ...contentList) + fs.writeFileSync(changelogFileName, changelog.join("\n")); + console.log("Записи добавлены в CHANGELOG.md"); } - fs.writeFileSync(changelogFileName, changelog.join('\n')) - console.log('Записи добавлены в CHANGELOG.md'); } else { - console.log('Нечего добавлять в CHANGELOG.md'); + console.log("Нечего добавлять в CHANGELOG.md"); } diff --git a/.github/scripts/update-changelog.sh b/.github/scripts/update-changelog.sh index 519c162046..138483e254 100644 --- a/.github/scripts/update-changelog.sh +++ b/.github/scripts/update-changelog.sh @@ -1,27 +1,49 @@ #!/bin/bash git diff --name-status HEAD^ HEAD | grep '^A' | grep -E '(html|css|js|tools|a11y|recipes)\/.*\/index\.md' | sed 's/^A\t//g' > added-content.txt -MONTH_TO_RUS() { - case "$1" in - 01) echo "января" ;; - 02) echo "февраля" ;; - 03) echo "марта" ;; - 04) echo "апреля" ;; - 05) echo "мая" ;; - 06) echo "июня" ;; - 07) echo "июля" ;; - 08) echo "августа" ;; - 09) echo "сентября" ;; - 10) echo "октября" ;; - 11) echo "ноября" ;; - 12) echo "декабря" ;; - esac -} - -MERGE_DATE=$(date -u +"%d %m") -DAY=$(echo $MERGE_DATE | cut -d ' ' -f 1) -MONTH=$(echo $MERGE_DATE | cut -d ' ' -f 2) -RUS_MONTH=$(MONTH_TO_RUS $MONTH) -FORMATTED_DATE="$DAY $RUS_MONTH" - -node .github/scripts/update-changelog.js "$FORMATTED_DATE" +if [ -s added-content.txt ]; then + MONTH_TO_RUS() { + case "$1" in + 01) echo "января" ;; + 02) echo "февраля" ;; + 03) echo "марта" ;; + 04) echo "апреля" ;; + 05) echo "мая" ;; + 06) echo "июня" ;; + 07) echo "июля" ;; + 08) echo "августа" ;; + 09) echo "сентября" ;; + 10) echo "октября" ;; + 11) echo "ноября" ;; + 12) echo "декабря" ;; + esac + } + + MERGE_DATE=$(date -u +"%d %m") + DAY=$(echo $MERGE_DATE | cut -d ' ' -f 1) + MONTH=$(echo $MERGE_DATE | cut -d ' ' -f 2) + RUS_MONTH=$(MONTH_TO_RUS $MONTH) + FORMATTED_DATE="$DAY $RUS_MONTH" + + node .github/scripts/update-changelog.js "$FORMATTED_DATE" + + rm -f added-content.txt + + if [[ -z $(git status -s) ]] + then + echo $(git status) + else + git config --global user.name "Doka Dog" + git config --global user.email "" + + git add CHANGELOG.md + git commit -m "Обновляет CHANGELOG" --author "Doka Dog " + + git pull --rebase + git push origin main + + exit + fi +else + echo "Новых материалов не было в предыдущем коммите" +fi diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index f09bbf8e22..aef77c1d99 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -25,20 +25,3 @@ jobs: node-version: 20 - name: Ищет новые материалы и обновляет CHANGELOG run: sh .github/scripts/update-changelog.sh - - name: Создание коммита с обновлениями полей - run: | - if [[ -z $(git status -s) ]] - then - echo $(git status) - else - git config --global user.name "Doka Dog" - git config --global user.email "" - - git add CHANGELOG.md - git commit -m "Обновляет CHANGELOG" --author "Doka Dog " - - git pull --rebase - git push origin main - - exit - fi diff --git a/.github/workflows/update-dates.yml b/.github/workflows/update-dates.yml index e12323bfc4..67b52dc5e4 100644 --- a/.github/workflows/update-dates.yml +++ b/.github/workflows/update-dates.yml @@ -3,7 +3,7 @@ name: Update Dates on: workflow_run: workflows: - - "Frontmatter Lint" + - "Update CHANGELOG" branches: - main types: diff --git a/CHANGELOG.md b/CHANGELOG.md index 6083b39e29..44cdaf346e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,28 +4,9 @@ ## Июль 2024 - - - - - - - - - - - - - - - - - - - - -- 19 июля, [`.difference()`](https://doka.guide/js/set-difference/), Viktar Nezhbart +- 22 июля, [Стилизация чекбоксов и радиокнопок](https://doka.guide/recipes/checkbox-radio-style/), Михаил Кривдин - 19 июля, [`.intersection()`](https://doka.guide/js/set-intersection/), Viktar Nezhbart +- 19 июля, [`.difference()`](https://doka.guide/js/set-difference/), Viktar Nezhbart - 12 июля, [`.union()`](https://doka.guide/js/set-union/), Viktar Nezhbart - 1 июля, [`.symmetricDifference()`](https://doka.guide/js/set-symmetric-difference/), Viktar Nezhbart diff --git a/js/index.md b/js/index.md index 244e414332..a6fa822a74 100644 --- a/js/index.md +++ b/js/index.md @@ -147,6 +147,11 @@ groups: - set-keys - set-entries - set-size + - set-union + - set-difference + - set-intersection + - set-symmetric-difference + - set-is-subset-of - name: "Обработка исключений" items: - try-catch diff --git a/js/set-is-subset-of/index.11tydata.json b/js/set-is-subset-of/index.11tydata.json new file mode 100644 index 0000000000..709d828cf8 --- /dev/null +++ b/js/set-is-subset-of/index.11tydata.json @@ -0,0 +1,4 @@ +{ + "createdAt": "2024-07-19T23:12:09.819Z", + "updatedAt": "2024-07-19T23:12:09.819Z" +} diff --git a/js/set-is-subset-of/index.md b/js/set-is-subset-of/index.md index 3885555f4a..7a685d35dc 100644 --- a/js/set-is-subset-of/index.md +++ b/js/set-is-subset-of/index.md @@ -11,7 +11,6 @@ related: - js/set - js/set-entries - js/array-every - - tags: - doka --- diff --git a/people/lonlylokly/index.md b/people/lonlylokly/index.md new file mode 100644 index 0000000000..a4edc7449b --- /dev/null +++ b/people/lonlylokly/index.md @@ -0,0 +1,10 @@ +--- +name: "Михаил Кривдин" +url: https://github.com/loonlylokly +photo: photo.png +photoAlt: "Инвертированный круг Малевича." +badges: + - first-contribution-small +--- + +Магистр ордена Дырявой Верстки. diff --git a/people/lonlylokly/photo.png b/people/lonlylokly/photo.png new file mode 100644 index 0000000000..979cbb8c10 Binary files /dev/null and b/people/lonlylokly/photo.png differ diff --git a/recipes/checkbox-radio-style/demos/checkbox-radio-accent-color/index.html b/recipes/checkbox-radio-style/demos/checkbox-radio-accent-color/index.html new file mode 100644 index 0000000000..ef126d979f --- /dev/null +++ b/recipes/checkbox-radio-style/demos/checkbox-radio-accent-color/index.html @@ -0,0 +1,123 @@ + + + + Стилизация при помощи accent-color — Стилизация чекбоксов и радиокнопок — Дока + + + + + + + + +
+
+ Чекбоксы +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ Радиокнопки +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + diff --git a/recipes/checkbox-radio-style/demos/checkbox-radio-pseudo-elements-div/index.html b/recipes/checkbox-radio-style/demos/checkbox-radio-pseudo-elements-div/index.html new file mode 100644 index 0000000000..edec130b3b --- /dev/null +++ b/recipes/checkbox-radio-style/demos/checkbox-radio-pseudo-elements-div/index.html @@ -0,0 +1,275 @@ + + + + Стилизация при помощи псевдоэлемента и контейнера — Стилизация чекбоксов и радиокнопок — Дока + + + + + + + + +
+
+ Чекбоксы + + + + + + + +
+ +
+ Радиокнопки + + + +
+
+ + diff --git a/recipes/checkbox-radio-style/demos/checkbox-radio-pseudo-elements/index.html b/recipes/checkbox-radio-style/demos/checkbox-radio-pseudo-elements/index.html new file mode 100644 index 0000000000..f255d8dddc --- /dev/null +++ b/recipes/checkbox-radio-style/demos/checkbox-radio-pseudo-elements/index.html @@ -0,0 +1,210 @@ + + + + Стилизация при помощи псевдоэлемента — Стилизация чекбоксов и радиокнопок — Дока + + + + + + + + +
+
+ Чекбоксы +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ Радиокнопки +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + diff --git a/recipes/checkbox-radio-style/index.md b/recipes/checkbox-radio-style/index.md new file mode 100644 index 0000000000..ae8fe057ef --- /dev/null +++ b/recipes/checkbox-radio-style/index.md @@ -0,0 +1,439 @@ +--- +title: "Стилизация чекбоксов и радиокнопок" +description: "Верстаем красивые и доступные чекбоксы и радиокнопки несколькими способами." +authors: + - lonlylokly +keywords: + - checkbox + - radio + - css чекбокс стили + - css радиокнопка + - стилизация чекбокса + - стилизация радиокнопки + - красивый чекбокс + - красивая радиокнопка + - оформление чекбокса и радиокнопки + - css checkbox style + - css radio style +related: + - css/appearance + - css/accent-color + - css/checked +tags: + - article +--- + +## Задача + +Стандартные чекбоксы и радиокнопки часто не соответствуют дизайну веб-приложений и сайтов. Их вид может отличаться в разных браузерах, что затрудняет создание единообразного пользовательского интерфейса. Кроме того, браузерные стили для чекбоксов и радиокнопок могут выглядеть несовременно. + +Задача состоит в том, чтобы создать кастомные элементы форм, которые будут: + +- соответствовать дизайну сайта или приложения; +- выглядеть одинаково во всех браузерах и операционных системах; +- быть доступными для пользователей с особенностями здоровья; +- поддерживать стандартные функции интерактивного элемента формы (отмечен или не отмечен, фокус, взаимодействие с клавиатуры). + +Рассмотрим три способа стилизации чекбокса и радиокнопки. У каждого есть преимущества и недостатки. + +## Решение + +### `accent-color` + +Самый простой способ изменить внешний вид интерактивных элементов управления в веб-формах — использовать CSS-свойство [`accent-color`](/css/accent-color/). Оно изменяет акцентный цвет выделения элемента. + + + +```html +
+ + + + +
+``` + +```css +input[type="checkbox"], +input[type="radio"] { + accent-color: #C56FFF; + width: 20px; + height: 20px; +} +``` + +Преимущества: + +- простота реализации; +- сохранение стандартного поведения элемента (доступен для [скринридеров](/a11y/screenreaders/), поддерживает навигацию с клавиатуры); +- хорошая [поддержка `accent-color` браузерами](https://caniuse.com/mdn-css_properties_accent-color), как и [`appearance`](/css/appearance). + +Недостатки: + +- ограниченные возможности кастомизации (только цвет); +- нельзя изменить форму элемента. + +### Псевдоэлементы + +Метод с псевдоэлементами [`::before`](/css/before/) и [`::after`](/css/after/) для создания кастомного чекбокса или радиокнопки. + + + +Напишем простую разметку. + +```html +
+
+ + +
+
+ + +
+
+``` + +Центрируем элемент и подписи внутри обёртки. + +```css +.checkbox, +.radio { + margin-top: 5px; + width: fit-content; + display: flex; + justify-content: center; + align-items: center; +} +``` + +Добавляем отступ для подписи. + +```css +.checkbox-label, +.radio-label { + padding-left: 5px; +} +``` + +Сбрасываем браузерные стили чекбокса и радиокнопки. Добавляем относительное позиционирование для псевдоэлементов и стилизуем. + +```css +.checkbox-input, +.radio-input { + appearance: none; + position: relative; + width: 30px; + height: 30px; + background: #C56FFF; + box-shadow: inset 0 0 5px rgb(0 0 0 / 0.2); + border-radius: 10px; + border: 1px solid #FFFFFF; + transition: 500ms; +} + +.radio-input { + border-radius: 50%; +} +``` + +Теперь добавим галочку внутрь чекбоксов и радиокнопок через псевдоэлемент `::after`. Есть три способа сделать это: + +1. Символ в значении свойства [`content`](/css/content/). +1. Ссылка на [SVG-файл](/html/svg/) с иконкой. +1. Инлайн SVG-иконка. + +Галочка символом. Символ можно вставить прямо в CSS-файл. + +```css +.checkbox-input::after, +.radio-input::after { + content: "\2714"; + position: absolute; + top: -5px; + left: 2px; + width: 0px; + height: 0px; + font-size: 26px; + transition: 500ms; + overflow: hidden; +} + +.radio-input::after { + content: "\1F78B"; +} +``` + +Галочка SVG-файлом. + +```css +.checkbox-input::after, +.radio-input::after { + content: ""; + position: absolute; + width: 0px; + height: 0px; + font-size: 30px; + background-image: url("images/check.svg"); + background-repeat: no-repeat; + transition: 500ms; +} + +.radio-input::after { + background-image: url("images/radio.svg"); +} +``` + +Галочка инлайнового SVG. Для конвертации SVG можете найти онлайн-сервис по запросу «SVG конвертация инлайн CSS». + +```css +.checkbox-input::after, +.radio-input::after { + content: ""; + position: absolute; + width: 0px; + height: 0px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='30' viewBox='0 -960 960 960' width='30' stroke='%23FFFFFF' stroke-width='30' fill='%23FFFFFF'%3E%3Cpath d='M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + transition: 500ms; +} + +.radio-input::after { + background-image: url("data:image/svg+xml,%3csvg width='28' height='28' viewBox='0 0 30 30' fill='none' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M9.88 23C12.6 23 14.2 21.32 15.52 19.52C16.84 21.32 18.44 23 21.16 23C22.16 23 23.04 22.72 23.04 21.8C23.04 21.24 22.6 20.72 21.96 20.72C21.72 20.72 21.28 20.8 21 20.8C19.72 20.8 18.2 19.12 17.36 17.92C19.08 16.08 20.96 13.72 20.96 11.12C20.96 8.12 18.68 6 15.52 6C12.36 6 10.08 8.12 10.08 11.12C10.08 13.72 11.96 16.08 13.68 17.92C12.84 19.12 11.32 20.8 10.04 20.8C9.76 20.8 9.32 20.72 9.08 20.72C8.44 20.72 8 21.24 8 21.8C8 22.72 8.88 23 9.88 23Z' fill='white'/%3e%3c/svg%3e"); +} +``` + +Добавляем состояние [`:checked`](/css/checked/). + +```css +.checkbox-input:checked::after, +.radio-input:checked::after { + width: 30px; + height: 30px; + transition: 500ms; +} +``` + +Добавляем состояние [`:disabled`](/css/disabled-enabled/). + +```css +.checkbox-input:disabled, +.radio-input:disabled { + background: #ccc; + border-color: #ccc; +} + +.checkbox-input:disabled::after, +.radio-input:disabled::after { + filter: grayscale(100%); +} +``` + +Преимущества: + +- разные варианты стилизации; +- использование векторных иконок или Unicode-символов; +- сохранение стандартного поведения элемента (доступен с клавиатуры). + +Недостаток — мало возможностей для анимации. + +### Псевдоэлементы и дополнительный контейнер + +Этот метод похож на предыдущий, но в нём используем дополнительный `
`, который перекрывает `` для более сложных эффектов или анимаций. + + + +Напишем HTML для кастомных чекбокса и радиокнопки. В нашем случае это мордочка Доки с открытыми и закрытыми глазками 👁️👄👁️ Не забудем указать атрибут [`aria-hidden: true`](/a11y/aria-hidden/), чтобы пользователям скринридеров не пришлось слушать названия символов, которые используем в иконке U•ᴥ•U. + +```html +
+ + + +
+``` + +Добавляем стили для новых элементов. Указываем относительное позиционирование, центрируем их и подпись. + +```css +.checkbox, +.radio { + position: relative; + width: fit-content; + display: flex; + justify-content: center; + align-items: center; +} +``` + +Сбрасываем стили по умолчанию у элемента, указываем размер и новые стили таким образом, чтобы при навигации с клавиатуры пользователь видел рамку фокуса. + +```css +.checkbox-input, +.radio-input { + appearance: none; + position: relative; + width: 90px; + height: 40px; + border-radius: 20px; + border: 1px solid #FFFFFF; +} +``` + +Добавляем отступ для подписи. + +```css +.checkbox-label, +.radio-label { + padding-left: 10px; +} +``` + +Позиционируем чекбокс и радиокнопку на место элементов по умолчанию. Добавляем нужные стили. + +```css +.checkbox-new, +.radio-new { + position: absolute; + top: 0px; + left: 0px; + display: flex; + width: 90px; + height: 40px; + padding: 3px; + justify-content: center; + align-items: center; + border: 1px solid transparent; + border-radius: 20px; + user-select: none; +} +``` + +Стилизуем состояние отмеченного элемента. Используем сложное сочетание селекторов, чтобы добраться до соседнего элемента для ``, а потом до вложенного в него элемента. + +```css +.checkbox-new_checked, +.checkbox-input:checked + .checkbox-new > .checkbox-new_unchecked, +.radio-new_checked, +.radio-input:checked + .radio-new > .radio-new_unchecked { + display: none; +} + +.checkbox-input:checked, +.radio-input:checked { + background: #C56FFF; +} + +.checkbox-input:checked + .checkbox-new, +.radio-input:checked + .radio-new { + color: #000000; +} +``` + +Пишем стили для невыбранного состояния элемента. + +```css +.checkbox-input:checked + .checkbox-new > .checkbox-new_checked, +.checkbox-input:not(:checked) + .checkbox-new > .checkbox-new_unchecked, +.radio-input:checked + .radio-new > .radio-new_checked, +.radio-input:not(:checked) + .radio-new > .radio-new_unchecked { + display: initial; +} +``` + +И не забываем про неактивное состояние. + +```css +.checkbox-input:disabled, +.radio-input:disabled { + background: gray; +} +``` + +Преимущества: + +- можно использовать сложные эффекты и анимацию; +- сохраняет базовую доступность, так как используем скрытый стандартный элемент; +- легко стилизовать. + +Недостатки: + +- более сложная реализация; +- нужно дополнительно поработать над доступностью элементов. + +## Доступность + +В некоторых случаях нужно дополнительно поработать над фокусом чекбоксов и радиокнопок, стилизованных при помощи псевдоэлементов или вложенных в один контейнер. + +Контейнер с новым чекбоксом или радиокнопкой может перекрыть фокус у ``. Чтобы пользователь не потерял элемент, добавьте стили фокуса для нового контейнера с помощью псевдокласса [`:focus-visible`](/css/focus-visible/). + +```css +.checkbox-input:focus-visible + .checkbox-new { + outline: 3px solid orange; +} +``` + +Когда из-за стилей для кастомных чекбоксов и радиокнопок на них не устанавливается фокус с клавиатуры, может помочь атрибут [`tabindex="0"`](/html/tabindex/). Помните, что это крайняя мера. + +Какие-то чекбоксы и радиокнопки могут быть отмеченными (`checked`) и одновременно неактивными (`disabled`). Например, когда в личном кабинете всегда выбрана одна настройка и от неё нельзя отказаться. Чтобы передать это скринридерам, пригодится атрибут [`aria-disabled: true`](/a11y/aria-disabled/). В отличие от стандартного HTML-атрибута `disabled`, ARIA-атрибут `aria-disabled` остаётся в порядке фокуса и его зачитывают скринридеры. Так пользователи наверняка узнают, на что они по умолчанию соглашаются или какую настройку не могут изменить. + +На что ещё обратить внимание: + +- продумать стили выбранных/невыбранных, активных/неактивных чекбоксов и радиокнопок; +- следить за соотношением контрастности между элементами, их фокусом и фоном; +- обеспечить видимый фокус при навигации с клавиатуры; +- сделать область клика достаточно большой (минимум 24x24 пикселя, идеально 48х48); +- связывать элемент с подписью к нему при помощи атрибута `for` или оборачивать чекбокс и радиокнопку сразу в `