Next.js: [next/image] flash broken image placeholder (alt text and white border) before load image

Created on 29 Oct 2020  路  4Comments  路  Source: vercel/next.js

Bug report

Describe the bug

I use next/image component and after reload page I see blink alt (attribute alt) text.

To Reproduce

  1. Use next/image component
  2. Reload page

Expected behavior

  1. Show alt text if image didn't load (404 error for example)
  2. If I have good image I shouldn't see flash broken image placeholder

Screenshots

https://monosnap.com/file/BjNLnRZMWmwG5NugYk8TuDm3VZ6tez

screen from video above (timecode 8sec)
Screenshot 2020-10-29 133243

System information

  • OS: Windows 10
  • Browser: Latest Edge, Latest Firefox
  • Version of Next.js: 10
  • Version of Node.js: 14.13

Additional context

My code:

import Link from 'next/link'
import Image from 'next/image'
import slugify from '@sindresorhus/slugify'
import format from 'date-fns/format'
import isToday from 'date-fns/isToday'
import isTomorrow from 'date-fns/isTomorrow'
import ru from 'date-fns/locale/ru'
import cx from 'classnames'
import { ReleaseType, ReleaseInList } from 'types/common'
import PlatformList from '../PlatformList'
import Text from '../Text'
import ExpectButton from '../ExpectButton'

import styles from './styles.module.css'

export enum Source {
  Calendar = 'calendar',
  Today = 'today',
  Profile = 'profile',
}

function renderDate(today: boolean, tomorrow: boolean, date: Date) {
  if (today) return '褋械谐芯写薪褟'

  if (tomorrow) return '蟹邪胁褌褉邪'

  return format(date, 'EEEEEE, d MMM', {
    locale: ru,
  })
}

interface Props {
  release: ReleaseInList
  source: Source
}

function ReleaseCard({ release, source }: Props) {
  const { title, released, release_id } = release

  const releasedDate = new Date(released)

  const slug = slugify(title)
  const today = isToday(releasedDate)
  const tomorrow = isTomorrow(releasedDate)

  return (
    <Link href="/release/[id]" as={`/release/${release_id}-${slug}`}>
      <a className={styles.ReleaseCard}>
        <div className={styles.Header}>
          <div
            className={cx(styles.Date, {
              [styles.isToday]: today,
            })}
          >
            {renderDate(today, tomorrow, releasedDate)}
          </div>
          <ExpectButton release={release} />
        </div>
        <div className={styles.Cover}>
          <Image src={release.cover} alt={release.title} unsized />
        </div>
        <div className={styles.Footer}>
          <Text className={styles.Title}>{release.title}</Text>
          {release.type === ReleaseType.Films && (
            <Text secondary i className={styles.Info}>
              {release.director}
            </Text>
          )}
          {release.type === ReleaseType.Series && (
            <Text secondary i className={styles.Info}>
              {release.season} 褋械蟹芯薪
            </Text>
          )}
          {release.type === ReleaseType.Games && (
            <PlatformList platforms={release.platforms} />
          )}
        </div>
      </a>
    </Link>
  )
}

export default ReleaseCard
.Cover {
  display: flex;
  width: 100%;
  height: 100%;
  background-color: #000;
  transition: opacity 250ms;

  &::after {
    position: absolute;
    top: 20%;
    left: 0;
    width: 100%;
    height: 80%;
    background-image: var(--release-card-cover-gradient);
    content: '';
  }

  * {
    width: 100%;
    height: 100%;
  }

  img {
    object-fit: cover;
  }
}

When I use lazysizes I had similar problem, but I fix it like this

You can check it

const IMG_PLACEHOLDER = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='

function Image({
  lazy = true,
  src,
  alt = '',
  ...rest
}: Props & HTMLAttributes<HTMLImageElement>) {
  const isAmp = useAmp()

  if (isAmp) {
    return <amp-img src={src} alt={alt} layout="fill" {...rest} />
  }

  if (lazy) {
    return (
      <img
        className="lazyload"
        src={IMG_PLACEHOLDER} // It is fix that problem
        data-src={src}
        alt={alt}
        {...rest}
      />
    )
  }

  return <img  src={src} alt={alt} {...rest} />
}
bug please add a complete reproduction 3 p1 needs investigation

Most helpful comment

@Timer, it reproduce if I add alt text to images, but it important part for SEO

Repo: https://github.com/shashkovdanil/reproduce-nextjs-bug

Flash moment:
Screenshot 2020-10-31 130839

After ~1-2ms
Screenshot 2020-10-31 130856

All 4 comments

Please provide a full reproduction so we can take a look!

@Timer, it reproduce if I add alt text to images, but it important part for SEO

Repo: https://github.com/shashkovdanil/reproduce-nextjs-bug

Flash moment:
Screenshot 2020-10-31 130839

After ~1-2ms
Screenshot 2020-10-31 130856

I believe this is fixed on canary.

Please visit https://image-component.nextjs.gallery or try this example locally to confirm.

This was fixed in PR #18903

Was this page helpful?
0 / 5 - 0 ratings