The Mountain (background)
Dan Sorensen
Published on

Explaining the Next Image Layout Options

Authors
  • avatar
    Name
    Dan Sorensen
    Twitter

The Next/Image Tag

The Next/Image tag automatically serves images optimized to the client screen size. Layout modes allow limited adjustments to the responsive resizing behavior.

Modes:

  • Intrinsic (default)
  • Fixed
  • Responsive
  • Fill

To achive this magic, Next wraps an image in span tags and uses the srcset feature with compatible browsers.

Wrapper Styles

Next/Image wraps the HTML img tag with a span. Styles are applied to the span wrapper depending on the mode selected.

Default span wrapper styles:

const wrapperStyle: JSX.IntrinsicElements['span']['style'] = {
  boxSizing: 'border-box',
  display: 'block',
  overflow: 'hidden',
  width: 'initial',
  height: 'initial',
  background: 'none',
  opacity: 1,
  border: 0,
  margin: 0,
  padding: 0,
}

Layout Mode: Intrinsic (default)

According to the docs, the intrinsic setting "Scale[s] down to fit width of container, up to image size."

Line 617-624:

 } else if (layout === 'intrinsic') {
      // <Image src="i.png" width="100" height="100" layout="intrinsic" />
      wrapperStyle.display = 'inline-block'
      wrapperStyle.position = 'relative'
      wrapperStyle.maxWidth = '100%'
      hasSizer = true
      sizerStyle.maxWidth = '100%'
      sizerSvgUrl = `data:image/svg+xml,%3csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20version=%271.1%27%20width=%27${widthInt}%27%20height=%27${heightInt}%27/%3e`

The generated span wrapper: (defaults omitted)

<span
  style="
    display:inline-block;
    position:relative;
    max-width:100%"
  ...
>
  ...
</span>

Layout Mode: Fixed

When using the fixed style, you must also set the height and width.

<image src="..." layout="fixed" height="400" width="1024" />

Line 625-630 describes the fixed overrides:

} else if (layout === 'fixed') {
      // <Image src="i.png" width="100" height="100" layout="fixed" />
      wrapperStyle.display = 'inline-block'
      wrapperStyle.position = 'relative'
      wrapperStyle.width = widthInt
      wrapperStyle.height = heightInt

The generated span wrapper: (defaults omitted)

<span
  style="
    display:inline-block;
    width:1024px;
    height:400px;
    position:relative"
>
  ...
</span>

Layout Mode: Responsive

When using the responsive style, you must also set the height and width.

<image src="..." layout="responsive" height="400" width="1024" />

Line 611-616:

if (layout === 'responsive') {
      // <Image src="i.png" width="100" height="100" layout="responsive" />
      wrapperStyle.display = 'block'
      wrapperStyle.position = 'relative'
      hasSizer = true
      sizerStyle.paddingTop = paddingTop

Generated span wrapper styles. This includes a span above the image, called a 'sizer' to keep the image positioned on resize. The top padding is calucated based on the image size.

const quotient = heightInt / widthInt
const paddingTop = isNaN(quotient) ? '100%' : `${quotient * 100}%`

See Chris Coyier's Aspect Ratio Boxes for an explanation of this technique.

<span
  style="
    position:relative"
>
  <span
    style="
            display:block;
            padding:0;
            padding-top:39.0625%"
  >
  </span>
  ...
</span>

Layout Mode: Fill

Image Tag Source:596-603:

Line 596-603:

if (layout === 'fill') {
    // <Image src="i.png" layout="fill" />
    wrapperStyle.display = 'block'
    wrapperStyle.position = 'absolute'
    wrapperStyle.top = 0
    wrapperStyle.left = 0
    wrapperStyle.bottom = 0
    wrapperStyle.right = 0