Как стать автором
Обновить

Имитируем height:auto при использовании animate()

Время на прочтение6 мин
Количество просмотров21K
Задача использования на сайте различных анимированных объектов, как то меню или фотогалерея, уже давно не является редкостью. И здесь на помощь разработчикам приходит замечательный jquery-метод animate(). Этот метод позволяет анимировать различные свойства css, но имеет один довольно существенный недостаток – в качестве значения свойства может использоваться только число, либо значения hide, show и toggle. Например, height:20 – верно, а вот height:auto будет работать не всегда и не везде.

Попробуем решить эту проблему на конкретном примере

Допустим, необходимо разработать вертикальное двухуровневое меню. По умолчанию открыты только пункты первого уровеня, а при клике на соответствующую ссылку, сначала скрывается открытый подуровень, а затем открывается нужный скрытый. Но не просто открываются, а анимировано с увеличением высоты и прозрачности контейнера.

То есть, в итоге нужно получить вот такое меню:

image

Пишем HTML код нашего будущего меню:

<a id="1" class="menu">Меню 1</a><br/>
<div id="magic1" class="magic">Меню 2</div>
<a id="2" class="menu">Меню 1</a><br/>
<div id="magic2" class="magic">Меню 2<br/>Меню 2<br/>Меню 2</div>
<a id="3" class="menu">Меню 1</a><br/>
<div id="magic3" class="magic">Меню 2</div>


Css:
div.magic{
filter:alpha(opacity=0);
-moz-opacity: 0;
-khtml-opacity: 0;
opacity: 0;
overflow:hidden;
padding-left:10px;
}



И javascript:

$(document).ready(function(){
  $("a.menu").click(
    function(){          
      $("div.magic").animate({
      opacity: 0,
      height: "10px"
      }, 500);
          
      $("div#magic"+ this.id).animate({
      opacity: 1,
      height: "auto"
      }, 500);    
    }
  );
})



При клике по пункту меню, мы скрываем все блоки класса «magic», и раскрываем тот из них, который содержит нужные нам подпункты.

Казалось бы, все должно работать, но это совсем не так. Вместо значения свойства height «auto» Firefox, Google Chrome и Opera устанавливают для контейнера высоту в 10px, которая была прописана нами в css, а IE7 и вовсе выдает ошибку: недопустимый аргумент.

Как же с этим бороться?

Способ 1.

Идея состоит в том, чтобы предварительно, до начала работы с меню, записать в массив значения высот всех необходимых контейнеров, а потом вместо «auto» подставлять значение элемента этого массива. То есть, новый javascript-код будет выглядеть следующим образом.

$(document).ready(function(){
  var height_element= new Array();
  var array_length=$("div.magic").length;
    
  for(i=1;i<=array_length;i++)
  {
    height_element[i]=$("div#magic"+i).height();
  }
    
  $("a.menu").click(
    function(){          
      $("div.magic").animate({
      opacity: 0,
      height: "10px"
      }, 500);
        
      $("div#magic"+ this.id).animate({
      opacity: 1,
      height: height_element[this.id]+'px'
      }, 500);    
    }
  );
})



Таким образом, мы избавимся от использования устанавливаемого значения высоты, равного «auto», и заменим его конкретным числовым значением. Это поможет нам избавиться от ошибки в IE, но, как оказалось, не решит проблемы с истинным значением высоты контейнера, ведь все браузеры продолжат выставлять в качестве нового значения 10px. То есть, на экране мы увидим вот что:

image

Для того, чтобы справиться с этой проблемой, уберем из свойств класса «magic» значение высоты, а устанавливать его будем динамически после записи истинного значения высоты в массив.

Новый css-файл будет выглядеть так:

div.magic{
filter:alpha(opacity=0);
-moz-opacity: 0;
-khtml-opacity: 0;
opacity: 0;
padding-left:10px;
overflow:hidden;
}



А javascript так:

$(document).ready(function(){
  var height_element= new Array();
  var array_length=$("div.magic").length;
    
  for(i=1;i<=array_length;i++)
  {
    height_element[i]=$("div#magic"+i).height();        
  }

    $("div.magic").css("height","10px");
    
    $("a.menu").click(
    function(){          
      $("div.magic").animate({
      opacity: 0,
      height: "10px"
      }, 500);
        
      $("div#magic"+ this.id).animate({
      opacity: 1,
      height: height_element[this.id]+”px”
      }, 500);    
    }
  );
})



Ну и для полного счастья, можно добавить некую переменную «first», которая будет равна 0 после загрузки страницы, и примет значение 1 после первого клика по пункту меню. Она нужна для того, чтобы избавиться от задержки в 500 миллисекунд на скрывание открытого подуровня меню, когда все подуровни скрыты.

Рабочий пример можно посмотреть здесь

Способ 2.

Вместо метода animate() применить методы hide() и show() с длительностью в те же самые 500 миллисекунд.

Однако, при использовании методов hide() и show() плавно изменяются все стили объекта, то есть, необходимый нам padding так же будет меняться от 0 до 10 и обратно. Эффект, конечно, красивый, но в данном случае не нужный. Поэтому padding нужно будет вынести в отдельный контейнер.

HTML-код для данного случая:

<a id="1" class="menu">Меню 1</a><br/>
<div id="magic1" class="magic"><div class="inner">Меню 2</div></div>
<a id="2" class="menu">Меню 1</a><br/>
<div id="magic2" class="magic"><div class="inner">Меню 2<br/>Меню 2<br/>Меню 2</div></div>
<a id="3" class="menu">Меню 1</a><br/>
<div id="magic3" class="magic"><div class="inner">Меню 2</div></div>


CSS:
div.magic{
overflow:hidden;
display:none;
}

a.menu{
cursor:pointer;
color:#0033CC;
text-decoration:underline;
margin-bottom:10px;
}

div.inner{
padding-left:10px;
}




И javascript:

$(document).ready(function(){
    var first=0;
    var last_id=0;
    var id_now=0;
    
    $("a.menu").click(
      function(){
        id_now=this.id;
        
        if(first!=0)
        {
          $("div#magic"+ last_id).hide(500,function(){
            $("div#magic"+ id_now).show(500);
            });
        }
        else
        {
          first=1;
          $("div#magic"+ this.id).show(500);
        }
        
        last_id=id_now;
      }
    );
  })


* This source code was highlighted with Source Code Highlighter.

Спасибо пользователю Voenniy за доработку второго способа.

А рабочий пример можно посмотреть здесь

И в качестве заключительного слова. Этот пост писался не ради того, чтобы создать меню на jQuery, ведь таких меню существует очень много. Главная цель здесь — показать, как двумя способами можно сымитировать значение свойства height:auto при использовании метода animate(). А ведь такая задача может встречаться не только при создании меню.
Теги:
Хабы:
Всего голосов 18: ↑9 и ↓90
Комментарии9

Публикации

Истории

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань