|
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