DEV Community

Cover image for Accessibility Auditing My Portfolio Site - Part 4
Abbey Perini
Abbey Perini

Posted on • Edited on

Accessibility Auditing My Portfolio Site - Part 4

Read Part 1 - The Audit, Part 2 - Quick Fixes, and Part 3 - Dark Mode Toggle.

This blog will focus on making the blog preview component code on the main page of my site more accessible.

The Problems

First, I want to update the blog preview component to always return a <section> and <h1>. Currently, the error or loading text is returned with just a Shiba Inu SVG. Also, I need revisit the CSS so this component is uniform with the rest of the site.

Next, the individual blog previews within the component aren't focusable when you're using a keyboard. Once I've made the previews focusable, keyboard and screen reader users need to be able to scroll horizontally... without getting trapped.

Finally, when I was manually testing, I noticed that it wasn't obvious to a screen reader that you can interact with each blog preview heading. Luckily, the answer to this may also be the answer to making the previews focusable.

Uniformity, but with Meaning

This is the easiest to do, and requires my lambdas to be off, so I'm starting here. I import Error and Loading components into my blog preview component, so I'll need to add the <section> and <h1> within them. To maintain functionality, I also had to pass down my chooseComponent function in props.

For example, my Error component now looks like this:

function Error(props) {

  const chooseComponent = (component) => {
    props.chooseComponent(component);
  }

  return (
    <section className="container_blog">
      <h1 aria-label="button to open full blog page" ><button className="blog-section_title" onClick={() => chooseComponent("FullBlog")}>Blog</button></h1>
      <div className="container_error">
        <ConfusedShiba className="error-graphic"/>
        <p>There was an error! Try again later.</p>
      </div>
    </section>
  )
}

export default Error
Enter fullscreen mode Exit fullscreen mode

Now for the CSS! Getting the font size of the "Blog" button/heading the same as the other sections only required changing the value of the font-size property in my .blog-section_title rule to 1.5em.

Next, I want the spacing between the headings and content containers to be more uniform. Plus I want the Error and Loading components to always be the same width as the rest of the sections. I revisited all of my media queries, adjusting margin and width properties.

Finally, I set up my local lambda server so I can verify that the spacing of the blog preview component still looks correct. The width is a little off, so I go through all my media queries again and find a couple spots where the heading spacing needed to be tweaked too.

Totally Tabbular

The first thing I want to try is putting my preview headings in a <button> instead of just in an <h2> with an onClick handler. I suspect this will also make it more obvious to a screen reader that they are interactive.

Adding the <button> does make it focusable, but I end up removing the <h2> entirely. Now, the screen reader I'm testing with clearly states the title of the blog, that you're on a button, the item number, and how many items there are in the list when you focus on a blog title. The structure of the individual blog previews now looks like this:

return (
  <li key={blog.id} className="preview">
    <button className="preview_button" onClick={() => chooseComponent({id: blog.id})}>{blog.title}</button>
    <img className="preview_image" alt={altText} src={blogImage}></img>
  </li>
)
Enter fullscreen mode Exit fullscreen mode

Honestly, I have no idea why I didn't just use a <button> in the first place. I mean, the CSS class is called preview_button, for heaven's sake. I would like to say I was focused on heading hierarchy, but I wrapped the "Blog" <button> in an <h1> in Part 2 of this blog series. However, my preview_button rule applies perfectly, including the focus/hover outline:

screenshot of abbeyperini.dev in light mode with one of the blog preview title buttons focused

Horizontal Scrolling

Now that the items are focusable, and you can tell when using a screen reader that you can interact with them, I need to manually test the horizontal scrolling.

The first thing I notice is that it is much easier to avoid having to scroll through the entire list of blog previews on a screen reader. The second is that I need to set alt-text="" on all of the cover images, so the screen reader will skip over them. Hearing both the heading text and cover image alt-text becomes very repetitive. Plus, one could say the cover images are decorative. This will also solve a warning I got about one of the cover images having alt-text longer than 150 characters.

Next I add aria-label="previews of Abbey's blog posts" to the <ul> that holds all of my blog preview <li>s:

return (
  <section aria-label="Blog Previews" className="container_blog">
    <h1 aria-label="button to open full blog page" ><button className="blog-section_title" onClick={() => chooseComponent("FullBlog")}>Blog</button></h1>
    <div className="scroll-cropper">
        <ul aria-label="previews of Abbey's blog posts" className="blog-preview">
          {blogPreviewList}
        </ul>
    </div>
  </section>
)
Enter fullscreen mode Exit fullscreen mode

Now instead of just "list," the screen reader I am using says "list preview of Abbey's blog posts." At this point, keyboard navigation is working fine, if a bit lengthy, and navigating this component with a screen reader makes much more sense.

It's Not a Trap!

Turns out, I had no idea what a keyboard trap was! As long as the user can escape the component using just the keyboard or screen reader and not a mouse, it's ok! Very glad this component passes the test. I'll be doing some more research on skip links for the next blog post. I may add one in here as this 19 item list is only growing with every blog post I write. Up until this point, I haven't been adding any because a user would only have to tab through the navigation bar to hit the main content. Plus, the navigation bar buttons load single sections, allowing a user to skip directly to what they want to read.

