라벨 및 태그를 영문 주소 + 한글 텍스트로 만들기 (JavaScript)
개요: 라벨/태그는 영문이 SEO에 좋아요
Q: 왜요?
A: 한글 url은 인코딩 때문에 깨지고 길어져요.
우리는 한국인이라 라벨에 한글을 사용하는게 편하죠. 블로그 방문자도 대부분 한국인이라 외국어 쓰면 뇌내 딜레이가 생겨요.
하지만 검색엔진을 비롯한 웹 생태계는 라틴 문자 중심이고, 특히 url은 ascii 문자만 쓸 수 있어서 문제가 생겨요.
한글을 쓰면 주소가 깨져요 = '%ED%95%9C%EA%B8%80%EC%9D%84%20%EC%93%B0%EB%A9%B4%20%EC%A3%BC%EC%86%8C%EA%B0%80%20%EA%B9%A8%EC%A0%B8%EC%9A%94' 이런 식으로 URL 퍼센트 인코딩이 되어버리죠.
요즘 브라우저는 주소창에 한글을 제대로 보여주긴 하는데요, 보여만 줄 뿐이지 서버쪽에 요청할 때는 이런 인코딩 된 '깨진 주소'를 보내고 있어요.
이러면 사람이 보기에도 안 좋고, 드물게 서버에서 해석하다 오류가 날 수도 있어서 url은 가능하면 영문이 좋아요.
의문: 라벨이나 태그에 영문쓰면 알아보기 힘든데?
맞아요. 그게 문제에요. 모든 문자를 가리지 않고 잘 표시해 주면 좋겠는데, 현실적 문제가 발목을 잡고 있어요. 기기 성능은 충분히 올라왔지만 하위 호환성이나 Homograph 공격 같은 피싱 문제가 있는 모양이더라고요.
결국 url에 ascii 문자만 쓸 수 있는 상황은 바뀌지 않을 것이고, 그럼 우리가 알아서 해결책을 찾아야 해요.
워드프레스는 이런 문제에 대한 해결책을 자체 지원하고 있어요. 태그나 카테고리 설정에서 slug와 text를 따로 지정할 수 있는데, 사람에게 보이는 text와 url로 쓰는 slug를 분리한 거죠.
하지만 블로그스팟은 해당 기능을 지원하지 않아요. 티스토리 역시 오랜만에 확인해 봤더니 아직 지원하지 않고 있네요. 네이버 블로그는 아예 사용자 지정 이름을 무시하고 쿼리문에 'categoryNo=0' 형태로 쓰고있고요.
이제 우리가, 블로거가 직접 기능을 구현할 차례가 왔어요. '없으면 만들어 쓴다' 이게 바로 html 수정 가능한 블로그의 단점이자 장점 아니겠어요?
Q: 구체적으로 어떻게 함?
A: 자바스크립트로 특정 라벨의 텍스트를 교체하는 거예요.
url 자체는 영문으로 하되, 거기 보여지는 앵커 텍스트만 한글로 바꾸는 거죠. 일종의 눈속임이에요.
css를 사용할 수도 있긴 해요. 라벨 본문을 숨기고 ::before, ::after 같은 의사 요소에 원하는 문자열을 지정하면 되거든요. 하지만 자바스크립트가 좀 더 자유롭고 확장성도 높아요.
해결: 라벨 텍스트만 한글로 바꾸는 코드
<script>
// 라벨명 한글로 변환.
// blogspot + essential 기준. 변경 가능.
// 개별 게시물 확인은 굳이 필요치 않음.
window.addEventListener('load', () => {
(function labelToKR() {
// 분리용 문자열
const labelStructure = '/label/';
// 한글 라벨 사전 정의.
const labelMapKR = {
'Blogidea' : '블로그 운영',
'UX' : '사용자 경험',
};
// requestIdleCallback 미지원 브라우저는 setTimeout 사용.
const runOnIdle = window.requestIdleCallback || function(cb) { setTimeout(cb, 0.5); };
// 작업 예약
runOnIdle(() => {
// A 태그 스냅샷
const labelLinks = document.querySelectorAll('a');
// 변환 작업
labelLinks.forEach(link => {
// console.log('진입'); // 테스트용. 필요 시 주석 해제하여 확인.
if ( !link.href.includes(labelStructure) ) return; // 라벨 링크 아니면 탈출
// 라벨 이름 분리, 추출.
const labelParts = link.href.split(labelStructure);
if (labelParts.length > 1) {
// 혹시 쿼리 있으면 제거. 맨 끝의 슬래시(/) 제거.
const labelName = decodeURIComponent(labelParts[1].split('?')[0]).replace(/\/$/, '');
if ( labelMapKR[labelName] ) {
// console.log('변환'); // 테스트용.
// 라벨 카운트 있으면 추출.
const labelCount = link.textContent.match(/\s*\(\d+\)\s*$/);
const countText = labelCount ? labelCount[0] : '';
// 한글 라벨명 + 카운트 결합.
link.textContent = labelMapKR[labelName] + countText;
// 변환된 라벨에 클래스 부여.
link.classList.add('labelKR');
}
// else { console.log('통과'); } // 테스트용.
}
}); // 루프 끝.
});
})(); // 래핑 함수 끝.
});
// maidvsai
<script>
<style>
/* 한글 세로 정렬 문제 */
/* 각 블로그 상황에 맞게 조정 */
a.labelKR { padding-block: 7px 5px; }
</style>
이 스크립트의 특징은 아래와 같아요.
- window load 이벤트 시점에서 실행
- requestIdleCallback을 이용
- requestIdleCallback 없는 브라우저는 setTimeout 사용
이렇게 최대한 브라우저의 메인 스레드를 방해하지 않도록 구성되어 있어요. 페이지 접속하자마자 보여줄 부분이 아니니까 느긋하게 실행하는 거죠.
클래스 삽입이 무거운 작업은 아니지만, 그래도 저사양 기기의 FCP 문제 때문에 최대한 로딩에 방해되지 않게 해 놨어요.

자바스크립트 코드는 블로그스팟, 에센셜 테마 기준으로 선택자가 구성되어 있어요. 다른 테마 혹은 블로그 서비스라면(티스토리) labelStructure, labelName 변수를 상황에 맞게 바꿔주세요.
트러블 슈팅은 중간중간 주석 처리해 둔 console.log를 활성화해서 확인하시고요.
깜빡임은 어떻게 해결함?
맞아요, 깜빡임. 그게 문제죠. 하지만 라벨이나 태그는 보통 화면 저 아래에 있잖아요? 일반적으로 페이지 상단에 보이는 요소가 아니라 괜찮아요.
만약 스킨이나 테마의 특성으로 라벨/태그 위치가 상단에 있다면, 혹은 사이드바가 항상 보이는 상태라면, requestIdleCallback을 없애 주세요.
즉, runOnIdle() 함수 없이 바로 실행하면 깜빡임이 줄어들 거고요, 네트워크 상태만 좋다면 방문자가 인지하기 어려운 짧은 시간 내에 바뀔 거예요.
한글로 바꾸는 시간이 오래걸리면 어떻게 함?
글쎄요... 별로 오래 안 걸릴걸요?
수십개 정도의 요소에 클래스 추가하는 건 그렇게 무거운 작업은 아니더라고요. 아주 저사양 기기라면 힘겨울 수 있겠지만, 그런 초 저사양 기기까지 다 대응하기엔 일이 너무 많아요. 주객전도, 딱 이 말이 어울리겠죠.
수백 ~ 수천개의 라벨/태그가 한 페이지에 있다? 그러면 평범한 블로그나 웹 문서가 아니라 전용 페이지라는 뜻이겠죠? 그런 전용 페이지는 다소 느려도 괜찮지 않을까요?
일반 게시물이 아니라 수 많은 라벨/태그가 빽빽하게 모여있는 특수 페이지라면, 연산 시간 0.몇 초 정도 늘어나는 건 문제없다고 생각해요.
루프 내에서 클래스 하나 넣고 다음 차례에 강제 확인하는 동작을 넣어서 리플로우를 유발하지만 않으면 문제없을 거예요.
참고 자료
- wiki: IDN homograph attack
- MDN: requestIdleCallback(), 유휴 상태에서 호출.