Blog Page Accessibility Deep Dive

The Problems

The Solutions

Refactor

 const chooseComponent = (component) => {
if (component.component === “SingleBlog”) {
setSingle(true)
setSingleBlogID(component.id)
setSingleShow(“FullBlog”)
} else if (component === “FullBlog”) {
setSingle(true)
setSingleBlogID(0)
setSingleShow(component)
} else {
setSingle(true)
setSingleShow(component)
}
}
if (props.id !== 0) {
fetchSingleBlog(props.id)
} else {
fetchBlogs()
}
<button className=”preview_button” onClick={() => chooseComponent({component: “SingleBlog”, id: blog.id})}>{blog.title}</button>
if (!state.isLoading && state.blogs !== null) {
let blogList
if (state.blogs.length > 1) {
blogList = state.blogs.map((blog) => {
let blogBody = parse(blog.body_html)
return (
<li key={blog.id} className=”blog”>
<h1>{blog.title}</h1>
{blogBody}
</li>
)
})
} else {
let blogBody = parse(state.blogs.body_html)
blogList =
<li key={state.blogs.id} className=”blog”>
<h1>{state.blogs.title}</h1>
{blogBody}
</li>
}
return (
<section aria-label=”Full list of Abbey’s blog posts” className=”full-blog”>
<ul>
{blogList}
</ul>
</section>
)
} else if (!state.isLoading && state.error) {
return (
<Error />
)
} else {
return (
<Loading />
)
}

Markdown or HTML?

const axios = require(‘axios’)
const API_KEY = process.env.API_KEY
exports.handler = async function (event, context) {
let articles
try {
articles = await axios.get(‘https://dev.to/api/articles/me', {
headers: {
“Api-Key”: API_KEY,
“Content-Type”: ‘application/json’
}
})
} catch (err) {
console.log(err)
return {
statusCode:err.statusCode || 500,
body: err.message,
headers: {
“Access-Control-Allow-Origin”: “https://abbeyperini.dev”,
“Access-Control-Allow-Methods": “GET”
}
}
}
return {
statusCode: 200,
body: JSON.stringify({
data: articles.data
}),
headers: {
“Access-Control-Allow-Origin”: “https://abbeyperini.dev",
“Access-Control-Allow-Methods”: “GET”
}
}
}
let markdown = state.blogs.body_markdown
blogList =
<li key={state.blogs.id} className=”blog”>
<h1>{state.blogs.title}</h1>
<ReactMarkdown children={markdown} remarkPlugins={[remarkGfm]}></ReactMarkdown>
</li>

Sections, Articles, and Headings, Oh My

