От автора: один из самых мощных и недостаточно используемых CSS-селекторов – это комбинатор общего родителя или ~. В последующих статьях я расскажу про разные способы создания не только привлекательных, но и функциональных и полезных компонентов с помощью ~. В этом уроке мы разберем с вами элементы формы: радиокнопки, чекбоксы и обычные инпуты.
Мы узнаем много нового: современные CSS-селекторы, свойство will-change, SVG-свойство stroke, состояния инпутов и многое другое!
Прежде чем начать…
Небольшой дисклеймер: представленные в статье эффекты могут работать в старых браузерах, а могут и нет. Я проверял их в последних версиях Chrome, Firefox и Safari.
Для ускорения процесса программирования я буду использовать Haml (HTML-компилятор) и Sass (CSS-препроцессор)! В демо будет использоваться Haml, а в инлайновом коде обычный HTML.
Также вместо вендорных префиксов я буду использовать замечательную библиотеку AutoPrefixer. Если вы работаете в CodePen, не забудьте перейти в настройки, кликнуть на CSS и выбрать AutoPrefixer.
Радиокнопки
Начнем мы с одного из базовых элементов формы – радиокнопки. У данного элемента есть два основных визуальных состояния (checked и unchecked), а также два промежуточных состояния (hover и click/active – click похоже визуально на checked).
Версия на SVG
Первым делом необходимо задать HTML. Нам необходим внешний контейнер и внутренний с двумя дочерними элементами: div с инпутом и визуальными элементами, а также label для инпута. В качестве внешнего контейнера я люблю использовать fieldset. Не забудьте добавить ID инпуту со значением, равным значению атрибута for на теге label.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<fieldset> <div class="container"> <div class="svg"> <input id="radio-svg" type="radio" name="option"/> <div></div> <svg viewBox="0 0 24 24"> <circle cx="12" cy="12" r="8"></circle> <circle cx="12" cy="12" r="8"></circle> </svg> </div> <label for="radio-svg">SVG</label> </div> </fieldset> |
Далее необходимо скрыть дефолтный инпут, добавить базовые стили и скрыть дополнительные элементы, которые должны показываться только после выбора радиокнопки. Идея заключается в том, чтобы сделать инпут невидимым и расположить его сверху визуальных элементов, чтобы клик по радиокнопке был похож на клик по визуальному элементу. Для этого необходимо задать position: relative для .svg и position: absolute для инпута, после чего скрыть его.
Заметка: визуальный вид можете сделать совершенно любой. Я сохранил базовый стиль кружка, имитирующего стандартную радиокнопку, только сделал ее более плоской.
С помощью Sass необходимо задать парочку переменных цвета: пара серых оттенков и светло-голубой для выбранной кнопки. Также необходимо создать переменную $p для единиц по умолчанию. У нас это будет 12px – прекрасное число, оно делится на 1, 2, 3, 4, 6.
Основные переменные я поместил напрямую во встроенное демо, остальное можно найти по ссылке или на странице в демо, кликнув на настройки в правом верхнем углу, далее вкладка CSS.
Первый кружок у нас светло-серый, второй – светло-голубой. Второй кружок скрыт с помощью transform: scale(0). Позже мы с помощью анимации вернем второй кружок, поэтому нам нужно задать первоначальное значение scale.
После всех настроек необходимо определиться со стилями всех состояний. При наведении светло-серый кружок будет становиться светло-голубым. По клику светло-голубой кружок плавно переходит в голубой, а задний фон меняется с серого на белый. Фон сохраняется для состояния checked. Убрать с кнопки состояние checked можно только, нажав на другую радиокнопку. При нажатии на другую кнопку голубой и белый цвет плавно возвращаются в исходные оттенки.
Сначала мы установим цвета, а затем анимацию, так как цвета заданы для всех состояний. Вот тут нам и понадобится ~. Селектор общего родителя (родственный комбинатор) выбирает элемент, если ему предшествует другой элемент, и у обоих есть общий родитель. Для выбора визуального элемента при наведении курсора на инпут мы используем input:hover ~ div.
Кликните на первую кнопку, затем на вторую. Вы должны четки видеть состояния hover и checked/active.
Осталось анимировать состояния. Для добавления анимации необходимо установить transition для состояния unchecked по умолчанию, а для состояния checked по клику. Для этого я воспользуюсь новым свойством will-change, чтобы дать понять браузеру, какие свойства я собираюсь анимировать.
Версия на HTML
Пользовательские радиокнопки можно сделать и без SVG. Разметка будет похожей:
1 2 3 4 5 6 7 8 9 10 11 |
<fieldset> <div class="container"> <div class="svg"> <input id="radio-html" type="radio" name="option"/> <div></div> <div></div> <div></div> </div> <label for="radio-html">HTML</label> </div> </fieldset> |
CSS остается почти тем же, добавляется немного стилей для тегов div, которые заменяют SVG-кружки. В этом случае для выбора разных div’ов (чтобы не давать им отдельные классы) мы будем использовать nth-of-type(n).
В версии на SVG меньше стилей, но больше разметки, в HTML-версии наоборот. Результат идентичен, можете использовать то, что больше нравится!
Чекбоксы
Следующий элемент, который мы будем кастомизировать – чекбокс. Состояния те же, что и у радиокнопки: два основных визуальных состояния (checked и unchecked) и два промежуточных (hover и click/active).
Версия на SVG
Разметка очень похожа, только вместо кружочка галка формируется с помощью линий.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<fieldset> <div class="container"> <div class="svg"> <input id="checkbox-svg" type="checkbox"> <div></div> <div></div> <svg viewBox="0 0 24 24"> <g> <line x1="4.5" x2="9.24" y1="12.5" y2="17.24"></line> <line x1="9.24" x2="19.76" y1="17.24" y2="6.73"></line> </g> <g> <line x1="4.5" x2="9.24" y1="12.5" y2="17.24"></line> <line x1="9.24" x2="19.76" y1="17.24" y2="6.73"></line> </g> </svg> </div> <label for="checkbox-svg">SVG</label> </div> </fieldset> |
Линии первой группы будут иметь светло-серый цвет, они не будут анимироваться. Линии второй группы будут анимироваться по клику на инпут.
Также есть дополнительный элемент div. Его мы будем использовать для создания эффекта нажатия. Этот блок будет плавно заполняться светло-голубым цветом. Чтобы эффект работал, div должен принять форму голубого круга с диаметром большим, чем ширина и высота реального чекбокса. Внешнему контейнеру необходимо задать overflow: hidden;, чтобы скрыть части круга, вылезающие за чекбокс. В круглом div’е будет изменяться transform: scale(0), как в радиокнопке.
И опять же, стиль можете задать любой. Я скруглю края галки, как, в принципе, и все углы.
Теперь необходимо подготовить анимацию. Эффекты похожи на эффекты для радиокнопки, только здесь будет не расширяющийся круг, а плавно рисующаяся галка. Для создания подобной анимации нам понадобится свойство stroke-dashoffset, которое необходимо применить к SVG-линиям.
Для анимации stroke-dashoffset необходимо знать длину линий. Я создал инструмент на CodePen для вычисления длины. Если вы используете созданные мной галки, то маленькая линия равна 6.708, а длинная – 14.873. Эти значения нам понадобятся для stroke-dashoffset и stroke-dasharray. Анимация нужна только для первой галки (второй набор линий показывается по умолчанию в состоянии unchecked).
По клику на инпут необходимо задать stroke-dashoffset в 0, что (со свойством transition) будет имитировать «рисование» линии. В другое состояние необходимо скопировать изменения из радиокнопки, в частности изменение фона по наведению и увеличение круга по клику.
Осталось добавить все плавные переходы. И опять, переходы для unchecked задаем по умолчанию, а для checked по клику. И как для круга в радиокнопке, галка будет плавно становиться светло-серой при переходе в состояние unchecked.
Версия на HTML
Тот же эффект можно воссоздать, добавив пару div’ов вместо SVG. Разметка станет проще, но не такой четкой. Первый пустой div – увеличивающийся голубой круг, второй блок – это галка по умолчанию, третий – анимируемая галка при клике.
1 2 3 4 5 6 7 8 9 10 11 |
<fieldset> <div class="container"> <div class="line"> <input id="checkbox-html" type="checkbox"> <div></div> <div></div> <div></div> </div> <label for="checkbox-html">HTML</label> </div> </fieldset> |
Для создания галки возьмем :before и :after, это упростит разметку. Можно пойти по-другому, но тогда понадобится 4 пустых элемента иди больше для создания двух галок. Линии необходимо спозиционировать и повернуть вручную. Для поворота и отрисовки линий можно использовать одну трансформацию.
Версия со специальным символом
Чтобы не вращать div’ы, можно использовать символ галки! Визуально она слегка отличается от двух других, но она работает.
1 2 3 4 5 6 7 8 9 10 11 |
<fieldset> <div class="container"> <div class="symbol"> <input id="checkbox-sym" type="checkbox"> <div></div> <div>✓</div> <div>✓</div> </div> <label for="checkbox-sym">Symbol</label> </div> </fieldset> |
Заметка: HTML-символ нужен только в последних двух div’ах, но в демо ниже я добавил его во всех три div’а, чтобы включить символ в повторяющийся цикл.
Мы не можем анимировать рисование символа, поэтому по клику будет просто плавно появляться белая галка. Все три версии можете посмотреть ниже!
Обычные инпуты
Последняя часть нашего урока – обычные текстовые инпуты. Я вдохновлялся материальным дизайном инпутов Google. У этих полей несколько состояний: по умолчанию, active/focus (когда виден мигающий курсор) и тонкое состояние hover.
Разметка еще более простая, чем в предыдущих двух примерах. У нас есть fieldset, input, label и div (рамка).
1 2 3 4 5 |
<fieldset> <input id="example" type="text"> <label for="example">Label</label> <div></div> </fieldset> |
Далее необходимо стилизовать инпут. В этот раз мы не будем прятать поле, оно должно показывать значение. Также необходимо создать лейбл, который будет плавно подниматься и опускаться по фокусу инпута. Чтобы все заработало, лейбл должен находиться прямо над инпутом. У рамки div будет псевдоэлемент :after, который поверх рамки будет рисовать линию, когда инпут получает фокус. Первоначальным значением для псевдоэлемента будет scale(0).
Попробуйте набрать текст в демо сверху. Видите, текст набирается поверх лейбла? С помощью анимации мы будем уменьшать лейбл и перемещать его вверх по клику. Всю анимацию можно выполнить с помощью трансформаций, чтобы не было перерисовок. А можете сделать как я, анимировать font-size. Я выяснил, что по font-size и translateY получается более точная анимация. Для создания эффекта рисования линии необходимо удалить scale с div:after.
Если теперь кликнуть на поле в демо сверху и ввести текст, то лейбл уменьшится и плавно передвинется вверх. Однако если оставить текст в поле и кликнуть где-либо в другом месте, лейб опустится и загородит текст. Избежать этого можно с помощью JS, а можно воспользоваться состоянием :valid.
В инпут можно добавить пустой атрибут required или же :required => true в Haml. Далее необходимо добавить состояние :valid к :focus в Sass/CSS, так мы получим дополнительное визуальное состояние для нашего инпута. Так как это простой текстовый инпут, то единственным валидным состоянием будет текст.
Заметка: эффект не работает с другими типами инпута, такими как email, так как у них другие требования по валидности.
Вдохновение
Хотите создать свои собственные инпуты по этим техникам, но не хватает вдохновения? Посмотрите UI-наборы, доступные после подписки на Envato Elements:
Заключение
Селектор с общим родителем можно использовать самыми разными способами, будь то визуальный селектор, функциональный или оба сразу. Селектор дает мощный инструментарий по настройке компонентов без необходимости подключать что-либо кроме CSS и HTML. Сегодня мы изучили три элемента формы, в следующем уроке мы рассмотрим меню и навигацию. Если у вас возникли вопросы или предложения, обязательно пишите об этом в комментариях!
Автор: Gabrielle Wee
Источник: //webdesign.tutsplus.com/
Редакция: Команда webformyself.