Пользовательские radio / checkbox кнопки с выравниванием

Пользовательские radio / checkbox кнопки с выравниванием

От автора: создание пользовательских кнопок radio / checkbox — непростая задача. Они должны быть доступными, легко настраиваемыми и идеально согласованными с метками.

Вот предварительный просмотр окончательного результата (загрузите компонент пользовательского интерфейса CodyHouse):

Важное правило, которого я стараюсь придерживаться при создании компонентов — начинать с простейшей структуры и добавлять дополнительные элементы (например, родительские контейнеры) только в случае необходимости. Вот все, что нам нужно для переключателей и чек-боксов:

<!-- radio button -->
<div> <input class="radio" type="radio" name="radio-button" id="radio-1"> <label for="radio-1">Choice 1</label>
</div> <!-- checkbox button -->
<div> <input class="checkbox" type="checkbox" id="checkbox-1"> <label for="checkbox-1">Option 1</label>
</div>

Структура HTML идентична той, которую мы использовали бы с нативными кнопками, за исключением того, что мы добавляем класс .radio / .checkbox.

Шаг 1 — визуально скрыть нативные кнопки:

// hide native buttons
.radio,
.checkbox { position: absolute; margin: 0 !important; padding: 0 !important; opacity: 0; height: 0; width: 0; pointer-events: none;
}

Если вы не установите значения top / right / bottom / left для элементов, они удаляются из потока, но не перемещаются. Это важно, потому что в противном случае их положение было бы непредсказуемым и могло бы вызвать прокрутку страницы вверх при нажатии кнопок.

Затем мы собираемся использовать селектор + для выбора и стилизации меток и их псевдо-элементов ::before (пользовательские кнопки):

// label
.radio + label,
.checkbox + label { user-select: none; cursor: pointer; line-height: 1.4;
} // custom buttons - basic style
.radio + label::before,
.checkbox + label::before { content: ''; display: inline-block; width: 18px; height: 18px; background-color: var(--color-bg); border: 2px solid var(--color-contrast-low); margin-right: var(--space-xxxs); // gap between custom input and label transition: .2s;
} // radio only style
.radio + label::before { border-radius: 50%; } // checkbox only style
.checkbox + label::before { border-radius: 4px;
}

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

:root { // radios and checkboxes --checkbox-radio-size: 18px; --checkbox-radio-gap: var(--space-xxxs); // gap between button and label --checkbox-radio-border-width: 2px; --checkbox-radio-line-height: var(--body-line-height); // radio buttons --radio-marker-size: 8px; // checkboxes --checkbox-marker-size: 12px; --checkbox-radius: 4px;
} // replace fixed values with variables - example
.checkbox + label::before { border-radius: var(--checkbox-radius);
}

Мы собираемся настроить таргетинг на статус элементов checked и применить стиль к псевдо-элементам меток:

// :checked
.radio:checked + label::before,
.checkbox:checked + label::before { background-color: var(--color-primary); border-color: var(--color-primary);
} // radio button :checked
.radio:checked + label::before { background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cg class='nc-icon-wrapper' fill='%23ffffff'%3E%3Ccircle cx='8' cy='8' r='8' fill='%23ffffff'%3E%3C/circle%3E%3C/g%3E%3C/svg%3E"); background-size: var(--radio-marker-size);
} // checkbox button :checked
.checkbox:checked + label::before { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpolyline points='1 6.5 4 9.5 11 2.5' fill='none' stroke='%23FFFFFF' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'/%3E%3C/svg%3E"); background-size: var(--checkbox-marker-size);
}

Мы используем свойство background-image для добавления маркеров SVG (через URI данных). Преимущество этого метода в том, что вы можете настроить в CSS толщину иконки (stroke-width=’2′) и ее цвет (stroke=’%23FFFFFF’). Что у нас есть на данный момент:

Пользовательские radio / checkbox кнопки с выравниванием

Выравнивание

А вот и самая сложная часть: совместить кнопки переключателей / чек-боксов с их метками. Сначала установите для свойства display метки inline-flex и для align-items — flex-start:

:root { // ... --checkbox-radio-gap: var(--space-xxxs); --checkbox-radio-line-height: var(--body-line-height);
} // label
.radio + label,
.checkbox + label { display: inline-flex; align-items: flex-start; // align button and label to top line-height: var(--checkbox-radio-line-height); // ...
} // custom buttons - basic style
.radio + label::before,
.checkbox + label::before { flex-shrink: 0; // prevent the button from shrinking margin-right: var(--checkbox-radio-gap); // gap // ...
}

Таким образом, мы устранили проблему выравнивания по левому краю, видимую, когда метка разбивается на несколько строк, и мы выровняли кнопки и метки по вертикали вверху:

Пользовательские radio / checkbox кнопки с выравниванием

Чтобы выровнять кнопки и метки по вертикали, нам нужно вычислить высоту метки, которая равна размеру шрифта, умноженному на высоту строки.

Пользовательские radio / checkbox кнопки с выравниванием

Высота строки сохраняется в var(—checkbox-radio-line-height). Вычисленное значение font-size для метки непредсказуемо (например, мы могли бы изменить его с помощью служебных классов), но для псевдо-элемента label ::before этот font-size всегда будет равен 1em!

Зная высоту, мы можем использовать формулу с очень конкретной величиной, которая выравнивает их с первой строкой метки.

.radio + label::before,
.checkbox + label::before { // .. position: relative; top: calc((1em * var(--checkbox-radio-line-height) - var(--checkbox-radio-size)) / 2);
}

Эта формула совместима с любыми значениями font-size и font-family. Больше никаких случайных и непредсказуемых уловок с отрицательным полем маржей!

Доступность

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

Пользовательские radio / checkbox кнопки с выравниванием

Однако не забудьте включить эффект :focus (пользовательские кнопки не видны):

// :focus
.radio:focus + label::before,
.checkbox:focus + label::before { border-color: var(--color-primary); box-shadow: 0 0 0 3px alpha(var(--color-primary), 0.2);
}

Автор: Sebastiano Guerriero

Источник: https://codyhouse.co

Редакция: Команда webformyself.