Статьи

Создание выпадающего меню для мобильных страниц

Из этого туториала вы узнаете, как создать и анимировать значок меню гамбургера, а затем подключить прослушиватель событий через jQuery для вызова раскрывающегося меню.

Я буду использовать Jade (Pug) и Sass вместо ванильного HTML и CSS. Так что вы должны хотя бы иметь базовые знания об этих шаблонизаторах.

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

Нефритовый файл:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
body
   #container
       #header
       #body
           .content
               .left
               .right
                   — for (i=1; i <= 5 ; i++ )
                       div( id=»text» + i )
           .content
               .left
               .right
                   — for (j=6; j <= 10 ; j++ )
                       div( id=»text» + j )
           .content
               .left
               .right
                   — for (k=11; k <= 15 ; k++ )
                       div( id=»text» + k )

Sass файл:

01
02
03
04
05
06
07
08
09
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
=flex()
  display: -webkit-box
  display: -moz-box
  display: -ms-flexbox
  display: -webkit-flex
  display: flex
   
=transition($time)
  -webkit-transition: all $time ease
  -moz-transition: all $time ease
  -ms-transition: all $time ease
  -o-transition: all $time ease
  transition: all $time ease
 
html, body
  margin: 0
  padding: 20px 0
  +flex()
  justify-content: center
 
//———————————-//
 
#container
  width: 320px
  height: 550px
  background-color: #ebebeb
  overflow: hidden
 
#header
  height: 45px
  background-color: #9b9b9b
  position: relative
 
 
#body
  padding: 0 20px
  padding-top: 40px
  +flex()
 
  flex-direction: column
  justify-content: flex-start
 
.content
  +flex()
 
  flex-direction: row
  justify-content: flex-start
  margin-bottom: 25px
 
 
  .left
    width: 100px
    height: 100px
    margin-right: 15px
    background-color: #e1e1e1
 
  .right
    @for $i from 1 through 15
      #text#{$i}
        margin-top: 10px
        width: 50 + random(100) + px
        height: 10px
        background-color: #e1e1e1

Примечание: здесь я создал два миксина с именем flex и transition . Миксины облегчают повторное использование некоторых правил CSS, группируя их. Всякий раз, когда мне нужно добавить display:flex со всеми префиксами вендора, я могу просто использовать вместо него +flex() , благодаря mixin.

Мы будем использовать эту структуру и опираться на нее до конца урока.

Конечный результат должен выглядеть так:

Детская площадка

Посмотреть текущий код

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

Добавьте новый div внутри #header и назовите его #hamburger . Затем создайте двух дочерних #hamburger внутри #hamburger . Они должны иметь общий класс и индивидуальные идентификаторы.

1
2
3
#hamburger
   .strip#top
   .strip#bottom

Теперь нам нужно #hamburger родительский div #hamburger и #hamburger div с общим классом .strip .

1
2
3
4
5
6
7
8
#hamburger
 height: 100%
 width: 45
 +flex()
 
 flex-direction: column
 justify-content: space-between
 padding-left: 20px

Мы устанавливаем высоту div, равную его родительскому div, который является #header , определяя height: 100% . Также мы устанавливаем значение ширины для этого родительского элемента div, который будет определять его «активируемую» область.

Далее мы добавляем flexbox со всеми префиксами вендоров, используя миксины, которые мы создали ранее.

Поскольку мы хотим, чтобы наши .strip .strip располагались вертикально, мы устанавливаем flex-direction: column и затем используем justify-content: space-between .strip чтобы поместить пробел между .strip .strip.

Затем нам нужно подтолкнуть эти div к друг другу, добавив нижний и верхний отступы к соответствующим div.

1
2
3
4
5
#top
  margin-top: 17px
   
#bottom
  margin-bottom: 17px

Мы также добавили padding-left: 20px , чтобы переместить .strip .strip дальше вправо.

Следующее, что нужно, это оформить полоски. Это относительно просто, просто определив размер и цвет элементов.

1
2
3
4
.strip
 width: 25px
 height: 2px
 background-color: #ffffff

Окончательный результат со значком меню гамбургера должен выглядеть следующим образом:

Значок меню гамбургера

