Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Тонкости веб-разработки. Позиционирование элементов на JavaScript.


Сегодня я расскажу о том, как правильно позиционировать элементы страницы друг относительно друга.
Зачем это нужно? Например, чтобы создать красивый выпадающий список. Сегодня мы зададимся целью создать некий пользовательский комбо-бокс. И стандартные возможности HTML нас не устраивают. То есть, мы хотим получить нечто более сложное, чем вот это.
<select>
<option>Item 1</option>
<option>Item 2</option>
<option>Item 3</option>
</select>

А получить хотели бы нечто вроде этого:

<input type=’text’ style="’width:" 100px;’ id=’textbox1′/>
<div style="’border:" 1px solid #072; background-color: #59E75D; width: 100px;’ id=’list1′>
<ul>
<li><a href=’#'>Item 1</a></li>
<li><a href=’#'>Item 2</a></li>
<li><a href=’#'>Item 3</a></li>
</ul>
То есть мы хотим отпозиционировать DIV так, чтобы он прикрепился к одному из углов другого элемента на странице. 

Вообще, для позиционирования элемента в координатах, заданных своими величинами (X, Y) подойдет вот такая функция:

function setPosXY(obj,x,y) {
  if(obj) {
    obj.style.position=’absolute’;
    obj.style.left=x+’px’;
    obj.style.top=y+’px’;
  }
}

Эта функция проста и особых пояснений не требует. Осталось только правильно определить координаты того элемента(E1), относительно которого хочется спозиционировать заданный элемент(E2), да еще и в соответствии с тем, к какому именно углу E1 будет пристыкован E2.  Углов у любого прямоугольника всего 4. Соответственно и вариантов позиционирования будет 4. Вот они.

Функция getBounds определяет параметры left, top, width, height объекта. Цикл while нужен для того, чтобы определить абсолютные координаты объекта относительно контейнера <body>.

function getBounds(obj){
  var w=obj.offsetWidth;
  var h=obj.offsetHeight;
  var x=y=0;
  while(obj){
    x+=obj.offsetLeft;
    y+=obj.offsetTop;
    obj=obj.offsetParent;
  }
  return{x:x,y:y,width:w,height:h};
}

 Ну а вот и сама функция позиционирования:

function setPos(anc_id,obj_id,corner,margin){
// anc_id - id элемента, относительно которого будем позиционировать
// obj_id - id элемента, который будем позиционировать
// corner - номер угла (смотрите Рис.1)
// margin - отступ между элементами, чтобы они не “слипались”
  if(!corner)corner=1;
  var obj=document.getElementById(obj_id);
  var anc=document.getElementById(anc_id);
  if(!obj||!anc) return;
  var b=getBounds(anc);
  var c=getBounds(obj);
  var xs=0,ys=0; // координаты left и top родительского элемента (на случай, если кто-то из родителей абсолютно позиционирован)
  var par=obj;
  for(var i=0;i<50;i++){
    par=par.parentNode;
    if(!par||par.tagName==’BODY’) break;
    var s=getCurrentStyle(par);
    if(par.tagName==’DIV’&&s&&s.position==’absolute’){
      var p=getBounds(par);
      xs+=p.x
      ys+=p.y;
      break;
    }
  }
  var xc=0,yc=0; // Дополнительные отступы, учитывающие номер угла
  switch(corner){
    case 2:
      yc=-c.height-b.height;
      break;
    case 3:
      yc=-c.height-b.height;
      xc=-c.width;
      break;
    case 4:
      xc=-c.width+b.width;
      break;
  }
  var xm=0;ym=0; // Дополнительные отступы, учитывающие параметр margin
  if(margin){
    xm=margin.x;
    ym=margin.y;
  }
  SetPosXY(obj,b.x-xs+xc+xm,b.y+b.height-ys+yc+ym);
}

И чуть не забыл, функция getCurrentStyle нужна, чтобы кроссбаузерно определить текущий стиль элемента:

function getCurrentStyle(el){
  if(!el) return null;
  var s=el.currentStyle; 
  if(!s) s=document.defaultView.getComputedStyle(el,null); // Для FireFox
  return s;
}

А вот здесь находится весь скрипт.  Пользуйтесь на здоровье.
Ну а вызов этой функции может выглядеть так:

setPos(’textbox1′,’list1′,1,{’x':2, ‘y’:2});
Прочесть эту статью целиком можно здесь.

В избранное