diff --git a/app/views/mfa_confirmation/show.html.erb b/app/views/mfa_confirmation/show.html.erb index d88f2569c95..806ece8ff5e 100644 --- a/app/views/mfa_confirmation/show.html.erb +++ b/app/views/mfa_confirmation/show.html.erb @@ -1,6 +1,6 @@ <% self.title = @content.heading %> -<%= image_tag asset_url('user-signup-ial1.svg'), width: 107, height: 119, alt: '', class: 'margin-bottom-4', role: 'img' %> +<%= image_tag asset_url('user-signup-ial1.svg'), width: 107, height: 119, alt: '', class: 'margin-bottom-4', aria: { hidden: true } %> <%= render PageHeadingComponent.new.with_content(@content.heading) %> diff --git a/app/views/openid_connect/logout/confirm_logout.html.erb b/app/views/openid_connect/logout/confirm_logout.html.erb index 0e474590447..4e9a2bd28b8 100644 --- a/app/views/openid_connect/logout/confirm_logout.html.erb +++ b/app/views/openid_connect/logout/confirm_logout.html.erb @@ -1,7 +1,7 @@ <% self.title = t('openid_connect.logout.heading', app_name: APP_NAME) %>
- <%= image_tag(asset_url('user-access.svg'), width: '280', height: '91', alt: '', role: 'img') %> + <%= image_tag(asset_url('user-access.svg'), width: '280', height: '91', alt: '', aria: { hidden: true }) %> <% if @service_provider_name.present? %> <%= render PageHeadingComponent.new.with_content(t('openid_connect.logout.heading_with_sp', app_name: APP_NAME, service_provider_name: @service_provider_name)) %> <% else %> diff --git a/app/views/partials/multi_factor_authentication/_mfa_selection.html.erb b/app/views/partials/multi_factor_authentication/_mfa_selection.html.erb index a9fcb0a3697..e8888d7e892 100644 --- a/app/views/partials/multi_factor_authentication/_mfa_selection.html.erb +++ b/app/views/partials/multi_factor_authentication/_mfa_selection.html.erb @@ -17,7 +17,7 @@ "two_factor_options_form_selection_#{option.type}", class: 'usa-checkbox__label usa-checkbox__label--illustrated', ) do %> - <%= image_tag(asset_url("mfa-options/#{option.type}.svg"), alt: '', class: 'usa-checkbox__image', role: 'img') %> + <%= image_tag(asset_url("mfa-options/#{option.type}.svg"), alt: '', class: 'usa-checkbox__image', aria: { hidden: true }) %>
<%= option.label %> <%= content_tag( diff --git a/app/views/shared/_banner.html.erb b/app/views/shared/_banner.html.erb index eb51448c7ef..90966378a74 100644 --- a/app/views/shared/_banner.html.erb +++ b/app/views/shared/_banner.html.erb @@ -28,7 +28,6 @@ asset_url('icon-dot-gov.svg'), size: 40, alt: '', - role: 'img', aria: { hidden: true }, class: 'usa-banner__icon usa-media-block__img', ) %> @@ -44,7 +43,6 @@ asset_url('icon-https.svg'), size: 40, alt: '', - role: 'img', aria: { hidden: true }, class: 'usa-banner__icon usa-media-block__img', ) %> diff --git a/app/views/shared/_footer_lite.html.erb b/app/views/shared/_footer_lite.html.erb index 0229d88350d..a2e8d100e9a 100644 --- a/app/views/shared/_footer_lite.html.erb +++ b/app/views/shared/_footer_lite.html.erb @@ -1,6 +1,6 @@
<%= new_tab_link_to('https://www.gsa.gov', class: 'footer__agency-logo') do %> - <%= image_tag(asset_url('sp-logos/square-gsa.svg'), size: 20, alt: '', class: 'margin-right-05', role: 'img') %> + <%= image_tag(asset_url('sp-logos/square-gsa.svg'), size: 20, alt: '', class: 'margin-right-05', aria: { hidden: true }) %> <%= t('shared.footer_lite.gsa') %> <% end %> <%= render LanguagePickerComponent.new(class: 'footer__language-picker') %> @@ -12,7 +12,7 @@
diff --git a/app/views/sign_up/registrations/_sp_registration_heading.html.erb b/app/views/sign_up/registrations/_sp_registration_heading.html.erb index 4de0f5ba94f..6b693ef2e1e 100644 --- a/app/views/sign_up/registrations/_sp_registration_heading.html.erb +++ b/app/views/sign_up/registrations/_sp_registration_heading.html.erb @@ -1,5 +1,5 @@
- <%= image_tag(asset_url('user-access.svg'), width: '280', height: '91', alt: '', role: 'img') %> + <%= image_tag(asset_url('user-access.svg'), width: '280', height: '91', alt: '', aria: { hidden: true }) %>

