chevron-left chevron-right

Piotr Nalepa Frontend, architektura i AI

[CSS] Efektowne okrągłe menu rozwijane zbudowane za pomocą CSS

Ta wersja
blog.piotrnalepa.pl/2013/08/08/css-efektowne-okragle-menu-rozwijane-zbudowane-za-pomoca-css
Opublikowano
Autor
, Staff Software Engineer
Kategoria
CSS
Uwagi
Napisz do mnie · Napisz na X

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

W oczekiwaniu na rozstrzygnięcia dzisiejszego wieczoru (polska drużyna, Legia Warszawa, gra mecz rewanżowy w Lidze Mistrzów) postanowiłem Ci przedstawić jeszcze jeden sposób na utworzenie rozwijanego menu na stronie za pomocą CSS. Co ciekawe, będzie ono symulowało efekt kliknięcia bez JS.

Sekcja 1Okrągłe menu - kod HTML

Przykład 1HTML
1
2
3
4
5
6
7
8
<a class="button" href="#">&#9733;</a>
<ul class="menu">
  <li class="item"><a href="#">&#10022;</a></li>
  <li class="item"><a href="#">&#10047;</a></li>
  <li class="item"><a href="#">&#10037;</a></li>
  <li class="item"><a href="#">&#10026;</a></li>
  <li class="item"><a href="#">&#9728;</a></li>
</ul>

Utworzono dwa osobne elementy: przycisk i listę elementów. Są one od siebie niezależne i są one nałożone na siebie. Jako tekstu w menu użyto encji HTMLowych, które są zapisem technicznym symboli, takich jak różnego rodzaju gwiazdy lub kwiatki.

Sekcja 2Dobrodziejstwa CSS3 - animacje i transformacje

Jedną z największych zalet najnowszej specyfikacji CSS są animacje i transformacje. Oczywiście, istnieje również mnóstwo innych zalet, między innymi nowy box-model czy też media queries.

W przypadku tego menu będzimy wykorzystywać animacje i transformacje, a także pobawimy się cieniami i wielokrotnymi tłami.

