chevron-left chevron-right

Piotr Nalepa Frontend, architektura i AI

[CSS] Jak utworzyć animowany przycisk typu toggle button za pomocą CSS?

Ta wersja
blog.piotrnalepa.pl/2015/04/01/css-jak-utworzyc-animowany-przycisk-typu-toggle-button-za-pomoca-css
Opublikowano
Autor
, Staff Software Engineer
Kategoria
CSS
Uwagi
Napisz do mnie · Napisz na X

Ten wpis ma 11 lat. Od tego czasu przeglądarki i narzędzia mogły się zmienić, więc zanim użyjesz kodu, sprawdź go z aktualną dokumentacją.

Po dłuższym okresie braku aktywności na blogu powracam z nowym wpisem. Dzisiejszy wpis będzie dotyczył utworzenia dwustanowego przycisku, typu toggle button, którego stan będzie można zmienić za pomocą CSS, bez użycia JavaScript.

Sekcja 1Kod HTML

Aby móc wykorzystać omawiany przykład przycisku typu toggle musimy przygotować odpowiednią strukturę kodu HTML, która wygląda następująco:

Przykład 1HTML
<label class="btn-toggle">
    <input class="btn-toggle__checkbox" type="checkbox"/>
    <span class="btn-toggle__body">
        <span class="btn-toggle__body__switch"></span>
        <span class="btn-toggle__body__track">
            <span class="btn-toggle__body__track__option--view">View</span>
            <span class="btn-toggle__body__track__option--edit">Edit</span>
        </span>
    </span>
</label>

Jak można zauważyć, wykorzystałem elementy <span/> do określenia suwaka i tła pod suwakiem. Jest to związane z tym, że chciałem zachować poprawną strukturę kodu HTML, gdzie wewnątrz elementów liniowych, takich jak <label/> nie powinny się znajdować elementy blokowe (np. takie jak <div/>) tylko elementy liniowe, m.in. <span/>.

Sekcja 2Kod CSS

Mając gotowy kod HTML, możemy zabrać się do stylowania tego kodu. Za pomocą poniższego kodu określimy jak ma się zachowywać przycisk w określonych sytuacjach:

Przykład 2CSS
.btn-toggle {
    position: relative;
    z-index: 1;
    display: inline-block;
    height: 30px;
    cursor: pointer;
}
 
.btn-toggle__checkbox {
    position: absolute;
    /*
        umieszczamy nasz checkbox poza zasiegiem kursora,
        tj. pod tekstem i tłem suwaka. Dzięki temu użytkownik
        nie będzie go widział, ale dalej będzie w stanie go kliknąć.
     */
    opacity: 0;
    z-index: -1;
    visibility: hidden;
}
 
.btn-toggle__body {
    width: 100px;
    height: 30px;
    background: #fff;
    border: 1px solid #dadde1;
    display: inline-block;
    position: relative;
    z-index: 1;
    border-radius: 50px;
}
 
.btn-toggle__body__switch {
    width: 30px;
    height: 30px;
    display: inline-block;
    position: absolute;
    z-index: 2;
    left: 0;
    top: 50%;
    border-radius: 50%;
    border: 1px solid #fff;
    box-shadow: 0 2px 2px rgba(0, 0, 0, 0.13);
    color: #fff;
    background: #439fd8;
    transition:
        transform cubic-bezier(0.34, 1.61, 0.7, 1) .25s,
        background cubic-bezier(0.34, 1.61, 0.7, 1) .25s;
    transform: translate3d(-1px, -50%, 0);
}
 
.btn-toggle__body__switch:before {
    content: '«';
    display: block;
    line-height: 30px;
    font-size: 20px;
    text-align: center;
}
 
.btn-toggle__body__track {
    position: absolute;
    z-index: 1;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    overflow: hidden;
    border-radius: 50px;
}
 
[class*="btn-toggle__body__track__option"] {
    position: absolute;
    z-index: 1;
    top: 0;
    bottom: 0;
    width: 100px;
    text-align: center;
    line-height: 30px;
    transition:
        transform cubic-bezier(0.34, 1.61, 0.7, 1) .25s,
        background cubic-bezier(0.34, 1.61, 0.7, 1) .25s;
}
 
