Adding margin support to attemptChangeSize#6824
Adding margin support to attemptChangeSize#6824dvoytenko merged 1 commit intoampproject:masterfrom tlong2:attempt-size-change-margins
Conversation
|
/to @dvoytenko |
src/custom-element.js
Outdated
| setStyle(this, 'width', newWidth, 'px'); | ||
| } | ||
| if (opt_newMargins) { | ||
| setStyle(this, 'marginTop', opt_newMargins.top, 'px'); |
There was a problem hiding this comment.
I think we should allow each component to be undefined and avoid overriding here. This is inline with similar use cases.
src/layout-margins.js
Outdated
| * The structure that represents the margins of an Element. | ||
| * | ||
| * @typedef {{ | ||
| * top: number, |
There was a problem hiding this comment.
As described above, let's do (number|undefined)
There was a problem hiding this comment.
Added a new type for specify the changes that allows undefined.
src/service/resources-impl.js
Outdated
| changeSize(element, newHeight, newWidth, opt_callback) { | ||
| this.scheduleChangeSize_(Resource.forElement(element), newHeight, | ||
| newWidth, /* force */ true, opt_callback); | ||
| newWidth, undefined, /* force */ true, opt_callback); |
There was a problem hiding this comment.
/* opt_margins */ undefined
src/service/resource.js
Outdated
| this.layoutBox_ = box; | ||
|
|
||
| const win = this.resources_.win; | ||
| const computedStyle = win./*OK*/getComputedStyle(this.element); |
There was a problem hiding this comment.
I'm wondering if we allow undefined values, would it be enough for us to just read the values from element.style? Calling getComputedStyle here for all elements (most of which do not care about resizing) is pretty expensive. If not - I think updating margin is a rare enough case and we should move it closer to the size updating code and only do this when margin changes have been requested.
There was a problem hiding this comment.
I don't think element.style is sufficient; it would ignore anything that comes from the CSS style rules.
I've changed it so that the getLayoutMargins method calls getComputedStyle and reads the margins only when it's called and have also changed mutate() in resources-impl.js to only call getLayoutMargins() when there is actually a newMargins defined in the request. Does that seem OK?
There was a problem hiding this comment.
Although it occurs to me that calling getComputedStyle would probably have to be done somewhere inside a vsync_.measure call I guess?
There was a problem hiding this comment.
Yes, it has to be in the vsync.measure. I think we need to change this. Basically, we only need to read margins in a relatively rare case when margin change has been requested: they are not needed before or after otherwise. So, what we can do, is remove layoutMargins_ var and code from Resource file and modify this code here: https://github.com/ampproject/amphtml/blob/master/src/service/resources-impl.js#L1334
It'd be something like this:
if (resource.hasBeenMeasured() && !opt_newMargings) {
// unchanged
} else {
vsync.measure(() => {
if (!resource.hasBeenMeasured()) {
resource.measure();
}
let marginsDiff = null;
if (opt_newMargin) {
marginsDiff = // calculate existing margins and diff with opt_newMargin
}
this.completeScheduleChangeSize_(..., marginsDiff);
});
}
And then we'd use marginsDiff in the resize code itself. E.g. marginsDiff && marginsDiff.top would mean that top margin has been modified, etc.
There was a problem hiding this comment.
I've done basically what you suggest. I've passed the existing and the new margins along, since we need the existing margins in mutateWork_() to know where the bottom displaced boundary is. So doesn't make much sense to pass a diff around just to turn it back into the original value later on.
src/service/resources-impl.js
Outdated
| // changed then it is the bottom edge of the margin box, otherwise it | ||
| // is the bottom edge of the layout box. | ||
| const bottomDisplacedBoundary = bottomMarginDiff ? | ||
| box.bottom + margins.bottom : box.bottom; |
There was a problem hiding this comment.
Shouldn't this be box.bottom + bottomDisplacedBoundary?
There was a problem hiding this comment.
I'm not sure what your suggestion is here?
The point in this is to record the boundary that will have a visible change as far as the user is concerned. If there is no margin change then it will only appear as though the bottom of the border-box has moved (which is box.bottom). If the bottom margin is also being resized then the spacing between this element and the next will also change.
So for example, if there is an element where box.bottom is <10% inside the top of the viewport and it has a bottom margin of 100px, then a pure height resize is fine (and would be allowed under the existing logic, as well as this new logic). If the bottom margin, however, is being resized then it's not fine, since this will make things within the main 80% of the viewport move around.
There was a problem hiding this comment.
Ok, got it. Let's do margin changes and I'll review this one more time - it should be good to go.
src/service/resources-impl.js
Outdated
| const box = resource.getLayoutBox(); | ||
| const iniBox = resource.getInitialLayoutBox(); | ||
| const diff = request.newHeight - box.height; | ||
| const margins = resource.getLayoutMargins(); |
There was a problem hiding this comment.
For simplicity, shouldn't we just do diff = (newHeight + newMargin) - (oldHeight + oldMargin) and operate with that as before? Why I'm asking is that naively, margin changes are visually very similar to padding changes and paddings would be captured inside the height. So it'd seem that the diff math should be the same?
There was a problem hiding this comment.
I don't think just doing what you suggest is correct for either the case of changing padding or margins.
It seems that the existing logic uses the fact that the top edge of an element will not change as a result of a change in height (none of the rules for setting resize=true/false ever check what box.top is) and for changes to the height where margins and padding are held constant this is valid.
As far as a user is concerned the top edge of an element is the edge of whatever they can see. For the case of an image without a border, then this will be the top of the content box, for the case of something with a border or a background color this will be the border box (which is equivalent to layout box in AMP).
So in all cases, changing the top margin is more akin to re-positioning the element than it is to resizing it. And for elements with no border or background changing the top padding would also be more akin to re-positioning than resizing.
So changes in margins need to be considered somewhat separately from changes in height if we want to avoid user visible re-flows in the middle of the viewpoint.
src/custom-element.js
Outdated
| setStyle(this, 'width', newWidth, 'px'); | ||
| } | ||
| if (opt_newMargins) { | ||
| if (opt_newMargins.top) { |
There was a problem hiding this comment.
Should this be opt_newMargins.top != null? I assume 0 would be a valid value here, right?
src/layout-margins.js
Outdated
| @@ -0,0 +1,56 @@ | |||
| /** | |||
There was a problem hiding this comment.
Sorry for the furniture moving, but could we move these to layout-rect.js?
| marginChange, force, opt_callback); | ||
| }); | ||
| } | ||
| } |
There was a problem hiding this comment.
"Returns the previously measured value..." is not longer true.
|
@tlong2 Great! Just one small comment and I should be ready to merge. Thanks a lot! |
| * marginChange: (!MarginChangeDef|undefined), | ||
| * force: boolean, | ||
| * callback: (function(boolean)|undefined) | ||
| * }} |
There was a problem hiding this comment.
Why aren't we giving changeSize a margins, too?
| } | ||
| if (bottomMarginDiff) { | ||
| // The lowest boundary of the element that would appear to be | ||
| // resized as a result of this size change. If the bottom margin is |
There was a problem hiding this comment.
Shouldn't this include the topMarginDiff?
There was a problem hiding this comment.
No. It's supposed to be the current position of the bottom boundary that will be displaced. This is used in the check that the bottom of the element is above the viewport (or within the 10% offset allowed). As long as the bottom displaced boundary meets this criteria then it doesn't matter what happens in terms of height changes of top margin changes, since the scroll adjusting will act such that nothing appears to change in the viewport except possibly in that allowed 10% region.
|
Merged! Thanks a lot, @tlong2 ! |
* master: (310 commits) Update csa.md to remove non-required parameters (ampproject#6902) Add notes about requesting ads ATF and link to demo (ampproject#7037) Remove whitelist for lightbox scrollable validator (ampproject#7034) Delegate submit events until amp-form is loaded (ampproject#6929) Moves closure sha384 into a new extension amp-crypto-polyfill for lazy load (ampproject#7006) Refactor observables in viewer-impl into a map object (ampproject#7004) resizing of margins (ampproject#6824) Use URL replacer from embed for pixel (ampproject#7029) adds support for Gemius analytics (ampproject#6558) Avoid duplicating server-layout (ampproject#7021) Laterpay validator config (ampproject#6974) Validator rollup (ampproject#7023) skeleton for amp-tabs (ampproject#7003) Upgrade post-css and related packages to latest (ampproject#7020) handle unload (ampproject#7001) viewer-integr.js -> amp-viewer-integration (ampproject#6989) dev().info()->dev().fine() (ampproject#7017) Turned on experiment flag (ampproject#6774) Unlaunch ios-embed-wrapper for iOS8 to avoid scroll freezing issues (ampproject#7018) Add some A4A ad request parameters (ampproject#6643) ...
Allows the margins on an element to be changed via the attemptChangeSize function in resources-impl.js.
#6626