Skip to content
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

Add new 'raw' image layout #34339

Merged
merged 62 commits into from Mar 14, 2022
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
889a3c8
Update framework chunk test regex to not select nested dependencies
atcastle Oct 9, 2019
ebafcca
Update webpack-config.ts
Timer Oct 14, 2019
7ab3c8a
Merge branch 'canary' into canary
Timer Oct 14, 2019
2c62327
Add support for raw layout mode
atcastle Feb 14, 2022
4c769d3
Update image documentation for raw layout
atcastle Feb 14, 2022
5843826
documentation autoformatting
atcastle Feb 14, 2022
4252ffb
change typescript text fixture
atcastle Feb 14, 2022
c4fa96b
Merge remote-tracking branch 'origin' into image-layout-raw
atcastle Feb 16, 2022
4006b36
Refactor base image element in image component. Remove raw layout sup…
atcastle Feb 17, 2022
efad4b8
lint fixes
atcastle Feb 17, 2022
26a6103
lint fixes
atcastle Feb 17, 2022
f32440d
Fix typescript test
atcastle Feb 17, 2022
78904f2
fix tests
atcastle Feb 17, 2022
c457914
lint fix
atcastle Feb 17, 2022
bdd8836
Merge remote-tracking branch 'origin' into image-layout-raw
atcastle Feb 17, 2022
e812837
Allow all layouts to use style prop
atcastle Feb 18, 2022
90c778d
Move ImageElement component outside of Image
atcastle Feb 18, 2022
34411f2
Fix handling of noscript image attributes
atcastle Feb 18, 2022
64a0b70
lint fix
atcastle Feb 19, 2022
435091e
Merge remote-tracking branch 'origin' into image-layout-raw
atcastle Feb 19, 2022
2be4e4e
Merge remote-tracking branch 'origin' into image-layout-raw
atcastle Feb 19, 2022
6c9a9e4
Update docs to show style is now allowed on image componenet
atcastle Feb 19, 2022
d9f51f1
Additional test coverage for image style prop and raw
atcastle Feb 20, 2022
ebf5812
auto-lint
atcastle Feb 22, 2022
80ffd7e
Add support for priority to raw image and test it
atcastle Feb 22, 2022
b4fdc15
image.md wording tweak
atcastle Feb 22, 2022
24cf3dc
Test coverage for srcset behavior in raw layout
atcastle Feb 22, 2022
8c12019
Remove test focus
atcastle Feb 22, 2022
74ac553
Update docs/api-reference/next/image.md
atcastle Feb 22, 2022
8904782
Remove raw from ImageProps type and delete typescript-style test suite
atcastle Feb 23, 2022
2f91512
auto-lint
atcastle Feb 23, 2022
cac28f0
Documentation updates and move sizes overwrite warning
atcastle Feb 23, 2022
3be7243
auto-lint
atcastle Mar 9, 2022
9c5b9b8
Update packages/next/client/image.tsx
atcastle Mar 9, 2022
adb3a57
Update docs/api-reference/next/image.md
atcastle Mar 9, 2022
dd21513
Merge branch 'image-layout-raw' of github.com:atcastle/next.js into i…
atcastle Mar 9, 2022
6baa8be
auto-lint
atcastle Mar 9, 2022
19ffddc
Merge remote-tracking branch 'upstream/canary' into image-layout-raw
atcastle Mar 9, 2022
e03c65b
Add experimental flag for raw layout mode
atcastle Mar 9, 2022
20955eb
Fix image style test
atcastle Mar 9, 2022
b64bda7
Add aspect-ratio for raw images and only add height/width without sizes
atcastle Mar 9, 2022
78b9434
Update packages/next/client/image.tsx
atcastle Mar 9, 2022
7338c3a
Update docs/api-reference/next/image.md
atcastle Mar 9, 2022
bc42437
update docs for experimental raw layout
atcastle Mar 9, 2022
5eea550
Fix markdown links
atcastle Mar 9, 2022
d3d82b6
Documentation wording change
atcastle Mar 9, 2022
57edfe0
Merge branch 'canary' of github.com:atcastle/next.js into canary
atcastle Mar 10, 2022
d4e19f2
Merge branch 'canary' into image-layout-raw
atcastle Mar 10, 2022
a3aae1b
Merge branch 'canary' into image-layout-raw
atcastle Mar 10, 2022
2e6e84d
Merge branch 'image-layout-raw' of github.com:atcastle/next.js into i…
atcastle Mar 10, 2022
7525553
Fix type from merge
atcastle Mar 10, 2022
9f41f20
Update packages/next/client/image.tsx
atcastle Mar 10, 2022
c4654fa
Update docs/api-reference/next/image.md
atcastle Mar 10, 2022
820b152
Update packages/next/client/image.tsx
atcastle Mar 10, 2022
8563475
change to isLazy image element prop
atcastle Mar 10, 2022
74076ff
Merge branch 'image-layout-raw' of github.com:atcastle/next.js into i…
atcastle Mar 10, 2022
a000df1
clean up image element props
atcastle Mar 10, 2022
d48b36a
Use optional chaining for experimeental image opts
atcastle Mar 10, 2022
531b623
Add placeholder to imgElementArgs
atcastle Mar 10, 2022
d22691d
Only throw experimentalRaw error in non-prod
atcastle Mar 10, 2022
b5b1375
Apply suggestions from code review
styfle Mar 14, 2022
6a5ffac
Merge branch 'canary' into image-layout-raw
styfle Mar 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 18 additions & 8 deletions docs/api-reference/next/image.md
Expand Up @@ -16,6 +16,7 @@ description: Enable Image Optimization with the built-in Image component.

