Blog Page Accessibility Deep Dive

The Problems

The Solutions

 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 />
)
}
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>
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>
)
})
<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)
abbeyperini.dev with the blog styling looking like a disaster
abbeyperini.dev with the blog styling looking nice
.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;
}
![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
}
Caption: “Me: explains polymorphism Friend: So the subclass the same as the superclass? Me:” A claymation pirate saying “Well yes, but actually no”
/* 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

--

--

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