diff --git a/docs/api-reference/next/image.md b/docs/api-reference/next/image.md index 93f01c3615160..6ce19500a0134 100644 --- a/docs/api-reference/next/image.md +++ b/docs/api-reference/next/image.md @@ -113,6 +113,18 @@ Should only be used when the image is visible above the fold. Defaults to false. In some cases, you may need more advanced usage. The `Image` component optionally accepts the following advanced properties. +### objectFit + +The image fit when using `layout="fill"`. + +[Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) + +### objectPosition + +The image position when using `layout="fill"`. + +[Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/object-position) + ### loading The loading behavior of the image. Defaults to `lazy`. diff --git a/examples/image-component/pages/background.js b/examples/image-component/pages/background.js index d2bded5e1bb9f..b2680e7cd797c 100644 --- a/examples/image-component/pages/background.js +++ b/examples/image-component/pages/background.js @@ -1,5 +1,5 @@ import Image from 'next/image' -import { bgWrap, bgText, objectFitCover } from '../styles.module.css' +import { bgWrap, bgText } from '../styles.module.css' const Background = () => (
@@ -8,8 +8,8 @@ const Background = () => ( alt="Mountains" src="/mountains.jpg" layout="fill" + objectFit="cover" quality={100} - className={objectFitCover} />

diff --git a/examples/image-component/pages/layout-fill.js b/examples/image-component/pages/layout-fill.js index a65587cb6c928..824958478c581 100644 --- a/examples/image-component/pages/layout-fill.js +++ b/examples/image-component/pages/layout-fill.js @@ -1,9 +1,4 @@ import Image from 'next/image' -import { - objectFitContain, - objectFitCover, - objectFitNone, -} from '../styles.module.css' const Fill = () => (

@@ -13,7 +8,7 @@ const Fill = () => ( alt="Mountains" src="/mountains.jpg" layout="fill" - className={objectFitCover} + objectFit="cover" />
@@ -21,7 +16,7 @@ const Fill = () => ( alt="Mountains" src="/mountains.jpg" layout="fill" - className={objectFitContain} + objectFit="contain" />
@@ -29,7 +24,7 @@ const Fill = () => ( alt="Mountains" src="/mountains.jpg" layout="fill" - className={objectFitNone} + objectFit="none" quality={100} />
diff --git a/examples/image-component/styles.module.css b/examples/image-component/styles.module.css index 2186eedaa8eea..2e3e92d886a7e 100644 --- a/examples/image-component/styles.module.css +++ b/examples/image-component/styles.module.css @@ -48,13 +48,3 @@ padding-top: 40vh; text-shadow: 1px 1px 1px #3c5c5e; } - -.objectFitContain { - object-fit: contain; -} -.objectFitCover { - object-fit: cover; -} -.objectFitNone { - object-fit: none; -} diff --git a/packages/next/client/image.tsx b/packages/next/client/image.tsx index f3164d711a02f..12a48c7a5ab96 100644 --- a/packages/next/client/image.tsx +++ b/packages/next/client/image.tsx @@ -30,6 +30,8 @@ type ImageData = { domains?: string[] } +type ImgElementStyle = NonNullable + type ImageProps = Omit< JSX.IntrinsicElements['img'], 'src' | 'srcSet' | 'ref' | 'width' | 'height' | 'loading' | 'style' @@ -39,6 +41,8 @@ type ImageProps = Omit< priority?: boolean loading?: LoadingValue unoptimized?: boolean + objectFit?: ImgElementStyle['objectFit'] + objectPosition?: ImgElementStyle['objectPosition'] } & ( | { width?: never @@ -247,6 +251,8 @@ export default function Image({ quality, width, height, + objectFit, + objectPosition, ...all }: ImageProps) { const thisEl = useRef(null) @@ -342,7 +348,7 @@ export default function Image({ let wrapperStyle: JSX.IntrinsicElements['div']['style'] | undefined let sizerStyle: JSX.IntrinsicElements['div']['style'] | undefined let sizerSvg: string | undefined - let imgStyle: JSX.IntrinsicElements['img']['style'] = { + let imgStyle: ImgElementStyle | undefined = { visibility: lazy ? 'hidden' : 'visible', position: 'absolute', @@ -363,6 +369,9 @@ export default function Image({ maxWidth: '100%', minHeight: '100%', maxHeight: '100%', + + objectFit, + objectPosition, } if ( typeof widthInt !== 'undefined' && diff --git a/test/integration/image-component/default/pages/layout-fill.js b/test/integration/image-component/default/pages/layout-fill.js index 299e357175a4f..e442c041b9a2e 100644 --- a/test/integration/image-component/default/pages/layout-fill.js +++ b/test/integration/image-component/default/pages/layout-fill.js @@ -10,7 +10,13 @@ const Page = () => {

Layout Fill

- +

Layout Fill

diff --git a/test/integration/image-component/default/test/index.test.js b/test/integration/image-component/default/test/index.test.js index 4cf85eb54c121..35ad401a47a1d 100644 --- a/test/integration/image-component/default/test/index.test.js +++ b/test/integration/image-component/default/test/index.test.js @@ -294,6 +294,15 @@ function runTests(mode) { }) expect(await getComputed(browser, id, 'width')).toBe(smallWidth) expect(await getComputed(browser, id, 'height')).toBe(smallHeight) + + const objectFit = await browser.eval( + `document.getElementById("${id}").style.objectFit` + ) + const objectPosition = await browser.eval( + `document.getElementById("${id}").style.objectPosition` + ) + expect(objectFit).toBe('cover') + expect(objectPosition).toBe('left center') } finally { if (browser) { await browser.close() diff --git a/test/integration/image-component/typescript/pages/valid.tsx b/test/integration/image-component/typescript/pages/valid.tsx index dede52cea1448..640211ea9c560 100644 --- a/test/integration/image-component/typescript/pages/valid.tsx +++ b/test/integration/image-component/typescript/pages/valid.tsx @@ -44,6 +44,20 @@ const Page = () => { width={100} height={100} /> + +

This is valid usage of the Image component

)