Warnings

[autoplay] should probably not be used

Description

A time-based media like <audio> or <video> should not [autoplay], because it can be quite surprising for the user.

References

Selector

video[autoplay],
audio[autoplay]

Test

<video autoplay controls src=""></video><span></span>

[controls] would be helpful

Description

A time-based media like <audio> or <video> would be easier to use if [controls] are activated for the user.

References

Selector

video:not([controls]),
audio:not([controls])

Test

<video src=""></video><span></span>

Semantic attribute on decorative svg

Description

Any decorative <svg> — with a [role="presentation"] or [aria-hidden="true"] — should not have any of those:

This test currently can't check if any <title> nor <desc> child is present since <svg> is a replaced elements. See Edge cases and known issues on a11y.css' wiki.

References

Selector

svg[aria-hidden="true"][title],
svg[aria-hidden="true"][aria-label],
svg[aria-hidden="true"][aria-labelledby],
svg[aria-hidden="true"][aria-describedby],
svg[role="presentation"][title],
svg[role="presentation"][aria-label],
svg[role="presentation"][aria-labelledby],
svg[role="presentation"][aria-describedby]

Test

<svg width="12cm" height="4cm" viewBox="0 0 1200 400"
     xmlns="http://www.w3.org/2000/svg" version="1.1"
     role="presentation" title="Decorative SVG, you punk!">
  <rect x="400" y="100" width="400" height="200"
        fill="forestgreen" stroke="darkgreen" stroke-width="10"  />
</svg><span></span>

[alt] can be empty but has to be checked

Description

An alternative has to be empty when image is decorative only. In any other case, [alt] must be defined. That should be double-checked.

References

Selector

img[alt=""],
area[alt=""],
input[type="image"][alt=""],
embed[type="image"][alt=""],
object[type="image"][alt=""]

Test

<img alt="" src="static/ffoodd.png" width="144" height="144" /><span></span>

Most of DOM nodes shouldn't be :empty

Description

Obviously void elements are empty, as well as <iframe> and <textarea> could be :empty. Any other :empty tag that is not hidden is probably useless, and should be deleted.

Please note that it's disabled for tags owning a source through [src]. It's pretty opinionated, but it's meant to avoid false positives on tags such as <video> or <audio> which may be empty if they have at least one source specified through [src].

Notes

References

Selector

body *:empty:not([hidden]):not([aria-hidden]):not([src]):not(button):not(a):not(iframe):not(textarea):not(area):not(base):not(br):not(col):not(command):not(embed):not(hr):not(img):not(input):not(keygen):not(link):not(meta):not(param):not(source):not(track):not(wbr):not(title)
body *:blank:not([hidden]):not([aria-hidden]):not([src]):not(button):not(a):not(iframe):not(textarea):not(area):not(base):not(br):not(col):not(command):not(embed):not(hr):not(img):not(input):not(keygen):not(link):not(meta):not(param):not(source):not(track):not(wbr):not(title)
body *:-moz-only-whitespace:not([hidden]):not([aria-hidden]):not([src]):not(button):not(a):not(iframe):not(textarea):not(area):not(base):not(br):not(col):not(command):not(embed):not(hr):not(img):not(input):not(keygen):not(link):not(meta):not(param):not(source):not(track):not(wbr):not(title)

Test

<p id="empty-node_code"></p>

abbr should have a [title]

Description

Any abbreviation should give an explanation about its meaning, at least on its first occurrence.

References

Selector

abbr:not([title]),
abbr[title=" "],
abbr[title=""]

Test

Do you know about W3C?

<p>Do you know about <abbr>W3C</abbr>?</p>

legend must be a fieldset's:first-child

Description

<legend> must be a <fieldset>'s:first-child. Always.

References

Selector

fieldset > *:not(legend):first-child,
fieldset > legend:not(:first-child)

Test

<fieldset>
  <label>I'm not a legend.</label>
</fieldset>

figure without the group ARIA role

Description

<figure> needs [role="group"] for accessibility reason.

References

Selector

figure:not([role="group"])

Test

Figcaption test
I'm a figcaption
<figure>
  <img src="static/ffoodd.png" width="144" height="144" alt="Figcaption test"/>
  <figcaption>I'm a figcaption</figcaption>
</figure>

[alt] containing file name

Description

A file name in [alt] is probably wrongly automated… and would never ever help any user.

References

Selector

img[alt$=".pdf"],
area[alt$=".pdf"],
input[type="image"][alt$=".pdf"],
img[alt$=".doc"],
area[alt$=".doc"],
input[type="image"][alt$=".doc"],
img[alt$=".png"],
area[alt$=".png"],
input[type="image"][alt$=".png"],
img[alt$=".jpg"],
area[alt$=".jpg"],
input[type="image"][alt$=".jpg"],
img[alt$=".gif"],
area[alt$=".gif"],
input[type="image"][alt$=".gif"],
img[alt$=".mp3"],
area[alt$=".mp3"],
input[type="image"][alt$=".mp3"],
img[alt$=".mp4"],
area[alt$=".mp4"],
input[type="image"][alt$=".mp4"],
img[alt$=".mov"],
area[alt$=".mov"],
input[type="image"][alt$=".mov"],
img[alt$=".ogg"],
area[alt$=".ogg"],
input[type="image"][alt$=".ogg"],
img[alt$=".xls"],
area[alt$=".xls"],
input[type="image"][alt$=".xls"],
img[alt$=".txt"],
area[alt$=".txt"],
input[type="image"][alt$=".txt"],
img[alt$=".zip"],
area[alt$=".zip"],
input[type="image"][alt$=".zip"],
img[alt$=".rar"],
area[alt$=".rar"],
input[type="image"][alt$=".rar"],
img[alt$=".docx"],
area[alt$=".docx"],
input[type="image"][alt$=".docx"],
img[alt$=".webp"],
area[alt$=".webp"],
input[type="image"][alt$=".webp"],
img[alt$=".apng"],
area[alt$=".apng"],
input[type="image"][alt$=".apng"],
img[alt$=".svg"],
area[alt$=".svg"],
input[type="image"][alt$=".svg"],
img[alt$=".svgz"],
area[alt$=".svgz"],
input[type="image"][alt$=".svgz"],
embed[type="image"][alt$=".pdf"],
object[type="image"][alt$=".pdf"],
embed[type="image"][alt$=".doc"],
object[type="image"][alt$=".doc"],
embed[type="image"][alt$=".png"],
object[type="image"][alt$=".png"],
embed[type="image"][alt$=".jpg"],
object[type="image"][alt$=".jpg"],
embed[type="image"][alt$=".gif"],
object[type="image"][alt$=".gif"],
embed[type="image"][alt$=".mp3"],
object[type="image"][alt$=".mp3"],
embed[type="image"][alt$=".mp4"],
object[type="image"][alt$=".mp4"],
embed[type="image"][alt$=".mov"],
object[type="image"][alt$=".mov"],
embed[type="image"][alt$=".ogg"],
object[type="image"][alt$=".ogg"],
embed[type="image"][alt$=".xls"],
object[type="image"][alt$=".xls"],
embed[type="image"][alt$=".txt"],
object[type="image"][alt$=".txt"],
embed[type="image"][alt$=".zip"],
object[type="image"][alt$=".zip"],
embed[type="image"][alt$=".rar"],
object[type="image"][alt$=".rar"],
embed[type="image"][alt$=".docx"],
object[type="image"][alt$=".docx"],
embed[type="image"][alt$=".webp"],
object[type="image"][alt$=".webp"],
embed[type="image"][alt$=".apng"],
object[type="image"][alt$=".apng"],
embed[type="image"][alt$=".svg"],
object[type="image"][alt$=".svg"],
embed[type="image"][alt$=".svgz"],
object[type="image"][alt$=".svgz"]

Test

static/ffoodd.png
<img alt="static/ffoodd.png" src="static/ffoodd.png" width="144" height="144" /><span></span>

JS [href]

Description

The [href] attribute should not start with "javascript". Should probably be a <button> or at least a [role="button"], don't you think? The only exception shall be bookmarklets.

References

Selector

a[href^="javascript"]:not([role="button"])

Test

<a href="javascript:(function(){a11ycss=document.createElement('LINK');a11ycss.href='https://rawgit.com/ffoodd/a11y.css/master/css/a11y-en.css';a11ycss.rel='stylesheet';a11ycss.media='all';document.body.appendChild(a11ycss);})();">Please use my bookmarklet ;)</a>

Invalid sibling in a definition list

Description

<dt> and <dd> should be direct adjacent siblings, and nothing else. Although multiple <dd> may follow a single <dt>.

References

Selector

dt + :not(dd),
:not(dt):not(dd) + dd

Test

I need a definition, don't you think?
  • I'm a list item.
  • <dl>
      <dt>I need a definition, don't you think?</dt>
      <li>I'm a list item.</li>
    </dl>

    Invalid nesting in a definition list

    Description

    <dt> and <dd> should be direct children of <dl>. Any other imbrication may be a crime somewhere.

    References

    Selector

    :not(dl) > dt,
    :not(dl) > dd,
    dl > :not(dt):not(dd)

    Test

  • I'm a list item.
  • <dl>
      <li>I'm a list item.</li>
    </dl>

    figcaption outside a figure

    Description

    <figcaption> doesn't make sense outside a <figure>.

    References

    Selector

    :not(figure) > figcaption

    Test

    I'm captionning something, isn't it?
    <figcaption>I'm captionning something, isn't it?</figcaption>

    Invalid nesting in a list

    Description

    The only child allowed in <ul> and <ol> is <li> - and the converse is also true.

    References

    Selector

    ul > :not(li),
    ol > :not(li),
    :not(ul):not(ol) > li

    Test

      I feel like I'm lost.

    <ul>
      <p>I feel like I'm lost.</p>
    </ul>

    Invalid nesting

    Description

    Some nestings are forbidden, and do not have their own test case for now:

    Maybe other invalid nestings to test. Stay tuned.

    References

    Selector

    :not(tr) > td,
    :not(tr) > th,
    colgroup *:not(col),
    :not(colgroup) > col,
    tr > :not(td):not(th),
    optgroup > :not(option),
    :not(select) > optgroup,
    :not(fieldset) > legend,
    select > :not(option):not(optgroup),
    :not(select):not(optgroup) > option,
    table > *:not(thead):not(tfoot):not(tbody):not(tr):not(colgroup):not(caption)

    Test

    I'm an legend. Am I?
    <legend>I'm an legend. Am I?</legend>

    Misplaced div

    Description

    Did you know that you shouldn't add a <div> inside any inline element? You could use a <span> instead.

    References

    Selector

    b div,
    i div,
    q div,
    em div,
    abbr div,
    cite div,
    code div,
    span div,
    small div,
    label div,
    strong div

    Test

    Hey ya!
    <b><div>Hey ya!</div></b>

    Missing head for data table

    Description

    <thead> is strongly needed if <tbody> is present.

    Selector

    table:not([role="presentation"]) > caption + tbody,
    table:not([role="presentation"]) > tbody:first-child

    Test

    Missing thead
    I'm a table without thead. I'm a table without thead.
    I'm a table without thead. I'm a table without thead.
    <table>
      <caption>Missing thead</caption>
      <tbody>
        <tr>
          <td>I'm a table without thead.</td>
          <td>I'm a table without thead.</td>
        </tr>
        <tr>
          <td>I'm a table without thead.</td>
          <td>I'm a table without thead.</td>
        </tr>
      </tbody>
    </table>

    Nested tables

    Description

    There's no good reason to nest data tables: thus it probably means we're facing a layout table…

    References

    Selector

    table table

    Test

    I'm a caption :3
    Oh boy…
    I'm a table-cell!
    I'm a caption too!
    Oh boy…
    I'm a table-cell!
    I'm a table-cell!
    <table>
      <caption>I'm a caption :3</caption>
      <thead>
        <tr>
          <th scope="col">Oh boy…</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>I'm a table-cell!</td>
        </tr>
        <tr>
          <td>
            <table>
              <caption>I'm a caption too!</caption>
              <thead>
                <tr>
                  <th scope="col">Oh boy…</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>I'm a table-cell!</td>
                </tr>
                <tr>
                  <td>I'm a table-cell!</td>
                </tr>
            </table>
          </td>
        </tr>
      </tbody>
    </table>

    Missing [aria-level]

    Description

    Though [aria-level] is not required by ARIA specification, it's actually better to specify it.

    References

    Selector

    [role="heading"]:not([aria-level])

    Test

    Heading with undefined level
    <strong role="heading">Heading with undefined level</strong>

    A role is needed for svg

    Description

    Any <svg> should either have a [role="presentation"] or [aria-hidden="true"] if decorative, or a [role="img"] if informative.

    References

    Selector

    svg:not([aria-hidden="true"]):not([role="presentation"]):not([role="img"])

    Test

    <svg width="12cm" height="4cm" viewBox="0 0 1200 400"
         xmlns="http://www.w3.org/2000/svg" version="1.1"
         aria-label="Decorative SVG, you punk!">
      <rect x="400" y="100" width="400" height="200"
            fill="forestgreen" stroke="darkgreen" stroke-width="10"  />
    </svg><span></span>

    [alt] should be empty for decorative image

    Description

    An alternative must be empty when image is decorative only — which is declared with [role=presentation].

    References

    Selector

    img[role="presentation"]:not([alt=""]),
    area[role="presentation"]:not([alt=""]),
    input[role="presentation"]:not([alt=""]),
    embed[type="image"][role="presentation"]:not([alt=""]),
    object[type="image"][role="presentation"]:not([alt=""])

    Test

    I'm a deocrative image!
    <img role="presentation" alt="I'm a deocrative image!" src="static/ffoodd.png" width="144" height="144" /><span></span>

    Bad computed value

    Description

    Don't laugh, shit happens.

    Selector

    [id*="NaN"],
    [id*="null"],
    [class*="NaN"],
    [class*="null"],
    [id*="undefined"],
    [class*="undefined"]

    Test

    Oups, something went wrong.

    <p class="undefined">Oups, something went wrong.</p>

    Misused sectioning tags

    Description

    <section>, <aside>, <article> are sectioning tags. They must not be used as wrappers!

    References

    Selector

    aside > aside:first-child,
    article > aside:first-child,
    aside > article:first-child,
    aside > section:first-child,
    section > section:first-child,
    article > section:first-child,
    article > article:first-child

    Test

    <aside>
      <section>I'm wrapping, you know.</section>
    </aside>

    spacer.gif used

    Description

    Believe me, this still have to be tested.

    References

    Selector

    img[src*="1px.gif"]:not([role="presentation"]),
    img[src*="1x1.gif"]:not([role="presentation"]),
    img[src*="clear.gif"]:not([role="presentation"]),
    img[src*="spacer.gif"]:not([role="presentation"]),
    img[src*="dotclear.gif"]:not([role="presentation"]),
    img[src*="transparent.gif"]:not([role="presentation"]),
    img[src*="pixel-1x1-clear.gif"]:not([role="presentation"])

    Test

    Spacer.gif
    <img src="static/spacer.gif" alt="Spacer.gif" width="100" height="100"/><span></span>

    [style] attribute

    Description

    Your styles should be driven by a CSS file. That's it. And no, JS shouldn't manipulate styles: it's better to play with classes, for example.

    References

    Selector

    [style]

    Test

    I'm red. I really feel dirty.
    <div style="color: red;">I'm red. I really feel dirty.</div>

    Every data table must have a caption

    Description

    <caption> is needed for data <table>. And it must be the :first-child, by the way.

    References

    Selector

    table:not([role="presentation"]) > caption:not(:first-child),
    table:not([role="presentation"]) > *:first-child:not(caption)

    Test

    I'm a table without a caption! I'm a table without a caption!
    I'm a table without a caption!
    I'm a table without a caption!
    <table>
      <thead>
        <tr>
          <th id="th-one">I'm a table without a caption!</th>
          <th id="th-two">I'm a table without a caption!</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td colspan="2" headers="th-one th-two">I'm a table without a caption!</td>
        </tr>
        <tr>
          <td colspan="2" headers="th-one th-two">I'm a table without a caption!</td>
        </tr>
      </tbody>
    </table>

    A single line table may be used for layout

    Description

    A lonely <tr> can be a symptom of a table used for layout. Should be double checked!

    References

    Selector

    table:not([role="presentation"]) > tr:only-child,
    table:not([role="presentation"]) > tbody > tr:only-child

    Test

    I'm a caption :3
    Oh boy…
    I'm a poor lonesone table-roooow!
    <table>
      <caption>I'm a caption :3</caption>
      <thead>
        <tr>
          <th scope="col">Oh boy…</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>I'm a poor lonesone table-roooow!</td>
        </tr>
      </tbody>
    </table>

    Invalid table structure

    Description

    <thead>, <tfoot> and <tbody> must be in this order.

    References

    Selector

    table > tfoot ~ thead,
    table > tbody ~ tfoot,
    table > tbody ~ thead,
    table > tfoot ~ colgroup,
    table > tbody ~ colgroup,
    table > tbody ~ colgroup

    Test

    I'm a caption
    Where's my foot?
    I'm a table with tfoot done wrong. I'm a table with tfoot done wrong.
    I'm a table with tfoot done wrong. I'm a table with tfoot done wrong.
    I'm a table with tfoot done wrong. I'm a table with tfoot done wrong.
    <table>
      <caption>I'm a caption</caption>
      <thead>
        <tr>
          <th scope="col">Where's my foot?</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>I'm a table with tfoot done wrong.</td>
          <td>I'm a table with tfoot done wrong.</td>
        </tr>
        <tr>
          <td>I'm a table with tfoot done wrong.</td>
          <td>I'm a table with tfoot done wrong.</td>
        </tr>
      </tbody>
      <tfoot>
        <th id="th-1">I'm a table with tfoot done wrong.</th>
        <th id="th-2">I'm a table with tfoot done wrong.</th>
      </tfoot>
    </table>

    th without [scope] or [id]

    Description

    <th> strongly needs an [id] or a [scope].

    References

    Selector

    th:not([scope]):not([id])

    Test

    Need for a [scope] or [id]
    I'm a th without [scope] or [id]. I'm a th with [scope].
    I'm a td missing something. I'm a td missing something.
    I'm a td feeling well. I'm a td feeling well.
    <table>
      <caption>Need for a [scope] or [id]</caption>
      <thead>
        <tr>
          <th>I'm a th without [scope] or [id].</th>
          <th scope="col">I'm a th with [scope].</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>I'm a td missing something.</td>
          <td>I'm a td missing something.</td>
        </tr>
        <tr>
          <td>I'm a td feeling well.</td>
          <td>I'm a td feeling well.</td>
        </tr>
      </tbody>
    </table>

    Unsecured [target=_blank]

    Description

    [target="_blank"] links might be used for phishing. This is not actually an accessibility related issue, but everything helping users is welcome.

    References*

    Selector

    [target$="blank"]:not([rel]),
    [target$="blank"]:not([rel*="noopener"]),
    [target$="blank"]:not([rel*="noreferrer"])

    Test

    <a href="/" target="_blank">I feel vulnerable…</a>