<%= decorated_sp_session.sp_name %> <%= t('headings.create_account_with_sp.sp_text', app_name: APP_NAME) %> diff --git a/app/views/users/backup_code_setup/reminder.html.erb b/app/views/users/backup_code_setup/reminder.html.erb index 3a12ba1af86..c36c6d72b1d 100644 --- a/app/views/users/backup_code_setup/reminder.html.erb +++ b/app/views/users/backup_code_setup/reminder.html.erb @@ -1,6 +1,6 @@ <% self.title = t('forms.backup_code.title') %> -<%= image_tag asset_url('user-signup-ial1.svg'), width: 107, height: 119, alt: '', class: 'margin-bottom-4', role: 'img' %> +<%= image_tag asset_url('user-signup-ial1.svg'), width: 107, height: 119, alt: '', class: 'margin-bottom-4', aria: { hidden: true } %> <%= render PageHeadingComponent.new.with_content(t('forms.backup_code_reminder.heading')) %> diff --git a/app/views/users/webauthn_setup/new.html.erb b/app/views/users/webauthn_setup/new.html.erb index 4b2e391980b..1323e2fe05d 100644 --- a/app/views/users/webauthn_setup/new.html.erb +++ b/app/views/users/webauthn_setup/new.html.erb @@ -1,7 +1,7 @@ <% self.title = @presenter.page_title %> <% if @platform_authenticator %> - <%= image_tag asset_url('platform-authenticator.svg'), alt: '', width: 84, height: 95, class: 'margin-left-1 margin-bottom-2', role: 'img' %> + <%= image_tag asset_url('platform-authenticator.svg'), alt: '', width: 84, height: 95, class: 'margin-left-1 margin-bottom-2', aria: { hidden: true } %> <% end %> <%= render PageHeadingComponent.new.with_content(@presenter.heading) %> diff --git a/spec/support/matchers/accessibility.rb b/spec/support/matchers/accessibility.rb index e398cebcb3a..f11ae053a58 100644 --- a/spec/support/matchers/accessibility.rb +++ b/spec/support/matchers/accessibility.rb @@ -187,22 +187,32 @@ def ids(page) end end -RSpec::Matchers.define :tag_decorative_svgs_with_role do +RSpec::Matchers.define :tag_decorative_svgs_with_aria_hidden do + # VoiceOver on Safari will erroneously announce SVG elements with a null text alternative, + # even with `role="presentation"` (see LG-12465). Assigning `aria-hidden` is equivalent to + # `role="presentation"` for image elements, and prevents the images from being announced. This + # should be removed if and when the bug is fixed in a future version of Safari. + # + # "Consequently, using role="presentation" or role="none" on an HTML img is equivalent to using + # aria-hidden="true"." + # + # See: https://www.w3.org/TR/wai-aria-1.2/#presentation + def decorative_svgs(page) page.all(:css, 'img[alt=""][src$=".svg" i]') end match do |page| - expect(decorative_svgs(page)).to all satisfy { |img| img[:role] == 'img' } + expect(decorative_svgs(page)).to all satisfy { |img| !img[:'aria-hidden'].nil? } end failure_message do |page| - img_tags = decorative_svgs(page).reject { |img| img[:role] == 'img' }. + img_tags = decorative_svgs(page).select { |img| img[:'aria-hidden'].nil? }. map { |img| %(#{img[:alt]}) }. join("\n") <<~STR - Expect all decorative SVGs to have role="img", but found ones without: + Expect all decorative SVGs to have aria-hidden, but found ones without: #{img_tags} STR end @@ -327,15 +337,12 @@ def fieldset_legend_name(element) end def expect_page_to_have_no_accessibility_violations(page, validate_markup: true) - expect(page).to be_axe_clean.according_to(:wcag22aa, :"best-practice"). - # Axe flags redundant img role on img elements, but is necessary for a Safari bug - # See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#identifying_svg_as_an_image - excluding('img[alt=""][src$=".svg" i]') + expect(page).to be_axe_clean.according_to(:wcag22aa, :"best-practice") expect(page).to have_unique_ids expect(page).to have_valid_idrefs expect(page).to label_required_fields expect(page).to have_valid_markup if validate_markup - expect(page).to tag_decorative_svgs_with_role + expect(page).to tag_decorative_svgs_with_aria_hidden end def activate_skip_link