.btn-toggle__body__track__option--view {
    transform: translate3d(10%, 0, 0);
    background: #fff;
    color: #439fd8;
}
 
.btn-toggle__body__track__option--edit {
    transform: translate3d(-100%, 0, 0);
    background: #439fd8;
    color: #fff;
}
 
.btn-toggle:hover .btn-toggle__body__switch {
    border-color: #b5bbc3;
    transform: scale(1.06) translate3d(-1px, -47%, 0);
}
 
.btn-toggle:active .btn-toggle__body__switch {
    transform: scale(0.94) translate3d(-1px, -53%, 0);
}
 
/*
  gdy checkbox nie jest zaznaczony, ustawiamy mu style które pokażą informację o tym,
  że zmiana stanu przycisku zaznaczy checkbox
*/
.btn-toggle__checkbox:not(:checked) ~ .btn-toggle__body > .btn-toggle__body__switch {
    transform: translate3d(70px, -50%, 0);
    background: #fff;
    color: #439fd8;
    border: 1px solid #ccd0d6;
}
 
.btn-toggle__checkbox:not(:checked) ~ .btn-toggle__body > .btn-toggle__body__switch:before {
    content: '»';
}
 
.btn-toggle:hover .btn-toggle__checkbox:not(:checked) ~ .btn-toggle__body > .btn-toggle__body__switch {
    transform: scale(1.06) translate3d(66px, -47%, 0);
}
 
.btn-toggle:active .btn-toggle__checkbox:not(:checked) ~ .btn-toggle__body > .btn-toggle__body__switch {
    transform: scale(0.94) translate3d(74px, -53%, 0);
}
 
.btn-toggle__checkbox:not(:checked) ~ .btn-toggle__body .btn-toggle__body__track__option--view {
    transform: translate3d(110%, 0, 0);
}
 
.btn-toggle__checkbox:not(:checked) ~ .btn-toggle__body .btn-toggle__body__track__option--edit {
    transform: translate3d(-10%, 0, 0);
}

Powyższy kod CSS jest odpowiedzialny za ukrycie pola typu checkbox przed wzrokiem użytkownika strony. Ponadto, dodaje odpowiedni design i przejścia między stanami zaznaczenia pola typu checkbox. Dzięki temu, użytkownik ma przyjemną kontrolkę do używania na stronie lub w aplikacji internetowej.

Aby poprawić wydajność animacji przejścia wykorzystałem funkcję translate3d, dzięki czemu przeglądarka nie będzie musiała przeliczać ponownie położenia layoutu, tak jakby to miało miejsce w przypadku wykorzystania własności CSS: left, right.

Sekcja 3Podsumowanie

Powyższy przykład nie zawiera wszystkich właściwości CSS z vendor prefiksami (tzn. z przedrostkami wymaganymi przez starsze wersje przeglądarek), po to aby kod był bardziej przejrzysty. Dobrym sposobem na uzupełnienie brakującego kodu z vendor prefiksami jest użycie Autoprefixera (można go uruchomić z linii poleceń w terminalu lub za pomocą Grunt.js).

Mam nadzieję, że zaprezentowany przeze mnie sposób na tworzenie efektownie wyglądających przycisków okaże się przydatny. Efekt był testowany na przeglądarkach Mozilla Firefox, Google Chrome oraz Opera.

źródło

Udostępnij
Uwagi

O autorze

Staff Software Engineer

Piszę na tym blogu od 2009 roku, a strony i aplikacje webowe tworzę zawodowo od 14 lat. Obecnie w Bishop Fox prowadzę frontend platformy Cosmos, od samego początku projektu. Wcześniej pracowałem m.in. w OLX, KUDO, Auto1 i eZ Systems. Piszę tu o tym, czego nauczyłem się w praktyce: o JavaScripcie, TypeScripcie, Reakcie, CSS-ie i architekturze frontendu. Występowałem też jako prelegent na konferencjach w Polsce i Europie. Masz pytanie albo pomysł na wpis? Daj znać!