-
-
Notifications
You must be signed in to change notification settings - Fork 827
Implement slightly magical CSS soln. to thumbnail sizing #1912
Conversation
As the slightly nicer alternative to fixupHeight being applied once we actually have a timelineWidth. The niceness comes from not needing timelineWidth, which means we can implement at render time with CSS. (Despite still calculating aspect ratios when we render.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be using the same logic for stickers? Since this just removes the width / height fixing for stickers without replacing it with anything.
.mx_MImageBody_thumbnail_container { | ||
// Prevent the padding-bottom (added inline in MImageBody.js) from | ||
// effecting elements below the container. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
affecting ;)
"display": "flex", | ||
"alignItems": "center", | ||
"width": "100%", | ||
}}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we put these in the stylesheet?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can indeed!
In theory they can be sized in the same way as images, albeit with their natural width/height halved on non hdpi displays. Edit: remove annoyingly big screenshots. |
The benefits of this: - One code path for determining spinner/placeholder and it's position for loading images/stickers. This includes spinner used in e2e decryption of images. - Very small definition for MStickerBody, only overriding the minimal differences is has from MImageBody. The disadvantages: - Slightly more complicated MImageBody, but hopefully not less readable.
I may have gone overboard by factoring out all shared logic between stickers and images. As explained in the commit message: The benefits of this:
The disadvantages:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
otherwise lgtm
"display": showPlaceholder ? undefined : 'none', | ||
// Constrain width here so that spinner appears central to the loaded thumbnail | ||
"max-width": content.info.w + "px", | ||
}}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why put the thing in the dom with display: none if there's no placeholder (as opposed to not putting it in at all?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair, the placeholder doesn't need to be there at all
// which may well be much smaller than the 800x600 bounding box. | ||
<div style={{display: !showPlaceholder ? undefined : 'none'}}> | ||
{ img } | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above re: display: none
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The <img>
does have to be in the DOM so that it can load during which time the placeholder is shown.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh right, of course
this.fixupHeight(); | ||
_messageContent(contentUrl, thumbUrl, content) { | ||
// The maximum height of the thumbnail as it is rendered as an <img> | ||
const maxHeight = Math.min(THUMBNAIL_MAX_HEIGHT, content.info.h); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what happens if the image (or thumbnail) has no explicit width & height?
If the event has an explicit thumbnail (e.g. e2e image), shouldn't we be looking at the thumbnails dims here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Apparently thumnbnail_info
is provided for e2e and non-e2e images.)
Previously, we didn't use thumbnail_info
in the process of calculating the height of the thumbnail in the timeline. We could do but it would be a change in functionality.
_messageContent(contentUrl, thumbUrl, content) { | ||
// The maximum height of the thumbnail as it is rendered as an <img> | ||
const maxHeight = Math.min(THUMBNAIL_MAX_HEIGHT, content.info.h); | ||
// The maximum width of the thumbnail, as dictated by it's natural |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its
this.fixupHeight(); | ||
_messageContent(contentUrl, thumbUrl, content) { | ||
// The maximum height of the thumbnail as it is rendered as an <img> | ||
const maxHeight = Math.min(THUMBNAIL_MAX_HEIGHT, content.info.h); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still really surprised that we can't just set max-height: 600px
on the image rather than calculating this in JS...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be frank, using CSS/JS is irrelevant. We restrict the height of the image with max-height
. If we use 600px then all thumbnails will be 600px high (because of the magical padding-bottom).
The image should be a maximum height of 600px or, if it's less, the given info.h
.
Just checking that this has been manually tested and checked for flickering in:
...all both in a wide browser window and a narrow (<800px) window? Also, are videos and other file types going to bite us in the same way? |
Nothing was changed wrt other event types. Edit: Although Edit: Turns out MVideoBody loading spinner was actually broken by this PR before 538979a was committed. MVideoBody still does its own thumbnail sizing and I suggest we keep that out of scope for now. (Video thumbnails are broken on small timelines regardless of this PR). |
These changes don't change our current failure mode under these circumstances, which is to not show any image in the timeline - we just show the "Download..." link. |
@dbkr, i'm finding it quite hard to gauge whether this is going to be a maintainability/stability improvement over your JS-based fix - wdyt? (post-GDPR) |
Hmm, I would quite like to get rid of the fixupHeight thing, especially the fact that it manipulates to dom directly after mounting and uses slightly different code paths for stickers and images. My inclination is this is probably worthwhile. |
To summarise the key changes:
|
it looks net positive to me, but i'm scared of the risk of breaking something which is otherwise working right now, especially without test coverage. however, given we've manually tested it, i'm happy to risk it. |
Also, we'll get a lot of testing on |
Prior to #1912, height fix up of image events without an `info` in their content would fail, setting `style.height = null + "px"`. Now that all thumbnail sizing is done through one path, we can fix the same problem for all cases (images, stickers, e2e/non-e2e) by handling images without `info` correctly. At the bare minimum, we use a null-guard that will make sure an image without an `info` does not appear in the timeline (as a spinner or otherwise until loaded). When loaded, we size it like any other image by using the natural dimensions of the loaded image in place of `info`. Note that we do not apply the same logic to images that *do* specify an `info` with `w` and `h` keys. If the aspect ratio of the image does not match that of the event, we use the one in `info` even when the image has loaded.
See http://www.mademyday.de/css-height-equals-width-with-pure-css.html for details on how this works.
It relies on being able to set
padding-bottom
to a percentage which is the aspect ratio of the thumbnail.This change attempts to be restricted to sizing of the thumbnail, the logic of when to display a thumbnail, spinner for decryption should be the same. It could use some improvement though as the conditions on displaying certain views are quite unclear.
Fixes element-hq/element-web#6722