Przykład 2CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
.button, /* #1 */
.menu {
  position: absolute;
  top: 50%;
  left: 50%;
  font: 1.5em/1.13 Verdana, sans-serif;
  transition: .5s;
}
.button,
.menu a {
  display: block;
  opacity: .56;
  background: #c9c9c9;
  color: #7a8092;
  text-align: center;
  text-decoration: none;
  text-shadow: 0 -1px #666;
}
.button:hover,
.button:focus,
.menu a:hover,
.menu a:focus {
  opacity: 1;
}
.button:focus,
.menu a:focus {
  outline: none;
}
.button {
  z-index: 2;
  margin: -.625em;
  width: 1.25em;
  height: 1.25em;
  border-radius: 50%;
  box-shadow: 0 0 3px 1px #fff;
}
.menu { /* #2 */
  z-index: 1;
  margin: -5em;
  width: 10em;
  height: 10em;
  transform: scale(.001);
  list-style: none;
  opacity: 0;
}
.menu:before,
.menu:after { /* #3 */
  position: absolute;
  top: 34.3%;
  width: .5em;
  height: 14%;
  opacity: .56;
  background: #c9c9c9;
  content: '';
}
.menu:before {
  left: 5.4%;
  border-radius: .25em 0 0 .25em;
  box-shadow:
    -1px 0 1px #666,
    inset 1px 0 1px #fff,
    inset -1px 0 1px #555,
    inset 0 1px 1px #fff,
    inset 0 -1px 1px #fff;
  transform: rotate(-75deg);
}
.menu:after {
  right: 5.4%;
  border-radius: 0 .25em .25em 0;
  box-shadow:
    1px 0 1px #666,
    inset -1px 0 1px #fff,
    inset 1px 0 1px #555,
    inset 0 1px 1px #fff,
    inset 0 -1px 1px #fff;
  transform: rotate(75deg);
}
.button:focus + .menu { /* #4 */
  transform: scale(1);
  opacity: 1;
}
.item { /* #5 */
  overflow: hidden;
  position: absolute;
  width: 50%;
  height: 50%;
  transform-origin: 100% 100%;
}
.item:first-child  { transform: rotate(-45deg) skewY(60deg); } /* #6 */
.item:nth-child(2) { transform: rotate(-15deg) skewY(60deg); }
.item:nth-child(3) { transform: rotate(15deg) skewY(60deg); }
.item:nth-child(4) { transform: rotate(45deg) skewY(60deg); }
.item:last-child   { transform: rotate(75deg) skewY(60deg); }
.item:after { /* #7 */
  position: absolute;
  top: 32%;
  left: 32%;
  width: 136%;
  height: 136%;
  border-radius: 50%;
  transform: skewY(-60deg);
  content: '';
}
.item a { /* #8 */
  width: 200%;
  height: 200%;
  border-radius: 50%;
  box-shadow:
    0 0 3px #666,
    inset 0 0 4px #fff;
  transform: skewY(-60deg) rotate(-15deg);
  background:
      linear-gradient(75deg, transparent 50%, #555 50%, transparent 54%) no-repeat 36.5% 0,
      linear-gradient(-75deg, transparent 50%, #555 50%, transparent 54%) no-repeat 63.5% 0,
      radial-gradient(rgba(127,127,127,0) 49%, rgba(255,255,255,.7) 51%, #c9c9c9 52%);
  background-size: 15% 15%, 15% 15%, cover;
  line-height: 1.4;
}
.item:nth-child(3) a:after { /* #9 */
  position: absolute;
  top: 13%;
  left: 50%;
  margin: -.25em;
  width: .5em;
  height: .5em;
  box-shadow: 2px 2px 2px #fff;
  transform: rotate(45deg);
  background: linear-gradient(-45deg, #c9c9c9 50%, transparent 50%);
  content: '';
}

W przerwie meczu (jest remis 0-0 z Molde), kontynuuję dalsze opisywanie sposobu uzyskania efektu rozwijanego menu po okręgu.

W związku z tym, że ciekawych rozwiązań zastosowanych przy budowie tego menu jest dość sporo, to postanowiłem, że opiszę je kolejno w punktach.

Sekcja 2.1Zastosowane rozwiązania:

  1. Definiujemy te same style początkowe dla przycisku menu i samego menu, a także czas trwania efektu przejścia między wartościami własności;

  2. W tym miejscu definiujemy sposób zachowania się menu. Własność transform o wartości scale(.001) pozwala na utworzenie efektu rozwijania się menu bezpośrednio spod przycisku aktywującego;

  3. Pseudoelementy :before i :after służą do określania stylu zakończeń menu;

  4. Taka kombinacja selektorów pozwala na symulowanie kliknięcia w element i rozwinięcie menu;

  5. Określamy wymiary pojedynczego elementu w menu oraz jego stopień transformacji na osi OXY;

  6. W tym miejscu, definiujemy położenie każdego elementu z osobna, czyli określamy jego pozycję na okręgu oraz jego spłaszczenie, powstanie romboid. W tym przypadku, zastosowano wzór matematyczny:
    kąt obrotu = (A/2)° + (k - (n+1)/2)*A°, gdzie:

    • A to kąt pierwszego elementu naszej listy (stanowi naszą bazę),
    • k jest numerem porządkowym elementu, np: dla pierwszego elementu to 1, a dla trzeciego to 3;
    • n to liczba elementów w menu.

    Powyższy wzór ma zastosowanie dla nieparzystej liczby elementów. Dla parzystej liczby wzór się nieco zmienia:
    kąt obrotu = (A/2)° + (k - n/2)*A°

    Po obliczeniu kąta obrotu elementów, obliczamy ich przekrzywienie wg wzoru (dla wszystkich ta sama wartość):
    kąt przekrzywienia = 90° - kąt obrotu

  7. W tym miejscu określamy przestrzeń między elementem listy a przyciskiem głównym menu, aby efekt najazdu (hover) nie pojawiał się;

  8. Definiujemy wygląd środka elementu listy w którym znajduje się link. Dzięki wykonaniu transformacji link będzie widoczny poprawnie. Zerujemy przekrzywienie oraz poprawiamy jego położenie.
    Ponadto, tworzymy efektownie wyglądające tło elementu, dzięki temu uzyskujemy ulepszony efekt przestrzeni między elementami.

  9. Poprawiamy wygląd linka wewnątrz środkowego elementu listy.

Sekcja 3Podsumowanie

Powyższy przykład został przygotowany dla przeglądarki Mozilla Firefox, ale bez problemu można tak zmodyfikować kod, aby działał on również w przeglądarkach z silnikiem Webkit. Zapewne pod IE9 i nowszych też zadziała po podaniu odpowiednich prefiksów.

Dlaczego to menu jest ciekawe i użyteczne? Dlatego, że mamy tu doczynienia z nietypową animacją listy elementów, w których kształty elementów są zależne od kąta nachylenia. Ponadto, dzięki skupieniu elementów w jednym miejscu pod jednym prczyciskiem, możemy utworzyć ciekawe interefejsy użytkownika, które będą cieszyły wzrok animacjami i nie będą rozpraszały uwagi od głównej zawartości strony.

BTW. Wpis ten dokończyłem już po meczu Legii. Na szczęcie mamy przynajmniej jedną polską drużynę w pucharach do grudnia. Podoba Ci się taka forma wpisu, która zawiera wtrącenia niekoniecznie powiązane w projektowaniem stron?

Demo z tego artykułu jest dostępne tutaj (obecnie działa tylko w Firefoksie): menu punktowe w CSS

ź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ć!