Статьи

Замена кнопок радио без замены кнопок радио

Формирует элементы! Они боль в стиле, не так ли? Заманчиво полностью заменить их на какую-то пользовательскую разметку и CSS нашего собственного дизайна. Беда в том, что у получающегося в результате крысиного гнезда divspantype="radio"

 <div class="radio-label">
  <div class="radio-input" data-checked="false" data-value="accessible"></div>
  accessibility?
</div>

Это всего лишь одинокий фрагмент текста с надписью «доступность». Действительно, трагично. Чтобы это снова начало работать правильно, нам нужно добавить все виды исправительной семантики WAI-ARIA. В бессмертных словах Iron Maiden: « Могу ли я играть с безумием? »

 <div class="radio-label" id="accessible-radio">
  <div class="radio-input" data-checked="false" data-value="accessible" 
       aria-labelledby="accessible-radio" role="checkbox" aria-checked="false">
  </div>
  accessibility?
</div>

Наш пример все еще на сто процентов недоступен, потому что нам еще предстоит обойти все обычные поведения и привязки клавиш, установленные стандартным type="radio" Это потребует атрибута tabindexchecked Я даже не собираюсь идти по этому пути.

То, что я сделал, доступно в виде демонстрационной версии CodePen , и последующее объяснение этой методики.

Примечание. Если вы ранее не использовали радиокнопки на клавиатуре, знайте, что вы можете сфокусировать активную кнопку с помощью клавиши TAB и изменить активную кнопку с помощью клавиш со стрелками ВВЕРХ и ВНИЗ. Это стандартное поведение UA, а не эмуляция JavaScript.

Используйте то, что уже есть

Чтобы мыслить доступно, вы должны рассматривать HTML как интерфейс, а CSS — только внешний вид этого интерфейса; брендинг. Соответственно, нам нужно искать способы взять под контроль эстетику пользовательского интерфейса, не полагаясь на воссоздание базовой разметки, которая знаменует собой отход от стандартов.

Что мы знаем о радиокнопках?

Одна вещь, которую мы знаем о переключателях, это то, что они могут быть либо в проверенном, либо в нерабочем состоянии. Не берите в голову ARIA, это просто <label for="accessible">
<input type="radio" value="accessible" name="quality" id="accessible"> accessible
</label>

<label for="pretty">
<input type="radio" value="pretty" name="quality" id="pretty"> pretty
</label>

<label for="accessible-and-pretty">
<input type="radio" value="pretty"
name="quality" id="accessible-and-pretty" checked>
accessible and pretty
</label>

 :checked

К счастью, мы можем выразить проверенное состояние через псевдокласс [type="radio"]:checked {
/* styles here */
}

 [type="radio"]:checked + span {
   /* styles for a span proceeded by a checked radio button */
}

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

Соседний братский комбинатор

Я люблю соседний братский комбинатор со страстью, которую мужчина, возможно, не должен резервировать для выражений селектора CSS. Это позволяет мне стилизовать элементы в соответствии с природой предшествующих им элементов.

Это мощное понятие в отношении наших радиокнопок, потому что оно позволяет нам отложить появление изменений состояния на элементы, которые на самом деле можно легко стилизовать.

 span

Нам, конечно, придется добавить элементы разметки в разметку, но хуже HTML может стать и HTML.

 <fieldset>
  <legend>Radio Control Quality</legend>
  <label for="accessible">
    <input type="radio" value="accessible" name="quality" id="accessible"> 
    <span>accessible</span>
  </label>

  <label for="pretty">
    <input type="radio" value="pretty" name="quality" id="pretty"> 
    <span>pretty</span>
  </label>

  <label for="accessible-and-pretty">
    <input type="radio" value="pretty" name="quality" id="accessible-and-pretty" checked> 
    <span>accessible and pretty</span>
  </label>
</fieldset>

Мы не хотим на самом деле стилизовать текст метки, но мы создали необходимые отношения, чтобы отодвинуть визуальную обратную связь от <input> Стилизация переключателя будет фактически отложена <span>::before[type="radio"] {
border: 0;
clip: rect(0 0 0 0);
height: 1px; margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}

Скрытие переключателя — это всего лишь случай использования доступной техники сокрытия, подобной той, что есть в CSS HTML5 Boilerplate :

 <label>

Но если он скрыт, как кто-нибудь может щелкнуть по нему? Вложив переключатель в <label>[type="radio"] + span::before {
content: '';
display: inline-block;
width: 1em;
height: 1em;
vertical-align: -0.25em;
border-radius: 1em;
border: 0.125em solid #fff;
box-shadow: 0 0 0 0.15em #000;
margin-right: 0.75em;
transition: 0.5s ease all;
}
В любом случае, это хорошая техника, потому что она увеличивает «зону попадания» в противном случае уменьшительного контроля.

Стиль

Как упоминалось ранее, мы будем использовать псевдоконтент для подделки нашей «радиокнопки». Таким образом, мы можем обрабатывать стиль текста метки отдельно.

 border

Обратите внимание на использование box-shadow[type="radio"]:checked + span::before {
background: green;
box-shadow: 0 0 0 0.25em #000;
}
Выбранный стиль впоследствии изменяет разброс радиуса тени блока и включает зеленый на / правильный / выбранный / положительный цвет; вид, который обычно определяется где-то в ваших переменных Sass.

 outline

Никогда не забывай

Осталось только включить стиль фокуса, чтобы пользователи клавиатуры могли видеть, какой элемент находится под их контролем. thin dotted<span>::after[type="radio"]:focus + span::after {
content: '\0020\2190';
font-size: 1.5em;
line-height: 1;
vertical-align: -0.125em;
}
Эта визуальная обратная связь более убедительна, чем поставщики браузеров по умолчанию, помогая повысить доступность состояния фокуса.

 checked

IEH8

IE8 создает проблему, потому что он не поддерживает ни box-shadowborder-radiuslabel Поддержка селектора может быть заполнена такой библиотекой, как Selectivizr, а стили могут обрабатываться по-разному (возможно, фоновое изображение?), Но моя предпочтительная стратегия, вероятно, заключалась бы в использовании постепенной деградации. Sass или LESS могут кратко изолировать проблемные блоки объявлений.

Обратите внимание, что улучшения для cursor: pointer/* One radio button per line */
label {
display: block;
cursor: pointer;
line-height: 2.5;
font-size: 1.5em;
}

:not(.lt-ie9) {

/* HTML5 Boilerplate accessible hidden styles */
[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;
}

/* the basic, unchecked style */
[type="radio"] + span::before {
content: '';
display: inline-block;
width: 1em;
height: 1em;
vertical-align: -0.25em;
border-radius: 1em;
border: 0.125em solid #fff;
box-shadow: 0 0 0 0.15em #000;

margin-right: 0.75em;
transition: 0.5s ease all;
}

/* the checked style using the :checked pseudo class */
[type="radio"]:checked + span::before {
background: green;
box-shadow: 0 0 0 0.25em #000;
}

/* never forget focus styling */
[type="radio"]:focus + span::after {
content: '\0020\2190';
font-size: 1.5em;
line-height: 1;
vertical-align: -0.125em;
}
}

 checkbox

Вывод

Вот оно, решение для радиоуправляемых тем, которое использует все это…

  • HTML
  • CSS

… и ничего из этого:

  • JavaScript
  • WAI-ARIA
  • Колесо изобретать
  • шаман

Естественно, базовая техника может быть применена и к элементам управления флажками, но вы должны помнить о дизайне чеков (тиков). Так что ты думаешь? Простой юникод? Иконка шрифта? Фоновая картинка? Или, может быть, форма, созданная полностью в CSS?