Conclusion

That's an audit, some quick fixes, and 2 problematic components down - one massive blog styling revamp to go! I am quite relieved this component was so easily fixed.

Read Part 5 - Blog Page Accessibility Deep Dive
In which I find a security vulnerability, write a surprising number of regexes, and this series becomes a thesis.

Read Part 6 - The Finale

Top comments (5)

Collapse
 
grahamthedev profile image
GrahamTheDev • Edited

Hey Abbey, me again, but hopefully now we get each other you will like these suggestions. 🤣

And I want to say once again, I am loving the "follow me on the journey" way of writing these articles rather than a "how to". Another ❤🦄 from me (and a bit of jealousy that I didn't think of writing an article in this style! 😋)!

One Observation

Before you do any more on optimising on components or the blogs page etc. it would be good to look at adjusting the routing of the site so that when I visit a page the URL updates.

The only reason I suggest doing this now is that you will need to do that anyway at some point (as at the moment I cannot use the browsers back button or access a page directly via a URL so I can't share an article etc.) and it will affect how you adjust components.

For example here you have used <button> elements, which are correct with your current routing as everything happens in one page, but if you change to a system that has URLs for the site pages you will need to change these to anchors with valid hrefs (and intercept with JS).

Just thought it would save you some time in the future as you won’t have to go back and fix components a second time.

The skip link for the blog post section is a great idea, very few people realise you can have them anywhere, not only at the top of the page so that was a great spot!

The detailed stuff

Here are things for the future as that final 1% / things that you may want to add in to the list (if you haven't already!).

They are not needed until you have done everything else you have planned (except point 3, that is a great quick win with a massive impact if you can squeeze that in sooner):

  1. Wrapping the list in a <nav> element and giving that nav (and your main nav) an aria-label to differentiate them would work well here to aid discoverability. (Very minor).
  2. Your aria-label on the <h1> doesn't need to start with "button to open" as screen readers will know it is a button. This is the same principle as "image of" on alt text not being needed. (minor)
  3. It may be on your list but multiple <h1>s per page is not recommended despite what a load of articles might say (can point you to some info on this if you need it). Only mentioning it now as yet again, you might need to consider this when designing components (high priority - headings are the primary way screen reader users navigate a document)

p.s. some of the explanations are for others reading this who may be starting their accessibility journey so they understand why I am suggesting things, I know you may not need that much detail!

Collapse
 
abbeyperini profile image
Abbey Perini • Edited

Hey!

I made the decision to never add routing when I designed this site because I'm in a fight with React Router. 😂 I will add a note to consider adding the dev.to links in the blog bodies though.

1 and 2 and 3 will be checked when I do that final multiple screenreader testing I've mentioned, but the aria-label is in the <h1> because the screenreader I'm currently using doesn't say anything about the <button> when I'm on the <h1>. 🤷‍♀️ I removed the <h2>s for the same reason.

Heading hierarchy resets within <section> elements, which is why there are a lot of articles saying that and I made sure a <section> was returned in all forms of this component. I could go further on the uniformity and try to make sure the aria-labels are uniform in the sections, though. It annoys me that the about section is read slightly differently because it has aria-labelledby. 🤔

Collapse
 
grahamthedev profile image
GrahamTheDev • Edited

I made the decision to never add routing when I designed this site because I'm in a fight with React Router. 😂 I will add a note to consider adding the dev.to links in the blog bodies though.

In that case what you have is the best case solve for now.

You could possibly have a look at the History API and hack something straight forward in just so the back button works?

It is a tough one!

the screenreader I'm currently using doesn't say anything about the when I'm on the

No idea on the button problem, announces for me? But fair enough, as I said it was minor and you have a good reason to have it in place!

What SR are you using, as that is a very useful thing to know at my side so I know to look out for it! 👍

Heading hierarchy resets within elements, which is why there are a lot of articles saying that and I made sure a was returned in all forms of this component.

This, sadly, is one of the biggest misconceptions that won't die and people still write about it.

Originally there was going to be something called the "Document Outline Algorithm" on a document so that each section reset the headings as you said.

None of the browser vendors implemented it though, so it is a case of the spec says one thing but the real world says another.

adrianroselli.com/2013/12/the-trut...

adrianroselli.com/2016/08/there-is...

I can link to more stuff on that if you need it, but Adrian is pretty thorough in their explanations.

Thread Thread
 
abbeyperini profile image
Abbey Perini

I'm aware of the history API. Would I design another site this way? No. Am I only doing what makes me happy with this site? Yes. 😂

I'm using VoiceOver, but I'll also use NVDA and hopefully another, depending on price, for my final testing.

You are correct! Found it on MDN too. The prevalence of that misconception is truly unfortunate. Luckily the next post already involves revamping headings, so that'll fit right in.

I feel like it may hang around because only having <h2>s when I don't have a main site heading beyond my landing page is not intuitive at all.

Thread Thread
 
grahamthedev profile image
GrahamTheDev

Go for visually hidden <h1> with site name and then <h2>s thereafter if you are revamping, but otherwise everything else makes sense and looks good.

I will be having a play with VoiceOver to check some bits after you mentioning it, as I was unaware buttons weren't announced in headings so thanks for that 👍