the title and heading of Abbey’s blog 8 things I learned in a legacy codebase on DEV
function replaceHeadings(markdown) {
let newHeadings
newHeadings = markdown.replace(/\s#{5}\s/g, “\n###### “)
newHeadings = newHeadings.replace(/\s#{4}\s/g, “\n##### “)
newHeadings = newHeadings.replace(/\s#{3}\s/g, “\n#### “)
newHeadings = newHeadings.replace(/\s#{2}\s/g, “\n### “)
return newHeadings
}
blogList = state.blogs.map((blog) => {
let markdown = blog.body_markdown
let replaced = replaceHeadings(markdown)
return (
<article key={blog.id} className=”blog”>
<h2>{blog.title}</h2>
<ReactMarkdown children={replaced} remarkPlugins={[remarkGfm]}></ReactMarkdown>
</article>
)
})

Links on Links on Links

<article key={blog.id} className=”blog”>
<h2>{blog.title}</h2>
<a href={blog.url} target=”_blank” rel=”noreferrer”><button className=”preview_button”>Share</button></a>
<ReactMarkdown children={replaced} remarkPlugins={[remarkGfm]}></ReactMarkdown>
</article>
let SVGID = “ShareExternalLink” + Math.random().toString(16).slice(2)

The CSS Mess

abbeyperini.dev with the blog styling looking like a disaster
abbeyperini.dev with the blog styling looking nice

No to Reflow

.blog pre, .blog p, .blog blockquote, .blog h2, .blog h3, .blog h4, .blog ul, .blog ol {
max-width: 250px;
}
.blog {
min-width: 280px;
}
a {
word-wrap: break-word;
overflow-wrap: break-word;
}

Text Formatting

![a lacy Dowland shawl knit in sparkly burgundy yarn](https://dev-to-uploads.s3.amazonaws.com/i/yrjo5xbfu5gbsh5yzc0m.jpg “Knit by Abbey Perini, pattern by Dowland by Dee O’Keefe, yarn is Meeker Street by The Jewelry Box”)
*Knit by Abbey Perini, pattern by Dowland by Dee O’Keefe, yarn is Meeker Street by The Jewelry Box*
function replaceHeadings(markdown) {
let newHeadings
newHeadings = markdown.replace(/\s#{5}\s/g, “\n###### “)
newHeadings = newHeadings.replace(/\s#{4}\s/g, “\n##### “)
newHeadings = newHeadings.replace(/\s#{3}\s/g, “\n#### “)
newHeadings = newHeadings.replace(/\s#{2}\s/g, “\n### “)
newHeadings = newHeadings.replace(/<kbd>/g, “”)
newHeadings = newHeadings.replace(/<\/kbd>/g, “”)
return newHeadings
}

The Long Alt-Text

Caption: “Me: explains polymorphism Friend: So the subclass the same as the superclass? Me:” A claymation pirate saying “Well yes, but actually no”

Skipping Around

/* skip links */.screenreader-text {
position: absolute;
left: -999px;
width: 1px;
height: 1px;
top: auto;
}
.screenreader-text:focus {
color: black;
display: inline-block;
height: auto;
width: auto;
position: static;
margin: auto;
}
function makeID(title) {
title = title.toLowerCase()
let replaced = title.replace(/\s+/g, “-”)
replaced = replaced.replace(/#/g, “”)
return replaced
}
if (!state.isLoading && state.blogs !== null) {
let blogList
let skipLinks = []
if (state.blogs.length > 1) {
blogList = state.blogs.map((blog) => {
let SVGID = “ShareExternalLink” + Math.random().toString(16).slice(2)
let markdown = blog.body_markdown
let replaced = replaceHeadings(markdown)
let blogID = makeID(blog.title)
let Href = `#${blogID}`
let skipLinkID = blogID + Math.random().toString(16).slice(2)
let skipLink = <li id={skipLinkID}><a href={Href}>{blog.title}</a></li>
skipLinks.push(skipLink)
return (
<article className=”blog”>
<h2 id={blogID}>{blog.title}</h2>
<a href={blog.url} target=”_blank” rel=”noreferrer”><button className=”preview_button”>Share <ExternalLink className=”external-link” id={SVGID} focusable=”false”/></button></a>
<ReactMarkdown children={replaced} remarkPlugins={[remarkGfm]}></ReactMarkdown>
</article>
)
})
return (
<section aria-label=”Full list of Abbey’s blog posts” className=”full-blog”>
<div className=”screenreader-text”>
Skip directly to a blog:
<ol>
{skipLinks}
</ol>
</div>
{blogList}
</section>
)
} else {
let markdown = state.blogs.body_markdown
let replaced = replaceHeadings(markdown)
return (
<section aria-label=”Full list of Abbey’s blog posts” className=”full-blog”>
<article key={state.blogs.id} className=”blog”>
<h2>{state.blogs.title}</h2>
<a href={state.blogs.url} target=”_blank” rel=”noreferrer”><button className=”preview_button”>Share <ExternalLink className=”external-link” id=”ShareExternalLink” focusable=”false”/></button></a>
<ReactMarkdown children={replaced} remarkPlugins={[remarkGfm]}></ReactMarkdown>
</article>
</section>
)
} else if (!state.isLoading && state.error) {
return (
<Error />
)
} else {
return (
<Loading />
)
}
return (
<section aria-label=”Blog Previews” className=”container_blog”>
<h2 aria-label=”button to open full blog page” ><button className=”blog-section_title” onClick={() => chooseComponent(“FullBlog”)}>Blog</button></h2>
<a className=”screenreader-text” href=’#about’>Skip directly to the next section.</a>
<div className=”scroll-cropper”>
<ul aria-label=”previews of Abbey’s blog posts” className=”blog-preview”>
{blogPreviewList}
</ul>
</div>
</section>
)
when focused, “Skip directly to a blog:” appears and focusing on the skip links cycles through links to all the blogs on the page

Conclusion

--

--

--

…did someone say animated CSS button?

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Tips to Build Successful Car Rental Reservation System

My Experience as LFX Mentee

Constructing Distributed Applications

Key lessons learnt in containerizing Windows-based applications

Diffable Data Source In IOS Swift

Use cases of HMS Kits in Huawei Books Application

How to describe table in PostgreSQL

How I became an Android Developer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Abbey Perini

Abbey Perini

…did someone say animated CSS button?

More from Medium

Using ResizeObserver and transitions for animating container with dynamic content

Get Started with Bloomreach Headless Experience Manager — Part 2

How to use JS on your Webflow website (the right way)

Accessibility Auditing My Portfolio Site — Part 6

Frodo on Mount Doom “It’s done. It’s over now.”