Следующее, что нужно сделать, это анимировать значок меню, чтобы при щелчке он превращался в знак креста.

На этом этапе мы собираемся использовать базовый jQuery для переключения некоторых классов CSS.

Давайте сначала создадим CSS-классы для переключения.

Мы будем использовать настройки translate и rotate свойства transform CSS вместе со свойством transition .

Сначала добавьте переходы в #top и #bottom , используя миксины с определенным параметром синхронизации.

1
2
3
4
5
6
7
#top
  margin-top: 17px
  +transition(.25s)
 
#bottom
  margin-bottom: 17px
  +transition(.25s)

Теперь нам нужно определить стили классов, которые будут переключаться.

Мы будем вращать и переводить каждый .strip div по отдельности, поэтому нам нужно переключать разные классы как для #top и #bottom .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
#top
  margin-top: 17px
  +transition(.25s)
 
  &.topRotate
    transform-origin: center
    transform: translateY(4px) rotateZ(45deg)
 
#bottom
  margin-bottom: 17px
  +transition(.25s)
 
  &.bottomRotate
    transform-origin: center
    transform: translateY(-5px) rotateZ(-45deg)

Здесь мы определили стиль для двух разных классов с именами .bottomRotate и .topRotate , которые будут добавлены и удалены из соответствующих ссылок на #top , #top и #bottom .

Обратите внимание, что разные размеры класса .strip могут привести к необходимости использования разных значений translateY и rotateZ , чтобы анимировать их в правильный крестик.

Мы определили, как каждый .strip div будет анимироваться, когда topRotate классы topRotate и bottomRotate . Однако нам еще предстоит подключить прослушиватель событий для переключения этих классов.

Создайте новый файл JavaScript и используйте следующий код для переключения классов #top и #bottom идентификаторами #top и #bottom соответственно.

