Создание интерактивного редактора аватаров CSS с нулем строк JS

В этом посте рассматривается интерактивность CSS, показаны некоторые приемы, которые можно использовать для создания простого редактора аватаров без какого-либо JavaScript. Это было забавно реализовать, и я надеюсь, что будет также забавно прочитать & попробовать. При этом я бы не рекомендовал никому использовать это в производстве. 😊

Интерактивность с помощью CSS

Селектор псевдокласса CSS :checked может быть использован для добавления базового уровня интерактивности на страницу без использования JavaScript. Это специальный селектор, который включается и выключается, когда пользователь переключает флажок или радиокнопку. Например, в следующем фрагменте отмеченный флажок становится в два раза больше, чем не отмеченный:

input:checked {
    transform : scale(2);
}

Войти в полноэкранный режим Выйти из полноэкранного режима

Что выглядит следующим образом:

Привязав метку к флажку или радиокнопке (используя id и for), вы также можете нажать на метку, чтобы переключить флажок:

<input type="checkbox" id="box" />
<label for="box">Click label to toggle</label>

Войти в полноэкранный режим Выйти из полноэкранного режима

Используя комбинаторы CSS sibling, вы можете воздействовать на метку при переключении флажка:

input:checked + label {
    background : orangered;
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Если вы затем скроете флажок, его все равно можно будет переключить с помощью метки. Это открывает интересные возможности, как в этих примерах с использованием только CSS, найденных на CodePen:

  • Tabs
  • меню гамбургера
  • Игра с укладкой блоков

Построение элемента управления диапазоном только на CSS

Редактор аватара, показанный вверху, использует набор элементов управления диапазоном, чтобы повлиять на внешний вид аватара. Чтобы сделать это без использования JavaScript, мы не можем использовать <input type="range">. Вместо этого мы должны создать свой собственный, используя описанные выше приемы.

Каждый сегмент диапазона будет представлен радиокнопкой и меткой. Метка будет стилизована под сегмент элемента управления диапазона. Ниже приведен HTML, определяющий элемент управления диапазоном с 4 сегментами:

<div class="range">
    <input type="radio" id="range4" name="range">
    <label for="range4"></label>
    <input type="radio" id="range3" name="range">
    <label for="range3"></label>
    <input type="radio" id="range2" name="range" checked>
    <label for="range2"></label>
    <input type="radio" id="range1" name="range">
    <label for="range1"></label>
</div>

Вход в полноэкранный режим Выход из полноэкранного режима

Без стилей мы никого не обманем:

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

.range {
    display : flex;
}

/* Hide the radio buttons */
.range input {
    display : none; 
}

/* Style labels to look like a solid range control track */
.range label {
    width : 16px;
    height : 6px;
    background : #efefef;
    border-block : 1px solid #b2b2b2;
    display : flex;
    cursor : pointer;
    align-items : center;
}

.range label:first-of-type {
    border-radius : 6px 0 0 6px;
    border-inline-start : 1px solid #b2b2b2;
}

.range label:last-of-type {
    border-radius : 0 6px 6px 0;
    border-inline-end : 1px solid #b2b2b2;
}

Вход в полноэкранный режим Выход из полноэкранного режима

В результате получаем следующее:

Чтобы выделить текущее значение, мы используем :checked и стилизуем псевдоэлемент для метки, который будет выполнять роль большого пальца:

Теперь перейдем к самому сложному: мы также хотим выделить часть дорожки перед большим пальцем. Проблема в том, что не существует CSS-комбинатора (пока, во всяком случае, не существует) для выделения предыдущих братьев и сестер. Изменив порядок элементов в DOM, мы можем выделить то, что визуально кажется предыдущими братьями и сестрами с помощью комбинатора ~ 😵💫.

.range {
    /* Reverse element order */
    flex-direction : row-reverse;
    /* Move them back to the left */
    justify-content : flex-end;
}

Вход в полноэкранный режим Выход из полноэкранного режима

Беспорядок:

Первый сегмент теперь последний и наоборот, также нужно поменять местами селекторы :first-of-type и :last-of-type, чтобы внешний вид снова стал правильным:

И напоследок добавим выделение дорожки (это стало возможным благодаря инверсии, описанной выше):

.range :checked ~ label {
    background : #0075ff;
    border-color : #4b76bb;
}

Вход в полноэкранный режим Выход из полноэкранного режима

Выглядит как элемент управления диапазоном!

Использование регулятора диапазона для интерактивности

Хотя вышеупомянутый элемент управления диапазоном выглядит красиво и является интерактивным, мы должны использовать его для манипулирования чем-то другим 🤔. Мы можем (в настоящее время) воздействовать только на родственные элементы, снова используя комбинатор ~. Поэтому мы должны поместить еще один элемент во внешний элемент .range.

<div class="range">
    <!-- Existing range markup -->

    <div class="avatar"></div>
</div>

Вход в полноэкранный режим Выйти из полноэкранного режима

И использовать еще немного CSS-магии, здесь для масштабирования аватара в зависимости от значения диапазона (используя переменные CSS):

/* Represent the leftmost value, since we reversed the elements */
:nth-of-type(4):checked ~ .avatar {
    --avatar-size : 0.5;
}

:nth-of-type(3):checked ~ .avatar {
    --avatar-size : 0.75;
}

:nth-of-type(2):checked ~ .avatar {
    --avatar-size : 1;
}

/* Rightmost value */
:nth-of-type(1):checked ~ .avatar {
    --avatar-size : 1.25;
}

.avatar {
    /* Lots of CSS here to make the avatar look like a dog */

    transform : scale(var(--avatar-size));
}

Войти в полноэкранный режим Выход из полноэкранного режима

Попробуйте:

Вот и все! 🎉 Используя приведенные в посте приемы, можно создать полноценный редактор аватара, показанный сверху, обязательно посмотрите его на CodePen. Если вы уже используете подобные приемы в своем приложении, мы будем рады услышать об этом.

PS. В недалеком будущем мы сможем использовать селектор :has() для воздействия на элемент, который не является прямым братом или сестрой (мы также сможем избежать реверсирования элементов с его помощью). Следите за будущим обновлением с его использованием ⭐.

Оцените статью
devanswers.ru
Добавить комментарий