ButtonsSwitches

Новые свойства CSS (CSS3) дают невероятные возможности для творчества и полета фантазии. Мне особенно нравится проектирование и создание элементов пользовательского интерфейса, таких как кнопки, переключатели и тому подобное. В этой статье я покажу вам, как создать кнопку-переключатель при помощи только CSS, без единой строчки JavaScript.

Несколько замечаний, прежде чем начнем: 

  • Я не буду добавлять префиксы браузеров в примеры CSS-кода, но вы можете найти их в исходных файлах.
  • Мы не будем использовать множество переходов между различными состояниями кнопок, потому что мы будем использовать псевдо-элементы для уменьшения количества html-элементов до минимума, а только Firefox поддерживает переходы/анимацию для псевдо-элементов.
  • Мы будем использовать "checkbox hack" (см. ниже).

Лично я использую бокс-модель где [width] = [element-width] + [padding] + [borders]. Я активировал её при помощи следующего кода:

*,
*:after,
*:before {
    box-sizing: border-box;
}

О "Checkbox Hack"

Сheckbox hack позволяет нам иметь обработчик переключателя на чистом CSS. Он основывается на чекбоксе (который либо отмечен, либо неотмечен), псевдо-селекторе :checked, и родственном селекторе (~ или +). Если вкратце, то его можно описать так: "если чекбокс отмечен, то следующий элемент X ведет себя определенным заранее образом".

Раньше для таких целей использовали чекбокс с ID и тегом label, c атрибутом "for", ссылающимся на ID чекбокса. Этот метод позволял скрыть чекбокс и переключать его, нажав на label. Единственная проблема с этим подходом это то, что мобильный Safari не поддерживает его.

Поэтому мы будем использовать другой способ: делаем чекбокс невидимым, устанавливаем его выше других элементов (z-index:100), в нашем случае выше label, и затем когда вы кликаете на тег label, то на самом деле вы отмечаете чекбокс! Код выглядит следующим образом:

.switch input {
    /* Вначале делаем его равным размеру контейнера, в котором он находится */
    position: absolute;
    width: 100%;
    height: 100%;
    /* Затем, перемещаем его вверх, относительно других элементов */
    z-index: 100;
    /* Делаем его невидимым */
    opacity: 0;
    /* А это для эргономичности */
    cursor: pointer;
}

Эти 12 строк CSS-кода будут использоваться во всех последующих примерах, без изменений.

Пример 1

Пример 1

Давайте начнем с красивой небольшой кнопки, с небольшим горящим индикатором, когда она отмечена.

Разметка

<div class="switch">
    <input type="checkbox">
    <label></label>
</div>

Элемент .switch - это наш контейнер. Внутри этого элемента находится тег input и тег label. Для тега input достаточно указать только тип checkbox (ID, name не нужны).

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

CSS

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

.switch {
    width: 100px;
    height: 100px;
    position: relative;
}

Затем зададим стили для тега label. Прежде всего, установим его размеры равные размерам его родителя (контейнер). Затем, зададим ему относительное позиционирование для того, чтобы добавить позже некоторые псевдо-элементы.

.switch label {
    display: block;
    width: 100%;
    height: 100%;
    position: relative;
    border-radius: 50%;
    background: #eaeaea;
    box-shadow:
        0 3px 5px rgba(0,0,0,0.25),
        inset 0 1px 0 rgba(255,255,255,0.3),
        inset 0 -5px 5px rgba(100,100,100,0.1),
        inset 0 5px 5px rgba(255,255,255,0.3);
}

Затем, при помощи псевдо-элемента :after добавим кнопке реалистичности, нарисуем круглую рамку, добавим градиент и тени.