1
2
3
4
5
6
$(document).ready(function(){
  $(«#hamburger»).click(function(){
      $(«#top»).toggleClass(«topRotate»);
      $(«#bottom»).toggleClass(«bottomRotate»);
  });
})

Мы помещаем весь наш код в $(document).ready(function(){}) , чтобы дождаться загрузки всей страницы, прежде чем предпринимать какие-либо действия.

Когда мы #hamburger div #hamburger , он переключает классы для div с конкретными идентификаторами.

Примечание. Не забудьте добавить исходный файл jQuery в ваш проект.

Посмотреть текущий код

Следующим шагом является создание меню с элементами списка.

Используйте следующую структуру под #header :

1
2
3
4
5
6
7
8
9
#dropDown
   #background
   ul
       li Home
       li Blog
       li Projects
       li Authors
       li Jobs
       li Contact

Поэтому здесь мы использовали тег ul в качестве родительского для того, чтобы сгруппировать элементы с тегами li качестве дочерних. Более того, чтобы создать расширяющуюся фоновую анимацию, мы также добавили div с идентификатором #background .

Давайте сначала li элементы ul и li .

1
2
3
4
ul
 list-style: none
 padding: 0
 margin: 0

Установите list-style в none , чтобы удалить маркеры из элементов ul а также установите для padding и margin значение 0, чтобы удалить все предопределенные значения.

Теперь стиль элементов li :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
li
   //display: none
   background-color: #9b9b9b
   color: #ffffff
 
   font-family: ‘Quicksand’, sans-serif
   font-weight: lighter
   font-size: 15px
   padding: 20px
   padding-left: 60px
 
   &:after
     position: absolute
     content: »
     left: 60px
     width: 60%
     height: 1px
     bottom: 4px
     background: rgba(255, 255, 255, 0.25)
 
   &:last-child:after
     width: 0

Здесь я закомментировал display:none , чтобы можно было увидеть результат. Однако при анимации мы будем использовать его, чтобы изначально скрыть элементы списка.

Я также добавил псевдоэлемент after и стилизовал его соответственно, чтобы отделить каждый элемент li прямой линией. :last-child:after удаляет эту строку для последнего элемента li .

Посмотреть текущий код

Теперь мы собираемся использовать некоторые директивы управления Sass для добавления анимации ключевых кадров CSS с различными атрибутами к каждому элементу li .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
@keyframes drop
  0%
    opacity: 0
    transform: scale(1.3)
 
  100%
    opacity: 1
    transform: scale(1)
     
@keyframes fold
  0%
    opacity: 1
    transform: scale(1)
 
  100%
    opacity: 0
    transform: scale(0.7)

Здесь мы определили анимацию ключевого кадра « drop and fold .

drop для анимации открытия списка меню. Начальное масштабирование на 30% больше, и оно уменьшается до исходного размера, когда прозрачность изменяется от 0 до 1. Противоположное действие происходит в fold .

Теперь нам нужно прикрепить эти ключевые кадры к элементам li . В этой части Sass пригодится.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
@for $i from 1 through 6
 li:nth-child(#{$i})
   animation:
     name: fold
     duration: 80ms*(6-$i) + 1ms
     timing-function: ease-in-out
     fill-mode: forwards
 
 li.anim:nth-child(#{$i})
   animation:
     name: drop
     duration: 100ms*$i
     timing-function: ease-in-out
     fill-mode: forwards

Здесь я использовал цикл for, который идет от 1 до 6 с индексом $i .

Теперь нам нужно использовать этот индекс, чтобы прикрепить каждую анимацию к элементам li разной длительности.

Сначала рассмотрим li.anim:nth-child(#{$i}) .

Здесь мы берем $i й дочерний элемент элемента li с классом anim .

Мы будем переключать этот класс anim . Таким образом, при добавлении к элементам li анимация ключевого кадра с именем drop будет действовать. Когда он будет удален, анимация fold будет действовать.

Следующая важная вещь — это атрибут duration .

duration: 100ms*$i для анимации drop увеличивает продолжительность анимации для каждого увеличивающегося дочернего числа. Итак, когда этот код скомпилирован, первый дочерний duration: 600ms будет иметь duration: 100ms , а последний дочерний duration: 600ms будет иметь duration: 600ms .

Это даст смысл анимации каждого элемента один за другим.

Мы делаем то же самое для fold анимации. На этот раз последний элемент должен быть анимирован быстрее, следовательно, duration: 80ms*(6-$i) + 1ms . Добавление 1 мс к длительности связано с тем, что при установке длительности на 0 могут возникнуть некоторые проблемы, и ваша анимация может работать некорректно.

Когда мы разрабатывали элемент li , я упоминал, что нам нужно использовать display:none , чтобы избежать нежелательного воспроизведения анимации. Если вы не установите его в none , вы увидите, что анимация fold проигрывается один раз при загрузке страницы.

Если мы установим для свойства display значение none , мы этого не увидим, а затем нам нужно показать элемент li перед переключением класса anim .

Мы хотим, чтобы наша анимация воспроизводилась, когда мы щелкаем значок гамбургера. Итак, давайте используем jQuery для установки свойства display каждого элемента li для block а также для переключения класса anim .

01
02
03
04
05
06
07
08
09
10
$(document).ready(function(){
  $(«#hamburger»).click(function(){
      $(«#top»).toggleClass(«topRotate»);
      $(«#bottom»).toggleClass(«bottomRotate»);
 
      $(«li»).show();
      $(«li»).toggleClass(«anim»);
 
  });
})

Посмотреть текущий код

Вы заметите, что мы можем видеть анимацию каждого элемента li отдельности. Тем не менее, мы бы предпочли ощущение расширения меню.

Чтобы это исправить, нам просто нужно увеличить высоту div. Это div #background , который мы изначально добавили при создании элементов ul и li .

1
2
3
4
5
6
7
8
9
#background
 width: 100%
 height: 0
 background-color: #9b9b9b
 position: absolute
 +transition(.45s)
 
 &.expand
   height: 550px

Мы будем переключать класс expand , чтобы установить для атрибута height значение 550px течение .45s . Обратите внимание, что я использовал transition миксин для определения перехода с определенным параметром времени.

Конечный результат

На протяжении всего этого урока мы практиковались в использовании циклов в HTML и CSS с помощью шаблонизаторов Jade и Sass. Кроме того, мы создали анимации ключевых кадров CSS и прикрепили их с различными атрибутами продолжительности к определенным элементам HTML. Затем мы переключили классы с помощью jQuery для управления этими анимациями.