0

Thanks in advance for any help. This is what I am trying to do. I am creating a custom CSS to use when checking a web page for accessibility problems. One of those problems is an image with no alt-text (Description). Accessibility readers use the alt-text when describing images to the visually impaired.

I have successfully created a conditional where the image is filtered with a sepia tone to highlight it is missing the alt-text. But I also would like to either place text next to, or preferably on top of the image that states - "Alt Text is Missing"

This is what I have so far:

/* Locates images missing an Alt-Text */

img[alt=""] {filter: sepia(100%);}

img[alt=""]:after{
  content: "Image is missing an Alt text. ";
    color: black;
} 

The color works but the adding of the text after the image does not. Any ideas? Thanks!

Nathaniel Flick
  • 2,902
  • 2
  • 22
  • 31
  • An image element is an empty, void element, that can’t contain any html of content. Add a span, after the element, and toggle that instead. – David Thomas Jan 23 '20 at 19:56
  • Why not just fix the alt text of the image? And you have to position the pseudo text after you declare what the content attribute is. Per another poster pseudos aren't read by screenreaders so this is not an adequate solution. – Nathaniel Flick Jan 23 '20 at 20:47
  • Hi Nathaniel, the idea behind this is to create a sort of CSS overlay of a webpage to give the editor a quick glance at the accessibility factors on the page. It should all H tags in color codes, will point out usage of Bold, etc. So in the end, yes the alt tag will get edited but I am trying to have a way to let the user know when an image does not have one. – Billy Woody Jan 23 '20 at 21:01

4 Answers4

2

The pseudo-elements ::before and ::after only apply to elements that can contain content (flow and phrasing elements with an end tag (ex. <b></b>)) <img> is a void element (ie no end tag) therefore there's no way to use said pseudo-elements to an <img> tag. As @Kaiido commented having an end tag is not inclusive, replaced elements cannot have pseudo-elements as well (ex. <video></video>, <textarea></textarea>, <iframe></iframe>, etc.).