.switch label:after {
    content: "";
    position: absolute;
    z-index: -1;
    top: -8%;
    right: -8%;
    bottom: -8%;
    left: -8%;
    border-radius: inherit;
    background: #ddd; /* Fallback */
    background: linear-gradient(#ccc, #fff);
    box-shadow:
        inset 0 2px 1px rgba(0,0,0,0.15),
        0 2px 5px rgba(200,200,200,0.1);
}

Теперь добавим индикатор состояния кнопки. Это будет маленький круг, размещенный в середине кнопки.

.switch label:before {
    content: "";
    position: absolute;
    width: 20%;
    height: 20%;
    left: 40%;
    top: 40%;
    border-radius: inherit;
    background: #969696; /* Fallback */
    background: radial-gradient(40% 35%, #ccc, #969696 60%);
    box-shadow:
        inset 0 2px 4px 1px rgba(0,0,0,0.3),
        0 1px 0 rgba(255,255,255,1),
        inset 0 1px 0 white;
}

Итак, теперь у нас есть симпатичная кнопка. Давайте разбираться с отмеченным состоянием кнопки. Когда вы нажимаете на контейнер, вы на самом деле нажимаете на невидимый чекбокс, который находится над тегом label. Если вы отметили чекбокс, это означает, что вы можете использовать селектор :checked и родственный селектор.

Таким образом, когда кнопка включена, мы изменим цвет фона индикатора (псевдо-элемент :before), а также фон кнопки.

.switch input:checked ~ label { /* Button */
    background: #e5e5e5; /* Fallback */
    background: linear-gradient(#dedede, #fdfdfd);
}
 
.switch input:checked ~ label:before { /* LED */
    background: #25d025; /* Fallback */
    background: radial-gradient(40% 35%, #5aef5a, #25d025 60%);
    box-shadow:
        inset 0 3px 5px 1px rgba(0,0,0,0.1),
        0 1px 0 rgba(255,255,255,0.4),
        0 0 10px 2px rgba(0, 210, 0, 0.5);
}

Пример 2

Пример 2

В этом примере мы сделаем переключатель, похожий на те, которые используются в каждом доме для включения\выключения света.

Разметка

Разметка такая же, как и в первом примере: контейнер, чекбокс и этикетка:

<div class="switch">
    <input type="checkbox">
    <label></label>
</div>

CSS

Начнем с установки размера нашей кнопки.

.switch {
    width: 50px;
    height: 100px;
    position: relative;
}

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

.switch label {
    display: block;
    width: 100%;
    height: 100%;
    position: relative;
    background: #cbc7bc;
    border-radius: 5px;
    box-shadow:
        inset 0 1px 0 white,
        0 0 0 1px #999,
        0 0 5px 1px rgba(0,0,0,0.2),
        0 2px 0 rgba(255,255,255,0.6),
        inset 0 10px 1px #e5e5e5,
        inset 0 11px 0 rgba(255,255,255,0.5),
        inset 0 -45px 3px #ddd;
}

Теперь давайте добавим псевдо-элементы. Первый из них предназначен для создания корпуса, второй для имитации переключения. Давайте начнем с корпуса:

.switch label:after {
    content: "";
    position: absolute;
    z-index: -1;
    top: -20px;
    left: -25px;
    bottom: -20px;
    right: -25px;
    background: #ccc; /* Fallback */
    background: linear-gradient(#ddd, #bbb);
    border-radius: inherit;
    border: 1px solid #bbb;
    box-shadow:
        0 0 5px 1px rgba(0,0,0,0.15),
        0 3px 3px rgba(0,0,0,0.3),
        inset 0 1px 0 rgba(255,255,255,0.5);
}

Второй более интересен, так как у нас есть только один элемент для создания двух состояний. Используем для этого box-shadow!

.switch label:before {
    content: "";
    position: absolute;
    width: 8px;
    height: 8px;
    top: -13px;
    left: 20px;
    background: #666;
    border-radius: 50%;
    box-shadow:
        0 1px 0 white, /* Subtle reflection on the bottom of the hole */
        0 120px 0 #666, /* Faking a second screw hole... */
        0 121px 0 white; /* And its reflection */
}

В этом примере только центральная часть (которая является тегом label) будет изменяться, когда мы щелкнем по кнопке. И мы создали этот эффект при помощи box-shadow:

.switch input:checked ~ label { /* Button */
    background: #d2cbc3;
    box-shadow:
        inset 0 1px 0 white,
        0 0 0 1px #999,
        0 0 5px 1px rgba(0,0,0,0.2),
        inset 0 -10px 0 #aaa,
        0 2px 0 rgba(255,255,255,0.1),
        inset 0 45px 3px #e0e0E0,
        0 8px 6px rgba(0,0,0,0.18);
}

Пример 3

Пример 3

Давайте попробуем создать пример еще круче. Он взят из прекрасного дизайна  от талантливого Piotr Kwiatkowski. Это выглядит очень симпатично, не так ли?

Разметка

Для этого переключателя, нам нужен будет дополнительный элемент. Используем для этой цели тег <i>.

<div class="switch">
    <input type="checkbox">
    <label><i></i></label>
</div>

CSS

Итак, еще раз, мы скрываем чекбокс и задаем размеры для контейнера.

.switch {
    width: 180px;
    height: 50px;
    position: relative;
}

Затем мы собираемся сделать следующее: label будет контейнером для переключателя. А тег <i> и будет фактически переключателем. Поэтому тег label будет иметь только серый фон с тенями, не более того. Псевдо-элементы сделают все остальное.

.switch label {
    display: block;
    width: 100%;
    height: 100%;
    position: relative;
    background: #a5a39d;
    border-radius: 40px;
    box-shadow:
        inset 0 3px 8px 1px rgba(0,0,0,0.2),
        0 1px 0 rgba(255,255,255,0.5);
}

Это "рамка контейнера", поэтому мы задаем ей приятный градиент и некоторые тени для блока.

.switch label:after {
    content: "";
    position: absolute;
    z-index: -1;
    top: -8px; right: -8px; bottom: -8px; left: -8px;
    border-radius: inherit;
    background: #ccc; /* Fallback */
    background: linear-gradient(#f2f2f2, #ababab);
    box-shadow: 0 0 10px rgba(0,0,0,0.3),
        0 1px 1px rgba(0,0,0,0.25);
}

Этот псевдо-элемент предназначен для создания мягкого углубления вокруг кнопки, для этого мы будем использовать градиент и тени. Небольшое улучшение для Chrome с помощью фильтра blur, чтобы сделать эффект еще мягче.

.switch label:before {
    content: "";
    position: absolute;
    z-index: -1;
    top: -18px; right: -18px; bottom: -18px; left: -18px;
    border-radius: inherit;
    background: #eee; /* Fallback */
    background: linear-gradient(#e5e7e6, #eee);
    box-shadow: 0 1px 0 rgba(255,255,255,0.5);
    -webkit-filter: blur(1px); /* Smooth trick */
    filter: blur(1px); /* Future-proof */
}

Итак, теперь у нас есть очень красивая рамка для наших переключателей. Теперь перейдем к самим переключателям.

Сделаем его блочным элементом, зададим ему высоту его родителя и немного больше чем половину ширины родителя. Мы поместим его слева от контейнера, и зададим ему некоторые стили (тени и градиенты):

.switch label i {
    display: block;
    height: 100%;
    width: 60%;
    position: absolute;
    left: 0;
    top: 0;
    z-index: 2;
    border-radius: inherit;
    background: #b2ac9e; /* Fallback */
    background: linear-gradient(#f7f2f6, #b2ac9e);
    box-shadow:
        inset 0 1px 0 white,
        0 0 8px rgba(0,0,0,0.3),
        0 5px 5px rgba(0,0,0,0.2);
}

Этот первый псевдо-элемент используется для улучшения эстетики: он добавляет симпатичный эффект переключения.

.switch label i:after {
    content: "";
    position: absolute;
    left: 15%;
    top: 25%;
    width: 70%;
    height: 50%;
    background: #d2cbc3; /* Fallback */
    background: linear-gradient(#cbc7bc, #d2cbc3);
    border-radius: inherit;
}

Вторым псевдо-элементом является слово "ON" или "OFF", в зависимости от состояния кнопки. Мы используем свойство content, чтобы установить нужное слово, и некоторые стили для шрифтов, чтобы она выглядела, как будто она выгравирована на фоне:

.switch label i:before {
    content: "off";
    position: absolute;
    top: 50%;
    right: -50%;
    margin-top: -12px;
    color: #666; /* Fallback */
    color: rgba(0,0,0,0.4);
    font-style: normal;
    font-weight: bold;
    font-family: Helvetica, Arial, sans-serif;
    font-size: 24px;
    text-transform: uppercase;
    text-shadow: 0 1px 0 #bcb8ae, 0 -1px 0 #97958e;
}

Теперь у нас есть тумблер, который выглядит точно также как нарисовал Piotr, верно?

Теперь займемся состоянием кнопки, когда она "включена". Три вещи будут изменяться когда мы нажмем на флажок: цвет фона, переключение позиции, и слово ("ON" или "OFF"):

.switch input:checked ~ label { /* Background */
    background: #9abb82;
}
 
.switch input:checked ~ label i { /* Toggle */
    left: auto;
    right: -1%;
}
 
.switch input:checked ~ label i:before { /* On/off */
    content: "on";
    right: 115%;
    color: #82a06a;
    text-shadow: 0 1px 0 #afcb9b, 0 -1px 0 #6b8659;
}

Пример 4

Пример 4

Наш последний пример основан на другой работе от Piotr Kwiatkowski, но немного отредактированной мною, чтобы иметь те же цвета, что и другие примеры.

Разметка

Разметка будет почти такой же, как в третьем примере. Класс для тега <i> нужен для того, чтобы использовать FontAwesome.

<div class="switch">
    <input type="checkbox">
    <label><i class="icon-off"></i></label>
</div>

CSS

Я не буду описывать здесь все возможности FontAwesome, потому что я уверен, что многие уже работали с ним. Просто убедитесь, что

  • в вашем @font-face указан правильный путь к файлам,
  • один из ваших CSS-файлов включает в себя стили FontAwesome.

Итак, давайте начнем с основ: спрячем чекбокс и установим размеры контейнера:

.switch {
    width: 150px;
    height: 150px;
    position: relative;
}

Теперь, давайте позаботимся о этикетке, которая и будет нашей большой кнопкой. Обратите внимание, что мы включаем сюда некоторые стили для шрифтов. Поскольку все они наследуются, они будут применены к тегу <i> (значок).

.switch label {
    display: block;
    width: 100%;
    height: 100%;
    position: relative;
    color: #a5a39d;
    font-size: 70px;
    text-align: center;
    line-height: 115px;
    text-shadow: 0 2px 1px rgba(0,0,0,0.25);
    border-radius: 50%;
    background: #b25244; /* Fallback */
    background: linear-gradient(#f7f2f6, #b2ac9e);
    transition: all 0.3s ease-out;
    z-index: -1;
    box-shadow:
        inset 0 2px 3px rgba(255,255,255,0.13),
        0 5px 8px rgba(0,0,0,0.3),
        0 10px 10px 4px rgba(0,0,0,0.3);
}

Оба псевдо-элемента для этикетки используются для создания симпатичного эффекта вокруг кнопки. Мы применяем фильтр размытия для :before, чтобы сделать его немного более тонким.

.switch label:before {
    content: "";
    position: absolute;
    left: -10px;
    right: -10px;
    top: -10px;
    bottom: -10px;
    z-index: -1;
    border-radius: inherit;
    box-shadow: inset 0 10px 10px rgba(0,0,0,0.13);
    -webkit-filter:blur(1px); /* Smooth trick */
    filter: blur(1px); /* Future-proof */
}
 
.switch label:after {
    content: "";
    position: absolute;
    left: -20px;
    right: -20px;
    top: -20px;
    bottom: -20px;
    z-index: -2;
    border-radius: inherit;
    box-shadow:
        inset 0 1px 0 rgba(255,255,255,0.1),
        0 1px 2px rgba(0,0,0,0.3),
        0 0 10px rgba(0,0,0,0.15);
}

Теперь разберемся с нашими дополнительным элементом: <i>. FontAwesome использует :before псевдо-элемент, чтобы показать иконку, поэтому мы не можем его использовать. Но мы можем использовать :after, и мы так и поступим, потому что мы должны что-то сделать с верхней частью нашей кнопки.
Как обычно, мы зададим ей симпатичный градиент, тонкие тени с 1px размытия, чтобы сделать ее более гладкой.

.switch .icon-off:after {
    content: "";
    display: block;
    position: absolute;
    width: 70%;
    height: 70%;
    left: 50%;
    top: 50%;
    z-index: -1;
    margin: -35% 0 0 -35%;
    border-radius: 50%;
    background: #d2cbc3; /* Fallback */
    background: linear-gradient(#cbc7bc, #d2cbc3);
    box-shadow:
        0 -2px 5px rgba(255,255,255,0.05),
        0 2px 5px rgba(255,255,255,0.1);
    -webkit-filter:blur(1px); /* Smooth trick */
    filter: blur(1px); /* Future-proof */
}

Теперь стили для отмеченного состояния: значок становится зеленым, а кнопка выглядит нажатой:

.switch input:checked ~ label { /* Button */
    color: #9abb82;
    box-shadow:
        inset 0 2px 3px rgba(255,255,255,0.13),
        0 5px 8px rgba(0,0,0,0.35),
        0 3px 10px 4px rgba(0,0,0,0.2);
}

Спасибо за внимание, надеюсь вам понравилось

Демонстрация

Скачать исходные файлы

Перевод статьи с http://tympanus.net


Если у Вас возникли вопросы, то для скорейшего получения ответа рекомендуем воспользоваться нашим форумом

Комментарии  

#1 Dim Yanush 30.09.2012 06:36
В высшей степени интересная и актуальная статья. Вместо того. чтобы налегать на Фотошоп, самое время уделить внимание изучению CSS3. Результаты завораживают.
+2 #2 Сергей 05.03.2013 06:47
Спасибо за отличную статью. В шоке что можно рисовать относительно небольшим кодом CSS3.
Но как всегда осел портит картину - много людей им еще пользуется

You have no rights to post comments