-
Notifications
You must be signed in to change notification settings - Fork 64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: implement responsiveness with srcSet and sizes #159
Conversation
* chore(readme): fix typo in readme * chore(readme): edit codesandbox iframes to be links instead
- generateSrcSet -> disableSrcSet - remove aggressiveLoad - remove precision - add sizes top-level prop
- generateSrcSet -> disableSrcSet - remove - remove precision - add sizes top-level prop - remove empty img - remove defaultWidth and defaultHeight - remove fluid prop - remove auto-sizing behaviour in favour of srcsets - add check to ensure sizes is passed when in image mode and no width and heights have been passed
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.
A couple of small changes, but by and large this looks great.
The biggest issue I have is with the availWidth
and availHeight
constants--are they even necessary at this point? We already decided that they shouldn't be used to cap the list of generated widths at a specific size, so I'm not sure they have any use anymore.
README.md
Outdated
|
||
For server rendering, `aggressiveLoad` should be used. This component renders nothing on the first render as it tries to work out what the size of the container it will be rendering in, and only loads an image at the resolution required. For server rendering this will mean no image will be rendered. | ||
Since imgix can generate as many derivative resolutions as needed, react-imgix calculates them programmatically, using the dimensions you specify (note that the w and h params scale appropriately to maintain the correct aspect ratio). All of this information has been placed into the srcset and sizes attributes. |
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.
Maybe I'm missing something, but what's up with the bit about w
and h
scaling properly? This isn't exemplified in the above code.
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.
Whoops, I was planning to do this but didn't get around to it. I might pull this out and put it in a separate issue
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.
Removed from PR and added to #161
src/constants.js
Outdated
@@ -0,0 +1,6 @@ | |||
const CONSTANTS = { | |||
availWidth: window.screen.availWidth, |
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 can't find good data about browser support for this. Have we verified that window.screen
is available on all browsers we support?
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 realise now this isn't used anymore anyway so I'll just remove it.
|
||
const roundToNearest = (size, precision) => | ||
precision * Math.ceil(size / precision); | ||
const NODE_ENV = process.env.NODE_ENV; |
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.
Interesting. How does this end up manifesting when this code is run in-browser?
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.
This is an extremely common pattern which is used everywhere in React. It is usually defined by webpack plugin or webpack itself.
src/react-imgix.js
Outdated
if (props.crop) crop = props.crop; | ||
|
||
let fit = false; | ||
if (entropy) fit = "crop"; |
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 think this should be if (entropy || faces)
?
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.
Updated
let srcSet; | ||
|
||
if (disableSrcSet) { | ||
srcSet = src; |
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.
Hmm... the disabledSrcSet
option doesn't actually disabled srcset
. Is that bad? Maybe there's no good reason not to just set it anyway as we're doing here, but if the option says "don't set it" the user expectation might be that it doesn't get set. I don't feel strongly either way, but it's food for thought.
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'll be honest, it isn't very clear, by just reading this section of the code, what the actual behaviour is. I'll explain:
option says "don't set it" the user expectation might be that it doesn't get set
This is the actual behaviour. This value is not automatically applied to rendered element. For an img
, if disableSrcSet
is set then srcSet
is not applied. For a source
, if srcSet
is set then the srcSet
attribute is simply the source, without any px
or w
generations applied. For source
this is desired as srcSet
is required in this case.
Does this make more sense? Is there a way we can improve the code?
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.
Yea, I'm on board now 👍
src/react-imgix.js
Outdated
const addFallbackSrc = srcSet => srcSet.concat(`, ${src}`); | ||
const _srcSet = targetWidths.map(buildSrcSetPair).join(", "); | ||
const _srcSetWithFallback = addFallbackSrc(_srcSet); | ||
srcSet = _srcSetWithFallback; |
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.
This seems like a really convoluted way of doing this. How about just doing this?
srcSet = targetWidths.map(buildSrcSetPair).concat([src]).join(", ");
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.
My aim with _srcSetWithFallback
was to make clear what the added src
was for. Would this work?
const addFallbackSrc = srcSet => srcSet.concat(src);
const _srcSet = targetWidths.map(buildSrcSetPair);
const _srcSetWithFallback = addFallbackSrc(_srcSet);
srcSet = _srcSetWithFallback.join(', ');
or even
const addFallbackSrc = srcSet => srcSet.concat(src);
srcSet = addFallbackSrc(targetWidths.map(buildSrcSetPair)).join(', ');
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 think either one of those is an improvement over the code as it's currently written, yea.
}); | ||
} | ||
|
||
export default targetWidths(); |
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.
This is an excellent update to the crusty version found in imgix.js, thank you. At some point in the near future I'd love to pull this out into its own repo with a JSON distributable a la https://github.com/imgix/imgix-url-params.
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.
Thank you. That sounds like a great idea.
src/targetWidths.js
Outdated
|
||
import CONSTANTS from "./constants"; | ||
|
||
const _screen = { |
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.
Is this constant even used?
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.
No, I forgot to remove it when I did the update.
Thanks for the review @jayeb. You're dead right with the constants - I've removed them. |
Okay @jayeb I think I've covered everything discussed here - are you able to give this a quick review? |
* version-8: docs: add link to fluid example and fix some links docs: add example about fitting to the size of the container docs: add ref information feat: refactor picture and source behaviour into different components (#163) feat: reduce props API surface area (#162) feat: implement responsiveness with srcSet and sizes (#159) fix: warn the user when no <img> passed as a child to <picture> fixes #90 (#151) # Conflicts: # README.md
BREAKING CHANGE:
type=bg
has been removedDescription
This PR fundamentally changes the approach taken to responsiveness. Previously, the image (or component) was rendered with an empty image, and the size of the resulting DOM element was measured. An image was loaded with these dimensions, ensuring that the image loaded was only as large as needed. Now, this component achieves the same behaviour by leveraging new native browser features,
srcSet
andsizes
. This allows the browser to load an appropriate size based on the expected image size, which is calculated based onsizes
. This has an added benefit that images can load much quicker as the browser can load them as soon as page layout has completed, or sooner (e.g. if sizes is100vw
). Overall this change has made both the usage of the library and the internals simpler and easier to understand.The significant amount of breaking changes makes sense due to a lot of the props no longer making sense. Background mode has also been removed as it was incompatible with the new method of responsiveness, and after discussion with @jayeb it seemed that it wouldn't be missed (based on a similar change that imgix.js made).
Picture mode still doesn't work amazingly, as there is a mis-match between what a developer would expect to set as props and what they actually have to set to make picture work as they want. This is not a problem with our library per se, but with
picture
pecularities. For example, if the fallbackimg
in a<picture>
has awidth
attribute set, all the other sources will also be locked to that size, even if they specify their own widths. Maybe this is common knowledge but it seems peculiar to me. I expect to address this and make it clearer for developers in a future PR.This PR closes #153. This PR closes #115. This PR closes #71
Checklist
Please use the checklist that is most closely related to your PR (you only need to use one checklist, and you can skip items that aren't applicable or don't make sense):
New Feature
feat(<area>): added new way to do this cool thing #issue-number
Steps to Test
Observe changes to unit tests.
It may also be worth to set up a test project and use
npm link
to check default image rendering and picture rendering.