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

Gatsby-image: Placeholder image causes screen readers to read each image twice. #8579

Closed
AlmeroSteyn opened this issue Sep 27, 2018 · 7 comments · Fixed by #8671
Closed

Gatsby-image: Placeholder image causes screen readers to read each image twice. #8579

AlmeroSteyn opened this issue Sep 27, 2018 · 7 comments · Fixed by #8671
Assignees
Labels
type: bug An issue or pull request relating to a bug in Gatsby

Comments

@AlmeroSteyn
Copy link
Contributor

AlmeroSteyn commented Sep 27, 2018

Description

Because the placeholder image remains visible in the DOM, screen readers will encounter both images and read the image tag, as well as the alt text.

This means that each image is duplicated for screen reader users.

I am using Gatsby V2 with gatsby-image v2.0.9.

I tested this behaviour with NVDA in Firefox and iOS VoiceOver in Safari. Both setups read duplicate images.

Steps to reproduce

Add the Img from gatsby-image and browse the resulting web page with a screen reader.

I am not adding any code as this happens for all instances.

Expected result

When navigating the web page with a screen reader, every unique image should only be read out once.

Actual result

Every image is read out twice as the screen reader first encounters the placeholder image and then the actual image.

Suggested fix

This issue can be reliably prevented through the use of display:none as elements with this does not get read out by screen readers.

Therefore, applying display:none to the main image until it is loaded, and then applying display:none to the placeholder image.

Here is my current workaround for the placeholder image part. I cannot also apply this fix to the main image whilst loading, as the imgStyle is applied to the placeholder as well.

import React, { Component } from 'react';
import Img from 'gatsby-image';

class SafeImg extends Component {
  state = {
    placeholderExtraStyle: {}
  };

  onLoadHandler = () => {
    const { onLoad } = this.props;

    setTimeout(() => {
      this.setState({
        placeholderExtraStyle: { display: 'none' }
      });
    }, 500);

    if (onLoad) {
      onLoad();
    }
  };

  render() {
    const { placeholderStyle = {}, onLoad, ...props } = this.props;

    const { placeholderExtraStyle } = this.state;

    return (
      <Img
        onLoad={this.onLoadHandler}
        placeholderStyle={{ ...placeholderStyle, ...placeholderExtraStyle }}
        {...props}
      />
    );
  }
}

export default SafeImg;

Environment

System:
OS: Windows 10
CPU: x64 Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
Binaries:
Yarn: 1.9.4 - C:\Program Files (x86)\Yarn\bin\yarn.CMD
npm: 5.6.0 - C:\Program Files\nodejs\npm.CMD
npmPackages:
gatsby: ^2.0.0 => 2.0.6
gatsby-image: ^2.0.9 => 2.0.9
gatsby-plugin-manifest: ^2.0.2 => 2.0.2
gatsby-plugin-offline: ^2.0.5 => 2.0.5
gatsby-plugin-react-helmet: ^3.0.0 => 3.0.0
gatsby-plugin-sass: ^2.0.1 => 2.0.1
gatsby-source-datocms: ^2.0.0-alpha.6 => 2.0.0-alpha.6

@pieh
Copy link
Contributor

pieh commented Sep 27, 2018

Because of that fade transition there still will be short timespan where 2 images are visible. Would removing alt and title from placeholder image once we start showing actual showing solve this? Or would screen readers still announce placeholder image even if it's without alt or title?

@pieh pieh added type: bug An issue or pull request relating to a bug in Gatsby and removed status: inkteam to review labels Sep 27, 2018
@AlmeroSteyn
Copy link
Contributor Author

@pieh Thank you for the quick reply.

Images without alt are terrible for screen readers. Typically a screen reader will announce the src attribute then. So you'd end up with two images where one reads out the filename.

Even if you give it empty alt, the screen reader will still read it out as graphic or similar. This is ok for images that has no semantic meaning in a website, like decorative images that does not add to the website content, but here it would have every image then preceded by an empty image. That would be odd.

The only surefire way to ensure the screen reader does not read out one of the images is to add either a style of display:none or to add aria-hidden="true". The first option is preferable as it just uses standard CSS to fix the issue.

Would it not be able to time the application of display:none with the transition. The transition is set at 500ms correct? So if one were to account for it with a setTimeout like I did in my workaround?

Not the cleanest of solutions I know, but right now these images will cause quite a nasty experience for screen reader users.

If this is a no go one could also say that during the 500ms of the transition you leave both images in place. Leaving a split second for a user to encounter both elements. <img> tags are not focusable so the user will do this in reader mode where he either reads the page element by element or has the screen reader read the page from top to bottom. I think the chances of the screen reader encountering and reading both images in the span of 500ms may very well be negligible. It will certainly already improve the other 99.99999999999999% of the lifetime of the image.

@AlmeroSteyn
Copy link
Contributor Author

Just double checked with a colleague.

Turns out that setting the alt to empty has the same effect for a screen readers than the two above options. So whichever is easiest.

Either set alt to empty on the placeholder after it has loaded or add display:none. With aria-hidden="true" as a last resort.

@mikelax
Copy link
Contributor

mikelax commented Sep 27, 2018

This was briefly discussed here in ticket 8256, I think setting the alt tag empty is the correct (and most likely easiest solution.

@AlmeroSteyn
Copy link
Contributor Author

That will be perfect. Setting the alt attribute to empty for the actual image while loading and then setting the alt attribute of the placeholder to empty when the image is loaded. Switching the actual alt value like this will ensure that anyone who encounters either a loading or loaded picture with a screen reader will get one instance only and get the correct alt value read back to them.

@mikelax mikelax self-assigned this Sep 29, 2018
@mikelax
Copy link
Contributor

mikelax commented Sep 29, 2018

I have looked over the lib, and I think I have any easy solution using the isVisible attribute in state to conditionally set the alt text for the placeholder images. PR incoming this weekend.

@mikelax
Copy link
Contributor

mikelax commented Oct 1, 2018

New version 2.0.13 published.
Closed in #8671

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug An issue or pull request relating to a bug in Gatsby
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants