|
/* ==UserStyle== |
|
@name Govspeak accessibility issues |
|
@namespace github.com/alphagov |
|
@description Show possible accessibility issues coming from Govspeak on www.gov.uk |
|
@version 1.2.8 |
|
@license MIT |
|
@author Crown Copyright, Government Digital Service |
|
@preprocessor less |
|
@homepageURL https://gist.github.com/selfthinker/207d3d3682bd549599ceec20cb1cb087 |
|
@updateURL https://gist.githubusercontent.com/selfthinker/207d3d3682bd549599ceec20cb1cb087/raw/govspeak-a11y.user.css |
|
==/UserStyle== */ |
|
|
|
@-moz-document domain("www.gov.uk"), domain("publishing.service.gov.uk"), domain("dev.gov.uk"), domain("webarchive.nationalarchives.gov.uk") { |
|
|
|
/* == Mixins == */ |
|
|
|
.error() { |
|
color: #000; |
|
background-color: #fcc; |
|
outline: 2px solid #c00; |
|
/* &::before { content: "❌ " } */ |
|
} |
|
|
|
/* warning = we can't be sure if it's a problem, or it's a lesser issue */ |
|
.warning() { |
|
color: #000; |
|
background-color: #fc0; |
|
outline: 2px dotted #c00; |
|
/* &::before { content: "⚠️ " } */ |
|
} |
|
|
|
.help() { |
|
font-size: 1.1875rem; |
|
font-weight: normal; |
|
font-style: normal; |
|
color: #333; |
|
background-color: #fff; |
|
padding: 0 .2em; |
|
} |
|
.help-block() { |
|
.help(); |
|
display: block; |
|
} |
|
.help-inline() { |
|
.help(); |
|
} |
|
|
|
.empty() { |
|
display: inline-block; |
|
min-width: 1em; |
|
min-height: 1em; |
|
} |
|
|
|
.reset() { |
|
color: inherit; |
|
background-color: inherit; |
|
outline: inherit; |
|
&::after { |
|
display: none; |
|
} |
|
} |
|
|
|
|
|
/* == Inline text == */ |
|
|
|
div.govuk-govspeak strong { |
|
.warning(); |
|
|
|
&::after { |
|
.help-inline(); |
|
content: "⚠️ Use bold sparingly and not instead of a heading." |
|
} |
|
} |
|
|
|
div.govuk-govspeak tbody td:first-child strong { |
|
&::after { |
|
content: "⚠️ Do not use bold instead of a table header." |
|
} |
|
} |
|
|
|
div.govuk-govspeak th strong { |
|
&::after { |
|
content: "⚠️ There is no need to make table headers bold." |
|
} |
|
} |
|
|
|
div.govuk-govspeak em { |
|
.error(); |
|
|
|
&::after { |
|
.help-inline(); |
|
content: "❌ Do not use italics, they will not show up on pages." |
|
} |
|
} |
|
div.govuk-govspeak div.highlight-answer em, |
|
div.govuk-govspeak div.stat-headline em { |
|
.reset(); |
|
} |
|
|
|
div.govuk-govspeak small { |
|
.warning(); |
|
|
|
&::after { |
|
.help-inline(); |
|
content: "⚠️ Do not make the font smaller." |
|
} |
|
} |
|
|
|
div.govuk-govspeak sub, |
|
div.govuk-govspeak sup { |
|
.warning(); |
|
|
|
&::after { |
|
.help-inline(); |
|
content: "⚠️ Do not use 'sub' or 'sup' to make the font smaller." |
|
} |
|
} |
|
|
|
/* sup is automatically used for footnotes, therefore not showing the error for those */ |
|
div.govuk-govspeak a[href^="#"] sup, |
|
div.govuk-govspeak sup:has(a[href^="#"]) { |
|
.reset(); |
|
} |
|
|
|
|
|
/* == Headings == */ |
|
|
|
div.govuk-govspeak h1 { |
|
.error(); |
|
|
|
&::after { |
|
.help-block(); |
|
content: "❌ Do not use H1 within Govspeak. It won't show as a heading." |
|
} |
|
} |
|
|
|
/* only checks completely empty headings, not those with only spaces or s, |
|
as those will be in CSS4 and are not supported in most browsers; |
|
although Firefox supports its own version for most whitespace (except entities) */ |
|
div.govuk-govspeak h1:empty, |
|
div.govuk-govspeak h2:empty, |
|
div.govuk-govspeak h3:empty, |
|
div.govuk-govspeak h4:empty, |
|
div.govuk-govspeak h5:empty, |
|
div.govuk-govspeak h6:empty { |
|
.error(); |
|
.empty(); |
|
|
|
&::after { |
|
.help-block(); |
|
content: "❌ This heading is empty." |
|
} |
|
} |
|
/* doesn't work in non-Firefox when combined with the above */ |
|
div.govuk-govspeak h1:-moz-only-whitespace, |
|
div.govuk-govspeak h2:-moz-only-whitespace, |
|
div.govuk-govspeak h3:-moz-only-whitespace, |
|
div.govuk-govspeak h4:-moz-only-whitespace, |
|
div.govuk-govspeak h5:-moz-only-whitespace, |
|
div.govuk-govspeak h6:-moz-only-whitespace { |
|
.error(); |
|
.empty(); |
|
|
|
&::after { |
|
.help-block(); |
|
content: "❌ This heading is empty." |
|
} |
|
} |
|
|
|
div.govuk-govspeak h4, |
|
div.govuk-govspeak h5, |
|
div.govuk-govspeak h6 { |
|
.warning(); |
|
|
|
&::after { |
|
.help-block(); |
|
content: "⚠️ Avoid using lower level headings." |
|
} |
|
} |
|
|
|
div.govuk-govspeak h1 + h1, |
|
div.govuk-govspeak h2 + h2, |
|
div.govuk-govspeak h3 + h3, |
|
div.govuk-govspeak h4 + h4, |
|
div.govuk-govspeak h5 + h5, |
|
div.govuk-govspeak h6 + h6 { |
|
.error(); |
|
|
|
&::after { |
|
.help-block(); |
|
content: "❌ Do not use two headings of the same level after each other." |
|
} |
|
} |
|
|
|
|
|
/* == Links == */ |
|
|
|
div.govuk-govspeak a[href$=".pdf"], |
|
div.govuk-govspeak a[href$=".docx"], |
|
div.govuk-govspeak a[href$=".doc"], |
|
div.govuk-govspeak a[href$=".odt"], |
|
div.govuk-govspeak a[href$=".xls"], |
|
div.govuk-govspeak a[href$=".xlsx"], |
|
div.govuk-govspeak a[href$=".ods"], |
|
div.govuk-govspeak a[href$=".csv"], |
|
div.govuk-govspeak a[href$=".rtf"], |
|
div.govuk-govspeak a[href$=".ppt"], |
|
div.govuk-govspeak a[href$=".pptx"], |
|
div.govuk-govspeak a[href$=".odp"], |
|
div.govuk-govspeak a[href$=".zip"] { |
|
.warning(); |
|
|
|
&::after { |
|
.help-inline(); |
|
content: "⚠️ Do not link to files directly." |
|
} |
|
} |
|
|
|
/* attachments link to files directly, but are okay because they include file information */ |
|
div.gem-c-attachment__details .gem-c-attachment__title a, |
|
div.gem-c-attachment__thumbnail a, |
|
span.gem-c-attachment-link a, |
|
span.inline-attachment a, |
|
span.attachment-inline a, |
|
div.attachment-details .title a, |
|
div.attachment-thumb a, |
|
div.form-download a { |
|
.reset() !important; |
|
} |
|
|
|
div.govuk-govspeak a:empty { |
|
.error(); |
|
.empty(); |
|
|
|
&::after { |
|
.help-inline(); |
|
content: "❌ This link is empty." |
|
} |
|
} |
|
div.govuk-govspeak a:-moz-only-whitespace { |
|
.error(); |
|
.empty(); |
|
|
|
&::after { |
|
.help-inline(); |
|
content: "❌ This link is empty." |
|
} |
|
} |
|
|
|
|
|
/* == Images == */ |
|
|
|
/* images cannot have CSS-generated content, |
|
therefore the help text is attached to something else |
|
most images are within a `figure` element, so it often gets attached to that |
|
this won't work in the few cases that are not within such elements |
|
*/ |
|
/* removed `div.govuk-govspeak` because images are often in teasers or top of the page, not in Govspeak */ |
|
|
|
figure:has(img:is([alt*="png"], [alt*="jpeg"], [alt*="jpg"], [alt*="gif"], [alt*="webp"], [alt*="_"])) { |
|
.error(); |
|
|
|
&::before { |
|
.help-block(); |
|
content: "❌ Do not use a file name as the alt text."; |
|
} |
|
} |
|
|
|
/* historically, alt text couldn't be left empty, so people used to leave these instead */ |
|
figure:has(img:is([alt=" "], [alt='""'], [alt="''"])) { |
|
.error(); |
|
|
|
&::before { |
|
.help-block(); |
|
content: "❌ Do not use a space or quotation marks without any content as the alt text." |
|
} |
|
} |
|
|
|
/* this can only happen if HTML is used within Govspeak */ |
|
/* the help text is attached before the next element, if available |
|
if not available, there won't be any text */ |
|
div.govuk-govspeak img:not([alt]) { |
|
.error(); |
|
|
|
& + *::before { |
|
.help-block(); |
|
content: "❌ Image is missing the 'alt' parameter." |
|
} |
|
} |
|
|
|
/* empty alt in linked images, except for attachment thumbnails which have an aria-hidden */ |
|
a:not([aria-hidden="true"]):has(>img[alt=""]) { |
|
.error(); |
|
display: inline-block; |
|
|
|
&::before { |
|
.help-block(); |
|
content: "❌ Do not leave alt text empty in linked images." |
|
} |
|
} |
|
|
|
/* not using these for now... |
|
|
|
* never seen an animated gif on gov.uk, so might not be necessary |
|
figure:has(img[src$=".gif"]) { |
|
.warning(); |
|
|
|
&::before { |
|
.help-block(); |
|
content: "⚠️ Check if this is an animated gif." |
|
} |
|
} |
|
|
|
* we tell people to leave alt empty, so less of a point to highlight these |
|
figure:has(img[alt=""]) { |
|
.warning(); |
|
|
|
&::before { |
|
.help-block(); |
|
content: "⚠️ Check if this is an informative image or described in text." |
|
} |
|
} |
|
|
|
* not too important compared with other issues |
|
figure:has(img:is([alt^="Image of"], [alt^="Picture of"], [alt^="Photo of"])) { |
|
.warning(); |
|
|
|
&::before { |
|
.help-block(); |
|
content: "⚠️ Do not start alt text with 'Image of' etc." |
|
} |
|
} |
|
*/ |
|
|
|
|
|
/* == Tables == */ |
|
|
|
/* only 1 column */ |
|
div.govuk-govspeak tr > td:not([colspan]):only-child, |
|
div.govuk-govspeak tr > th:not([colspan]):only-child { |
|
.error(); |
|
&::after { |
|
.help-inline(); |
|
content: "❌ Do not use tables for layout purposes."; |
|
} |
|
} |
|
|
|
div.govuk-govspeak table > tbody > tr:only-child { |
|
.warning(); |
|
&::after { |
|
.help-inline(); |
|
content: "⚠️ There is only 1 row."; |
|
} |
|
} |
|
|
|
/* only checks completely empty cells, not those with only spaces or s, |
|
as those will be in CSS4 and are not supported in most browsers; |
|
although Firefox supports its own version for most whitespace (except entities) */ |
|
/* empty `th`s are not possible with Govspeak */ |
|
/* :empty doesn't work in non-Firefox when combined with :-moz-only-whitespace */ |
|
div.govuk-govspeak td:empty { |
|
.warning(); |
|
} |
|
div.govuk-govspeak td:-moz-only-whitespace { |
|
.warning(); |
|
} |
|
div.govuk-govspeak table:has(td:empty)::after { |
|
.help-block(); |
|
border: 2px dotted #c00; |
|
content: "⚠️ This table has empty cells." |
|
} |
|
div.govuk-govspeak table:has(td:-moz-only-whitespace)::after { |
|
.help-block(); |
|
border: 2px dotted #c00; |
|
content: "⚠️ This table has empty cells." |
|
} |
|
|
|
div.govuk-govspeak table thead th ~ td { |
|
.error() !important; |
|
&::after { |
|
.help-inline(); |
|
content: "❌ Do not leave cells in the header row empty."; |
|
} |
|
} |
|
|
|
/* probably missing row headers if top left cell is empty */ |
|
div.govuk-govspeak table thead:has(td:first-child:empty) + tbody tr td:first-child { |
|
.warning(); |
|
&::after { |
|
.help-inline(); |
|
content: "⚠️ Might need row headers."; |
|
} |
|
} |
|
div.govuk-govspeak table thead:has(td:first-child:-moz-only-whitespace) + tbody tr td:first-child { |
|
.warning(); |
|
&::after { |
|
.help-inline(); |
|
content: "⚠️ Might need row headers."; |
|
} |
|
} |
|
|
|
div.govuk-govspeak table:not(:has(th)) { |
|
.error(); |
|
&::before { |
|
.help-block(); |
|
content: "❌ This table has no table headers."; |
|
} |
|
} |
|
|
|
div.govuk-govspeak table thead tr + tr { |
|
.error(); |
|
&::before { |
|
.help-inline(); |
|
content: "❌ Do not use more than one header row."; |
|
} |
|
} |
|
|
|
div.govuk-govspeak table td:has(br), |
|
div.govuk-govspeak table th:has(br) { |
|
.warning(); |
|
&::before { |
|
.help-block(); |
|
content: "⚠️ Check <br> is not used for layout purposes."; |
|
} |
|
} |
|
|
|
/* not using these for now as tables can be quite busy with too many errors, |
|
and these are more usability rather than accessibility issues |
|
|
|
div.govuk-govspeak table tbody tr td:nth-child(n+6) { |
|
.warning(); |
|
&::after { |
|
.help-inline(); |
|
content: "⚠️ Avoid too many columns." |
|
} |
|
} |
|
|
|
div.govuk-govspeak table tbody tr:nth-of-type(n+11) { |
|
.warning(); |
|
&::after { |
|
.help-inline(); |
|
content: "⚠️ Avoid too many rows." |
|
} |
|
} |
|
|
|
div.govuk-govspeak table tbody tr:nth-of-type(n+25) { |
|
.error(); |
|
&::after { |
|
.help-inline(); |
|
content: "❌ This table is getting too long." |
|
} |
|
} |
|
*/ |
|
|
|
} |