|
1357 | 1357 | * not it is part of the same [CSS containing
|
1358 | 1358 | * block](http://www.w3.org/TR/CSS21/visudet.html#containing-block-details).
|
1359 | 1359 | *
|
| 1360 | + * Also note that `element` must already be `position: absolute` or |
| 1361 | + * `position: fixed`. This method will not apply a `position` style. |
| 1362 | + * |
1360 | 1363 | * ##### Options
|
1361 | 1364 | *
|
1362 | 1365 | * <table class='options'>
|
|
1416 | 1419 | element = $(element);
|
1417 | 1420 | var p, delta, layout, styles = {};
|
1418 | 1421 |
|
| 1422 | + var isAbsolute = Element.getStyle(element, 'position') === 'absolute'; |
| 1423 | + var parent = Element.getOffsetParent(element); |
| 1424 | + |
1419 | 1425 | if (options.setLeft || options.setTop) {
|
| 1426 | + // We start by measuring the source's viewport offset. |
1420 | 1427 | p = Element.viewportOffset(source);
|
| 1428 | + |
| 1429 | + // If the element we're altering is `position: fixed`, that's all the |
| 1430 | + // information we need: later we'll apply that offset to the `top` and |
| 1431 | + // `left` properties directly. |
1421 | 1432 | delta = [0, 0];
|
1422 |
| - // A delta of 0/0 will work for `positioned: fixed` elements, but |
1423 |
| - // for `position: absolute` we need to get the parent's offset. |
1424 |
| - if (Element.getStyle(element, 'position') === 'absolute') { |
1425 |
| - var parent = Element.getOffsetParent(element); |
1426 |
| - if (parent !== document.body) delta = Element.viewportOffset(parent); |
| 1433 | + |
| 1434 | + // But if it's `position: absolute`, we have to know where its offset |
| 1435 | + // parent is positioned and take those measurements into account as |
| 1436 | + // well. |
| 1437 | + if (isAbsolute && parent !== document.body) { |
| 1438 | + delta = Element.viewportOffset(parent); |
1427 | 1439 | }
|
1428 | 1440 | }
|
1429 | 1441 |
|
|
1440 | 1452 | return { x: x, y: y };
|
1441 | 1453 | }
|
1442 | 1454 |
|
1443 |
| - var pageXY = pageScrollXY(); |
1444 |
| - |
1445 |
| - |
1446 |
| - if (options.setWidth || options.setHeight) { |
1447 |
| - layout = Element.getLayout(source); |
1448 |
| - } |
| 1455 | + // When the offset parent is the document body, we need to account for |
| 1456 | + // scroll offsets when we set `top` and `left`. (Unless the element is |
| 1457 | + // `position: fixed`; in that case we should always ignore scroll |
| 1458 | + // position.) |
| 1459 | + var pageXY = (isAbsolute && parent === document.body) ? pageScrollXY() : { x: 0, y: 0 }; |
1449 | 1460 |
|
1450 | 1461 | // Set position.
|
1451 | 1462 | if (options.setLeft)
|
1452 | 1463 | styles.left = (p[0] + pageXY.x - delta[0] + options.offsetLeft) + 'px';
|
1453 | 1464 | if (options.setTop)
|
1454 | 1465 | styles.top = (p[1] + pageXY.y - delta[1] + options.offsetTop) + 'px';
|
1455 | 1466 |
|
1456 |
| - // Use content box when setting width/height. If padding/border are |
1457 |
| - // different between source and target, that's for the user to fix; |
1458 |
| - // there's no good option for us. |
1459 |
| - if (options.setWidth) { |
1460 |
| - styles.width = layout.get('width') + 'px'; |
1461 |
| - } |
1462 |
| - if (options.setHeight) { |
1463 |
| - styles.height = layout.get('height') + 'px'; |
| 1467 | + if (options.setWidth || options.setHeight) { |
| 1468 | + layout = Element.getLayout(source); |
| 1469 | + |
| 1470 | + // Use content box when setting width/height. If padding/border are |
| 1471 | + // different between source and target, that's for the user to fix; |
| 1472 | + // there's no good option for us. |
| 1473 | + if (options.setWidth) { |
| 1474 | + styles.width = layout.get('width') + 'px'; |
| 1475 | + } |
| 1476 | + if (options.setHeight) { |
| 1477 | + styles.height = layout.get('height') + 'px'; |
| 1478 | + } |
1464 | 1479 | }
|
1465 | 1480 |
|
1466 | 1481 | return Element.setStyle(element, styles);
|
|
0 commit comments