Search
Write a publication
Pull to refresh

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

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


Рассмотрим конкретный пример.

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

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

image

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

"1" class="menu">Меню 1<br/>
«magic1» class=«magic»>Меню 2
«2» class=«menu»>Меню 1<br/>
«magic2» class=«magic»>Меню 2<br/>Меню 2<br/>Меню 2
«3» class=«menu»>Меню 1<br/>
«magic3» class=«magic»>Меню 2


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 и вовсе выдает ошибку: недопустимый аргумент.

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

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

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

$(document).ready(function(){
  var height_element= new Array();
  for(i=1;i<=$("div.magic").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();
  for(i=1;i<=$("div.magic").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 миллисекунд на скрывание открытого подуровня меню, когда все подуровни скрыты.

Окончательно javascript будет выглядеть так:

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



Рабочий пример можно скачать здесь.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.