블로그를 Gatsby 프레임워크의 gatsby-starter-blog 테마로 선택한 후로 이것저것 많이 꾸며 보고 있습니다. 일단 기존의 CSS 파일의 대부분을 날려 버리고 Tailwind CSS를 설치해서 블로그 레이아웃을 Tailwind CSS로 뜯어 고치고 있습니다. 다만 마크다운으로 작성된 글은 다른 모듈을 통해서 생성되는 모양이라 클래스 명을 따로 추가하려면 모듈을 뜯어 고쳐야 되는 것 같아서, 일단은 CSS 파일로 스타일링했습니다.
대충 꾸며 놓고 결과를 확인해봤습니다. 만족합니다. 그래서 커밋을 올리고 배포를 했습니다. 배포가 완료된 후 그냥 아무 생각 없이 제 휴대전화로 블로그를 들어가 봤습니다. 이전에 작성한 글들도 한번 다시 읽어봤습니다. 그런데, 이상한 점을 하나 발견했습니다.
또 다시 나를 괴롭히는 각주
이번에도 각주는 저를 괴롭히고 있었습니다. 하단 각주의 돌아가기 링크가 이모지로 변환되었던 것입니다. Chrome에서(사실, 저는 Arc를 씁니다)는 ↩
특수문자가 멀쩡히 출력되었으나, iOS Safari(이것도 사실 저는 Arc Search 앱을 씁니다)에서는 ↩
특수문자를 이모지로 변환하는 것 같았습니다. 내가 왜 이렇게 각주에 집착하는 사람이 되었는지에 대한 고민은 뒤로 하고, 이 문제를 고치기 위해 '특수문자가 이모지로 변환되는 것을 막는 방법'을 검색해봤으나 원하는 답을 찾지 못했습니다. 그래서 저는 그냥 SVG 포맷의 아이콘 이미지를 ↩
대신 출력하는 것이 더 낫겠다는 생각이 들었습니다.
각주 생성을 담당하는 코드를 수정해 보자
제가 구상했던 해결 방법은 다음과 같습니다.
↩
기호를 디렉토리 내에서 검색한다.- 검색 결과를 토대로
↩
기호를 SVG로 바꾼다.
써 놓고 보니 뭔가 코끼리를 냉장고에 넣는 법처럼 들리지만, 실제로 코끼리를 냉장고에 넣는 것보단 간단했습니다. 디렉토리 내에서 각주를 담당하는 mdast-util-to-hast
모듈의 lib/footer.js
파일이 글 하단의 각주를 생성한다는 사실을 찾았습니다.
// mdast-util-to-hast/lib/footer.js
(중략...)
function generateFootnotes(h) {
var footnoteById = h.footnoteById
var footnoteOrder = h.footnoteOrder
var length = footnoteOrder.length
var index = -1
var listItems = []
var def
var backReference
var content
var tail
while (++index < length) {
def = footnoteById[footnoteOrder[index].toUpperCase()]
if (!def) {
continue
}
content = def.children.concat()
tail = content[content.length - 1]
backReference = {
type: 'link',
url: '#fnref-' + def.identifier,
data: {hProperties: {className: ['footnote-backref']}},
children: [{type: 'text', value: "↩"}]
}
(이하 생략...)
}
그리고 역시나, ↩
기호를 위와 같이 출력한다는 사실도 알 수 있었습니다. value
값을 원하는 대로 고치면, 그 값이 ↩
기호 대신 표시되는 것도 확인했습니다.
이제, ↩
을 지우고 SVG를 넣을 차례입니다. SVG 아이콘은 Heroicons에서 적당히 괜찮은 걸로 준비하고, 아래와 같은 코드를 추가했습니다.
function generateFootnotes(h) {
var backChar =
`<span class="sr-only">본문으로 돌아가기</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
style="display: inline"
fill="none"
viewBox="0 0 24 24"
stroke-width="3"
stroke="currentColor"
class="size-3">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9 15 3 9m0 0 6-6M3 9h12a6 6 0 0 1 0 12h-3"
/>
</svg>`
backReference = {
type: 'link',
url: '#fnref-' + def.identifier,
data: {hProperties: {className: ['footnote-backref']}},
children: [{type: 'html', value: backChar}]
}
(이하 생략...)
주요 변경점은 다음과 같습니다.
backChar
변수를 선언하고, 변수 내부에 스크린 리더를 위한 대체 텍스트("본문으로 돌아가기")와 SVG 아이콘을 추가했습니다.backReference
부분에type
을html
로 변경하고,backChar
변수를value
로 지정했습니다.
하단 각주를 SVG 아이콘대로 표시하는 걸 성공했습니다. sr-only
클래스로 추가한 대체 텍스트 "본문으로 돌아가기"도 개발자 도구 상에서 잘 나오는 걸 볼 수 있었고요.
대체 텍스트 하니까 생각이 났던 건데, 본문에서 각주로 이동하는 링크에도 대체 텍스트를 넣고 싶어졌습니다. 예를 들어, 1번 각주로 이동하는 링크를 스크린 리더에서 "1번 각주로 이동"으로 읽어주는 거죠. 그래서 저는 각주의 a 태그에 지정된 footnote-ref
클래스를 마찬가지로 검색했고, mdast-util-to-hast/lib/handlers/footnote-reference.js
파일이 이를 담당하는 사실을 찾았습니다.
footnote-reference.js
파일은 다음과 같이 수정했습니다.
'use strict'
module.exports = footnoteReference
var u = require('unist-builder')
function footnoteReference(h, node) {
var footnoteOrder = h.footnoteOrder
var identifier = String(node.identifier)
if (footnoteOrder.indexOf(identifier) === -1) {
footnoteOrder.push(identifier)
}
return h(node.position, 'sup', {id: 'fnref-' + identifier}, [
h(node, 'a', {href: '#fn-' + identifier, className: ['footnote-ref']}, [
u('element', {
tagName: 'span',
children: [u('text', identifier)]
}),
u('element', {
tagName: 'span',
properties: {
className: ['sr-only'],
},
children: [u('text', '번 각주로 이동')]
})
])
])
}
각주로 이동하는 링크도 대체 텍스트가 잘 추가된 것을 확인할 수 있었습니다.
이제 배포할 차례가 남았… 어라?
patch-package
로 node_modules
패치하기
배포하려고 생각해 보니, 모듈을 직접 수정한 게 배포 단계에서 그대로 적용될 리가 없었습니다. 제 리포지토리에는 node_modules
디렉토리는 Git에 관리되고 있지 않기 때문이었죠. 그렇다고 628MB에 달하는 node_modules
를 리포지토리에 직접 추가하기에는 너무 큰 용량이었고, 좋은 방법도 아니라고 생각했습니다. mdast-util-to-hast
모듈만 Git에 추가하는 것도 잠깐 고민했었지만, .gitignore
로 무시되고 있는 node_modules
디렉토리의 하위 디렉토리를 강제로 추가하는 것도 좋은 방법은 아닌 것 같았습니다.
더 나은 방법을 찾았습니다. patch-package
라는 npm 패키지를 사용하면 모듈의 수정 사항을 패치 파일로 생성할 수 있고, 빌드 단계에서 패치 파일을 토대로 모듈을 패치할 수 있었습니다.
저는 다음과 같은 단계로 패치를 진행했습니다.
patch-package
패키지를 설치합니다.$ npm install patch-package
- 수정된
mdast-util-to-hast
모듈을 패치 파일로 만듭니다.$ npx patch-package mdast-util-to-hast
- 위 명령으로 생성된 패치 파일은 /patches/ 경로에 존재합니다. 이 파일을 Git에 추가해 줍니다.
$ git add ./patches/mdast-util-to-hast+10.2.0.patch
package.json
파일을 다음과 같이 수정하면, 빌드 단계에서 패치를 진행합니다.{ "scripts": { "build": "patch-package && gatsby build", } }
사실 빌드 과정에서 postinstall
패키지를 이용하여 package.json
파일에 "postinstall": "patch-package"
스크립트를 추가하는 방법을 시도했습니다만, 로컬에서는 정상적으로 작동하지만 Cloudflare Pages에 빌드할 때 계속 오류가 발생해서 이 방법은 포기했습니다. 대신, 그냥 간단하게 package.json
스크립트의 빌드 명령에 patch-package
를 추가하여 문제를 해결했습니다.
문제 해결!
위의 과정을 거쳐서 Cloudflare Pages에 성공적으로 빌드할 수 있었고, 배포된 환경에서도 각주에 대체 텍스트가 정상적으로 표시되는 것을 확인할 수 있었습니다.
돌이켜 보면, 지금까지 블로그를 꾸미는 시간보다 각주에 신경을 쓰는 시간이 더 많았던 것 같네요. 이렇게까지 시간을 쏟아부은 것에 비해 막상 제 블로그에 각주를 자주 쓸 일이 있을까 싶긴 합니다. 그렇지만 접근성 개선 과제를 하나 끝냈다고 생각하니 오히려 속이 후련한 느낌입니다.
앞으로 제 블로그를 꾸며 나가고 글을 작성하면서 웹 접근성 또한 최대한 신경을 많이 쓰려고 합니다. 정보는 누구에게나 공평해야 하니까요.