| Version | Changes |
| --------- | ------------------------------------------------------------------------------------------------- |
| `v12.1.1` | `raw` layout added. Support added for `style` prop. |
atcastle marked this conversation as resolved.
Show resolved Hide resolved
| `v12.1.0` | `dangerouslyAllowSVG` and `contentSecurityPolicy` configuration added. |
| `v12.0.9` | `lazyRoot` prop added. |
| `v12.0.0` | `formats` configuration added.<br/>AVIF support added.<br/>Wrapper `<div>` changed to `<span>`. |
Expand Down Expand Up @@ -65,12 +66,13 @@ The `<Image />` component accepts a number of additional properties beyond those

The layout behavior of the image as the viewport changes size.

| `layout` | Behavior | `srcSet` | `sizes` |
| --------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------- |
| `intrinsic` (default) | Scale *down* to fit width of container, up to image size | `1x`, `2x` (based on [imageSizes](#image-sizes)) | N/A |
| `fixed` | Sized to `width` and `height` exactly | `1x`, `2x` (based on [imageSizes](#image-sizes)) | N/A |
| `responsive` | Scale to fit width of container | `640w`, `750w`, ... `2048w`, `3840w` (based on [imageSizes](#image-sizes) and [deviceSizes](#device-sizes)) | `100vw` |
| `fill` | Grow in both X and Y axes to fill container | `640w`, `750w`, ... `2048w`, `3840w` (based on [imageSizes](#image-sizes) and [deviceSizes](#device-sizes)) | `100vw` |
| `layout` | Behavior | `srcSet` | `sizes` | Has wrapper and sizer |
| --------------------- | -------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------- | --------------------- |
| `intrinsic` (default) | Scale *down* to fit width of container, up to image size | `1x`, `2x` (based on [imageSizes](#image-sizes)) | N/A | yes |
| `fixed` | Sized to `width` and `height` exactly | `1x`, `2x` (based on [imageSizes](#image-sizes)) | N/A | yes |
| `responsive` | Scale to fit width of container | `640w`, `750w`, ... `2048w`, `3840w` (based on [imageSizes](#image-sizes) and [deviceSizes](#device-sizes)) | `100vw` | yes |
| `fill` | Grow in both X and Y axes to fill container | `640w`, `750w`, ... `2048w`, `3840w` (based on [imageSizes](#image-sizes) and [deviceSizes](#device-sizes)) | `100vw` | yes |
| `raw` | Insert the image element with no automatic layout behavior | Behaves like `responsive` if the images has the `sizes` prop, and like `fixed` if it does not | optional| no |
atcastle marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like "Behaves like responsive if the images has the sizes prop" isn't true right now because it doesnt automatically stretch to fit the viewport like responsive does. This is because the width and height props go directly to the underlying <img>.

It seems like we need a way to maintain aspect ratio from width/height without setting the attributes to get the true responsive behavior.

Copy link
Collaborator

@kara kara Mar 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re docs: maybe instead of trying to make direct comparisons to other layout modes, we can just list what the srcset is directly for both cases (e.g. '1x', '2x' if sizes is set, otherwise '640w750w, ... 2048w3840w (based on imageSizes and deviceSizes). But then there's still the issue of aspect ratio.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @kara , the whole purpose of raw is to not add layout behaviors.

The "responsive" behavior from the browser is to download the right image version according to height, width, sizes and srcset attributes. Nothing should come in the way of of this.

I'd even argue if a user passes srcset prop when in raw layout, the values from the user should be passed directly to the <img> without any modification.

I think a default of 1x/2x or 640w, 750w, ...,3840w depending if sizes is set or not is fine, just don't prevent people from generating their own srcset. What I consider should always be 640w, ...3840w might be different for another person and vice versa. The whole point of raw is to give back the power to users, defaults are welcome if not forced on you.


- [Demo the `intrinsic` layout (default)](https://image-component.nextjs.gallery/layout-intrinsic)
- When `intrinsic`, the image will scale the dimensions down for smaller viewports, but maintain the original dimensions for larger viewports.
Expand All @@ -83,6 +85,9 @@ The layout behavior of the image as the viewport changes size.
- When `fill`, the image will stretch both width and height to the dimensions of the parent element, provided the parent element is relative.
- This is usually paired with the [`objectFit`](#objectFit) property.
- Ensure the parent element has `position: relative` in their stylesheet.
- When `raw`, the image will be rendered as a single image element with no wrappers, sizers or other responsive behavior.
- If your image styling will change the size of a `raw` image, you should include the `sizes` property for proper image serving.
- The other layout modes are optimized for performance and should cover nearly all use cases. It is recommended to try to use those modes before using `raw`.
- [Demo background image](https://image-component.nextjs.gallery/background)

### loader
Expand Down Expand Up @@ -121,7 +126,7 @@ const MyImage = (props) => {

A string that provides information about how wide the image will be at different breakpoints. Defaults to `100vw` (the full width of the screen) when using `layout="responsive"` or `layout="fill"`.

If you are using `layout="fill"` or `layout="responsive"`, it's important to assign `sizes` for any image that takes up less than the full viewport width.
If you are using `layout="fill"`, `layout="responsive"`, or `layout="raw"` it's important to assign `sizes` for any image that takes up less than the full viewport width.

For example, when the parent element will constrain the image to always be less than half the viewport width, use `sizes="50vw"`. Without `sizes`, the image will be sent at twice the necessary resolution, decreasing performance.

Expand Down Expand Up @@ -162,6 +167,12 @@ Try it out:

In some cases, you may need more advanced usage. The `<Image />` component optionally accepts the following advanced properties.

### style

Allows [passing CSS styles](https://reactjs.org/docs/dom-elements.html#style) to the underlying image element.

Note that all `layout` modes other than `"raw"` apply their own styles to the image element, and these automatic styles take precedence over the `style` prop.

### objectFit

Defines how the image will fit into its parent container when using `layout="fill"`.
Expand Down Expand Up @@ -285,7 +296,6 @@ size, or format. Defaults to `false`.
Other properties on the `<Image />` component will be passed to the underlying
`img` element with the exception of the following:

- `style`. Use `className` instead.
- `srcSet`. Use
[Device Sizes](#device-sizes)
instead.
Expand Down
4 changes: 2 additions & 2 deletions docs/basic-features/image-optimization.md
Expand Up @@ -181,15 +181,15 @@ The image component has several different [layout modes](/docs/api-reference/nex

**Target the image with className, not based on DOM structure**

Regardless of the layout mode used, the Image component will have a consistent DOM structure of one `<img>` tag wrapped by exactly one `<span>`. For some modes, it may also have a sibling `<span>` for spacing. These additional `<span>` elements are critical to allow the component to prevent layout shifts.
For most layout modes, the Image component will have a DOM structure of one `<img>` tag wrapped by exactly one `<span>`. For some modes, it may also have a sibling `<span>` for spacing. These additional `<span>` elements are critical to allow the component to prevent layout shifts. Images with `layout="raw"` will rendered without any wrapper elements or sizers.

The recommended way to style the inner `<img>` is to set the `className` prop on the Image component to the value of an imported [CSS Module](/docs/basic-features/built-in-css-support.md#adding-component-level-css). The value of `className` will be automatically applied to the underlying `<img>` element.

Alternatively, you can import a [global stylesheet](/docs/basic-features/built-in-css-support#adding-a-global-stylesheet) and manually set the `className` prop to the same name used in the global stylesheet.

You cannot use [styled-jsx](/docs/basic-features/built-in-css-support.md#css-in-js) because it's scoped to the current component.

You cannot use the `style` prop because the `<Image>` component does not pass it through to the underlying `<img>`.
> An additional `raw` layout mode is provided which removes the wrapper and sizer elements. This mode still requires `height` and `width` and is recommended only for advanced use cases that aren't covered by the primary layout modes.

**When using `layout='fill'`, the parent element must have `position: relative`**

Expand Down