jquerycssjquery-uicss-positionjquery-ui-widget

Why is absolute positioning of a jQuery widget wrong?


I have prepared a complete example demonstrating my problem:

screenshot

My context is: in a 2-columns table I would like to show a list of players on the left and a game with 2-players on the right.

To display a player I have prepared a jQuery UI widget based on a div with CSS position: relative; and it works well in list of players on the left side.

However on the right side I am trying to use the same widget twice with CSS position: absolute; and for some reasons the "Ms. Left" and "Mr. Right" are positioned as if their parent would be the body and not the #gameTd.

Why does it happen please and how to position the 2 divs relatively to the #gameTd?

HTML:

<table border="1" width="100%">
  <tr>
    <th>Lobby</th>
    <th>Game</th>
  </tr>
  <tr>
    <td id="lobbyTd"></td>
    <td id="gameTd">
      <div id="leftPlayer"></div>
      <div id="rightPlayer"></div>
    </td>
  </tr>
</table>

CSS:

#lobbyTd {
  width: 25%;
  overflow-y: scroll;
}

#gameTd {
  background: #6C6;
}

.my-player {
  position: relative;
  background: #FFF no-repeat center;
  background-size: contain;
  box-shadow: 0 0 32px rgba(0, 0, 0, 0.2);
  margin: 8px;
  width: 160px;
  height: 120px;
}

.my-player-name {
  position: absolute;
  font-size: 18px;
  background: #FFF;
  color: #000;
  left: 0;
  bottom: 0;
  padding: 2px;
  width: 154px;
  height: 20px;
}

Javascript:

jQuery(document).ready(function($) {
  var PHOTO_PATTERN = /^https?:\/\/\S+/i;

  $.widget('my.player', {
    // default options
    options: {
      name: '',
      photo: 'https://slova.de/raspasy/images/male_happy.png',
    },

    _create: function() {
      this._hoverable(this.element);

      this.element.addClass('my-player');

      this.nameDiv = $('<div/>', {
        'class': 'my-player-name'
      }).appendTo(this.element);

      this._refresh();
    },

    _destroy: function() {
      this.nameDiv.remove();
      this.element.removeClass('my-player');
    },

    _setOptions: function() {
      this._superApply(arguments);
      this._refresh();
    },

    _refresh: function() {
      var photo = (PHOTO_PATTERN.test(this.options.photo) ? this.options.photo : 'https://slova.de/raspasy/images/male_happy.png');
      this.element.css('background-image', 'url("' + photo + '")');
      this.nameDiv.text(this.options.name);
    }
  });


  var lobbyPlayer1 = $('<div/>').player({
    name: 'Player #1'
  }).appendTo($('#lobbyTd'));

  var lobbyPlayer1 = $('<div/>').player({
    name: 'Player #2',
    photo: 'https://slova.de/raspasy/images/female_sad.png'
  }).appendTo($('#lobbyTd'));

  var lobbyPlayer3 = $('<div/>').player({
    name: 'Alexander',
    photo: 'http://afarber.de/images/farber.jpg'
  }).appendTo($('#lobbyTd'));

  // Why is absolute positioning wrong below?
  var leftPlayer = $('#leftPlayer').player({
    name: 'Ms. Left',
    photo: 'https://slova.de/raspasy/images/female_happy.png'
  }).css({
    position: 'absolute',
    left: '30px',
    top: '20px'
  });
  var rightPlayer = $('#rightPlayer').player({
    name: 'Mr. Right',
    photo: 'https://slova.de/raspasy/images/male_sad.png'
  }).css({
    position: 'absolute',
    right: '30px',
    top: '20px'
  });
});

Solution

  • You need to add position: relative for #gameTd for positioning relative to this block.