There are three things you must do to meet your objective via CSS:

  1. Add an appropriate element immediately after each image. Any element with an end tag will suffice.

  2. Add alt="" to each <img> if you haven't already.

  3. Add the following ruleset to your CSS:

    img[alt=""]+b::after { content: "Image is missing an Alt text.";...
    

    This is interpreted as:

    "All <b> tags that are immediately after a <img alt=""> will have the text, 'Image is missing an Alt text.' after any content it has."

Demo

img {
  display: inline-block;
  width: 20vw
}

img[alt=""] {
  filter: sepia(100%);
}

img[alt=""]+b::after {
  content: "Image is missing an Alt text.";
  display: inline-block;
  position: relative;
  z-index: 1;
  right: 20vw;
  width: 20vw;
  font-size: 0.75rem;
  color: #930;
}
<img src='https://i.ibb.co/hZj77BZ/lena01.jpg' alt=""><b></b>
<img src='https://i.ibb.co/7XxsBr5/lena02.png' alt=""><b></b>
<img src='https://i.ibb.co/X7SCb3w/lena03.png' alt=""><b></b>
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • This is so close. The problem is that the images when added by the content editors of the pages will not have a tag on them, If I manually add the tags this solution works perfectly, but in reality the images will not have the associated with them. I re-read what you said at the beginning, what you did here makes perfect sense. I'll have to keep trying to find a way to do this through just the css though. Thanks again!! – Billy Woody Jan 23 '20 at 20:55
  • 1
    No problem @BillyWoody. CSS has many possibilities but in your current situation, you have reached that point when CSS is no longer a viable solution. JavaScript is the best option AFAIK. – zer00ne Jan 24 '20 at 00:47
  • 1
    It's not only void elements that can't have ::before and ::after, replaced elements can't either, so no, *Any element with an end tag will* not *suffice*, take for instance , , etc. – Kaiido Feb 05 '20 at 05:37
1

EDIT - this solution only works in chrome / webkit browsers as comment points out it is a hack. See my other answer for a cross browser solution.

While this isn't possible with text, it is possible to replace the image with another, forcing your user to fill in the alt text (which you can explain elsewhere in the editor).

This will give the visual clue that an image doesn't have an alt attribute.

Couple this with a border and you have a winner.

In the below example I have set it up so that an image missing an alt attribute gets replaced and has a 5px 'border' (I use offset so it doesn't ruin the document flow).

I set an empty alt attribute to have a dashed border (and replace the image, but this may or may not be right for your circumstances if the image can be decorative).

Obviously this doesn't help screen reader users who use your software, but that would need some JavaScript anyway as the support for reading pseudo text is flaky at best.

Create an image that says 'missing alt text' and you are set.

obviously only use this CSS in your back-end

img{
  width:200px;
  height: 200px;
}

img:not([alt]) {
  outline: solid 5px red;
  outline-offset: -5px;
  content:url("https://www.publicdomainpictures.net/pictures/250000/nahled/erorr.jpg"); 
}
img[alt=""] {
  outline: dashed 5px red;
  outline-offset: -5px;
  content:url("https://freesvg.org/img/molumen_red_square_error_warning_icon.png"); 
}
<img src="https://via.placeholder.com/150" alt="">

<img src="https://via.placeholder.com/150">

<img src="https://via.placeholder.com/150" alt="Great alternative text">
Community
  • 1
  • 1
GrahamTheDev
  • 22,724
  • 2
  • 32
  • 64
  • Using `content` property that way is impossible for two reasons: 1. The selector must include either the `::before` or `::after` pseudo-element. 2. The previously mentioned pseudo-elements cannot be applied to void elements -- they can only apply to elements that have an end tag (ex. `` ****). – zer00ne Jan 24 '20 at 00:53
  • yeah just realised this only works in webkit browsers, didn't think to check in FireFox or IE. – GrahamTheDev Jan 24 '20 at 04:32
0
img[alt=""] {
  filter: sepia(100%);
  position: relative;
  z-index: 1
}

img[alt=""]:after{
  content: "Image is missing an Alt text. ";
  color: black;
  position: absolute; 
  top: 0px;
  left: 0px;
  z-index: 10
} 
parth jansari
  • 138
  • 1
  • 6
  • You didn’t test this, I’m assuming? – David Thomas Jan 23 '20 at 19:57
  • @parth, thank you for this code snippet, which might provide some limited, immediate help. A [proper explanation](https://meta.stackexchange.com/q/114762/349538) would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please [edit] your answer to add some explanation, including the assumptions you’ve made. – Ismael Padilla Jan 23 '20 at 20:25
0

Thought it would be neater to add this as a second answer after a comment pointing out my original solution was not compatible with IE and FireFox.

If you know the width and height of the image in question the following is cross browser and valid CSS.

Basically we hide the original image by making it 0 height and then add padding to the bottom equivalent to the height to allow the background-image to show.

The downside of this method is that using the 'cover' option for background-size means that different aspect ratios cause the image cutoff so you would need to come up with an image that would work for your 'alt tag missing' and 'alt tag empty' images both in portrait and landscape (or use tile and make the image small).

img{
  width:200px;
  height: 200px;
}


img:not([alt]) {
  width: 200px;
  height: 0;
  padding: 0 0 200px 0;
  outline: solid 5px red;
  outline-offset: -5px;
  background-image: url(https://freesvg.org/img/molumen_red_square_error_warning_icon.png);
  background-size: cover;
}


img[alt=""]{
  width: 200px;
  height: 0;
  padding: 0 0 200px 0;
  outline: dashed 5px red;
  outline-offset: -5px;
  background-image: url(https://www.publicdomainpictures.net/pictures/250000/nahled/erorr.jpg);
  background-size: cover;
}
<img src="https://via.placeholder.com/150" alt="">

<img src="https://via.placeholder.com/150">

<img src="https://via.placeholder.com/150" alt="Great alternative text">

The best solution would be to just prevent people adding an image with an empty alt attributre in the first place as part of your editor (and give them a tick box to say that the image is decorative to allow an empty alt attribute if you need to provide the option of decorative images).

GrahamTheDev
  • 22,724
  • 2
  • 32
  • 64