Змінюємо радіокнопки, не змінюючи радіокнопки

18

Від автора: Елементи форми! Скільки мук доставляє їх оформлення, чи не так? Так і хочеться замінити їх все якою-небудь своєю розміткою і CSS. Але проблема криється в тому, що весь набір елементів div і span буде марний з семантичної точки зору, і у нього будуть відсутні ті поведінкові властивості, які роблять доступним стандартний елемент input типу radio.

Доступність?

Це всього лише самотній шматочок тексту, запитувач про доступність. Дійсно сумно. Щоб цей код навіть просто почав працювати, як треба, нам буде потрібно застосувати всілякі допоміжні технології WAI-ARIA. Як співається в безсмертної пісні британської рок-групи Iron Maiden – «чи Варто жартувати з безумством?»

Доступність?

Наш приклад, як і раніше, сто відсотків недоступний, тому що нам доведеться ще, слідуючи стандарту, наділити його всіма традиційними видами поведінки і зробити активними всі необхідні сполучення клавіш. А для цього потрібно використовувати атрибут tabindex і, в достатку, код на JavaScript — і ви знаєте, що? Я навіть не збираюся пробувати йти цим шляхом.

Те, що у мене вийшло зробити, ви можете подивитися в демо-на прикладі сайті CodePen. А далі піде пояснення даної техніки.

Примітка: Якщо до цього ви не використовували клавіатуру для взаємодії з радіокнопками, то знайте, що ви можете переключитися на активну кнопку за допомогою клавіші TAB, а змінити її можна за допомогою стрілок Вгору та Вниз. Це стандартна поведінка, передбачене браузером, а не емуляція на JavaScript.

Використовуйте те, що вже є

Якщо підходити до вирішення питання з точки зору доступності, то потрібно розглядати HTML в якості інтерфейсу, а CSS — просто як зовнішнє оформлення, як брендування. Відповідно, нам потрібно знайти способи отримання контролю над естетикою користувальницького інтерфейсу, не покладаючи надії на переробку розмітки, яка означає відхилення від стандартів.

Що ми знаємо про радіокнопках?

Перше, що нам відомо про радіокнопках, це те, що вони можуть перебувати або у зазначеному стані, або ні. Не думайте зараз про технології ARIA, це просто HTML атрибут checked.

доступний
симпатичний
доступний і симпатичний

По щасливому випадку ми можемо висловити зазначене стан за допомогою CSS псевдо-класу :checked :

[type=»radio»]:checked {
/* тут пишуться властивості */
}

Менше радує те, що ми можемо прописати не так вже багато властивостей, які будуть працювати одночасно особливо добре у всіх браузерах. Радіокнопки вперто відмовляються підкорятися нашої волі.

Селектор сусідніх елементів

Я люблю селектор сусідніх елементів з тією пристрастю, яку чоловік, мабуть, не повинен витрачати на селектори CSS. Цей селектор дозволяє мені стилізувати елементи у відповідності з сутністю елементів, що передує їм. Це дуже потужний інструмент щодо наших радіокнопок, тому що він дозволяє нам перекласти зовнішнє оформлення різних станів на ті елементи, які легко піддаються зміні.

[type=»radio»]:checked + span {
/* стилі для елемента span, що йде після зазначеної радіокнопки */
}

Ми, звичайно, повинні будемо додати у нашу розмітку елементи span, але ще більш важка доля могла б випасти на долю HTML.

Radio Control Quality
доступний
симпатичний
доступний і симпатичний

Насправді ми не збираємося оформляти текст, що знаходиться всередині елемента label, але ми повинні створити необхідні взаємозв’язки, щоб прибрати візуальний відгук елемента input. А оформлення радіокнопки, по суті, переміститься на псевдо-елемент ::before у тега span.

Щоб сховати радіокнопку, потрібно лише застосувати правильну техніку, наприклад, таку, як та, що була знайдена мною в CSS код HTML5 шаблону Boilerplate:

[type=»radio»] {
border: 0;
clip: rect(0 0 0 0);
height: 1px; margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}

Так, але якщо вона буде захована, то як же комусь вдасться кликнути по ній? Після переміщення радіокнопки всередину тега label, браузери перетворюють тег label в такий перемикач. Це хороша практика, т. к. у будь-якому випадку вона розширює область попадання» і без того маленького елемента управління.

Оформлення

Як вже згадувалося раніше, ми будемо використовувати псевдо-контент, щоб підробити нашу «радіокнопку». І це дозволить нам використовувати оформлення тексту в елементі label окремо.

[type=»radio»] + span::before {
content: «;
display: inline-block;
width: 1em;
height: 1em;
vertical-align: -0.25 em;
border-radius: 1em;
border: 0.125 em solid #fff;
box-shadow: 0 0 0 0.15 em #000;
margin-right: 0.75 em;
transition: 0.5 s ease all;
}

Зверніть увагу на використання властивостей border й box-shadow для створення концентричних кіл. Стиль зазначеної кнопки плавно змінюється за рахунок розтягування радіусу тіні і прояви зеленого кольору. Щось на зразок цього зазвичай задається при використанні змінних в Sass.

[type=»radio»]:checked + span::before {
background: green;
box-shadow: 0 0 0 0.25 em #000;
}

Ніколи не забувайте

Все, що залишилося, — це додати стилів для фокуса, щоб ті, хто користується клавіатурою, могли побачити, який елемент вибрано. Було б досить додавання властивості outline зі значенням thin dotted для елемента span, але я волів додати стрілку в кодуванні Unicode, що вказує на елемент, за допомогою псевдо-класу ::after. Таке оформлення є більш виразним, ніж те, яке надається виробниками браузерів за замовчуванням. Воно допомагає поліпшити доступність в стані фокуса.

[type=»radio»]:focus + span::after {
content: ‘\0020\2190’;
font-size: 1.5 em;
line-height: 1;
vertical-align: -0.125 em;
}

Браузер IE8

IE8 — це, звичайно, проблема, оскільки він не підтримує ні псевдо-клас checked, ні властивості box-shadow і border-radius, з допомогою яких ми оформили наші кнопки. Підтримка селекторів може бути поліпшена за допомогою такої бібліотеки, як, наприклад, Selectivizr, а стилі можуть бути додані різними способами (можливо, з допомогою фонового зображення?), але особисто я віддаю перевагу слідувати принципам відмовостійкості (graceful degradation). Препроцессоры Sass або LESS можуть швидко ізолювати проблематичні ділянки коду.

Зверніть увагу, що такі поліпшення для тега label, як властивість cursor: pointer, застосовуються до всіх браузерів.

/* По одній радиокнопке на рядку */
label {
display: block;
cursor: pointer;
line-height: 2.5;
font-size: 1.5 em;
}
:not(.lt-ie9) {
/* стилі для приховування елемента в HTML5 шаблоні Boilerplate */
[type=»radio»] {
border: 0;
clip: rect(0 0 0 0);
height: 1px; margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
[type=»radio»] + span {
display: block;
}
/* стилі для звичайного, неотмеченного стану */
[type=»radio»] + span::before {
content: «;
display: inline-block;
width: 1em;
height: 1em;
vertical-align: -0.25 em;
border-radius: 1em;
border: 0.125 em solid #fff;
box-shadow: 0 0 0 0.15 em #000;
margin-right: 0.75 em;
transition: 0.5 s ease all;
}
/* стилі для зазначеного стану з використанням псевдо-класу :checked */
[type=»radio»]:checked + span::before {
background: green;
box-shadow: 0 0 0 0.25 em #000;
}
/* ніколи не забувайте про стилі для стану фокуса */
[type=»radio»]:focus + span::after {
content: ‘\0020\2190’;
font-size: 1.5 em;
line-height: 1;
vertical-align: -0.125 em;
}
}

Висновок

Ось ви і отримали рішення для створення власних радіокнопок, яке використовує повний набір…

HTML

CSS

… і нічого з цього:

JavaScript

WAI-ARIA

«Винахід велосипеда»

«Танці з бубном»

І, природно, дана техніка може також застосовуватися для елементів checkbox, але ви повинні уважно продумати оформлення для вибраного (відзначеного) стану. Отже, що ви думаєте? Звичайні символи Unicode? Иконочный шрифт? Фонове зображення? Або, може бути, фігура, створена на чистому CSS?