오늘은 구글 블로그(블로그스팟) 사용자 경험을 향상시키는 두 가지 유용한 기능, '페이지 상단 이동 버튼'과 '플로팅 목차'를 추가하는 방법을 소개하려고 합니다. 특히 내용이 긴 포스트에서 독자들이 원하는 정보로 쉽게 이동하고, 언제든 맨 위로 돌아갈 수 있게 도와 가독성과 편의성을 크게 높일 수 있습니다.
이 기능을 구현하기 위해서는 블로그 테마의 HTML을 직접 수정해야 합니다. 수정 전에는 반드시 현재 테마를 백업해두시는 것을 강력히 권장합니다. (테마 > 맞춤설정 옆 점 세 개 > 백업)
Essential 테마 기준이며, 다른 테마에서 적용될지는 잘 모르겠습니다. 하지만 ChatGPT나 Grok을 통해 코드 수정하여 적용하실 수 있습니다.
⚠️ 먼저, 자바스크립트 코드가 작동하기 위해서는 jQuery 3.6.0이 필요합니다. 이를 설치하기 위해 코드 한 줄만 삽입하면 됩니다. 다음 글에서 꼭 먼저 확인하고 오세요.
1단계: 구글 아이콘 라이브러리 추가
상단 이동 버튼과 목차 아이콘 표시에 필요한 구글 아이콘 폰트를 로드해야 합니다. 블로그 대시보드에서 테마 > 맞춤설정 > HTML 편집으로 이동한 후, HTML 코드 편집기에서 </head> 태그를 검색하세요. 찾은 </head> 태그 바로 위에 다음 코드를 삽입합니다.
<!--구글 아이콘 시작-->
<link href='https://fonts.googleapis.com/css?family=Material+Icons+Outlined&display=swap' rel='stylesheet'/>
<link href='https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined' rel='stylesheet'/>
<!--구글 아이콘 끝-->
코드 설명:
- 이 코드는 구글에서 제공하는 Material Icons Outlined와 Material Symbols Outlined 웹 폰트 라이브러리를 블로그에 연결합니다. 이 라이브러리가 있어야 CSS에서 지정한 아이콘 코드(
\eacf,\e241등)가 실제 아이콘으로 표시됩니다. - 상단 이동 버튼의 아이콘과 플로팅 목차의 아이콘이 구글 아이콘의 링크를 통해 표시됩니다.
2단계: CSS 코드 추가
다음으로 상단 이동 버튼과 플로팅 목차의 디자인을 정의하는 CSS 코드를 추가합니다. HTML 편집기에서 ]]></b:skin> 코드를 찾아 그 바로 위에 아래의 CSS 코드 전체를 복사하여 붙여넣습니다.
상단 이동 버튼 CSS
/* 상단 이동 버튼 */
.move-top-btn {
float: left;
display: flex;
position: relative;
width: 32px;
height: 32px;
border-radius: 50%;
cursor: pointer;
justify-content: center;
align-items: center;
box-shadow: 0 0 2px rgba(115, 115, 115, 0.5);
}
.move-top-btn:before {
content: "";
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
opacity: 0.1;
border-radius: 50%;
}
.move-top-btn:after {
content: "\eacf"; /* 위쪽 화살표 아이콘 코드 */
font-size: 22px;
font-weight:500;
position: absolute;
visibility: visible;
border-radius: 50%;
line-height: 1;
}
/* 플로팅 버튼-상단 이동과 연계*/
.floating-button {
position: fixed; /* 화면에 고정 */
right: 10px; /* 오른쪽에서 10px */
bottom: 15px; /* 아래쪽에서 15px */
z-index: 201; /* 다른 요소 위에 표시될 우선순위 */
font-family: "Material Symbols Outlined"; /* 아이콘 폰트 지정 */
}
.floating-button a {
margin-left: 5px;
backdrop-filter: blur(1px); /* 배경 약간 흐리게 (지원 브라우저) */
color: #555 !important; /* 아이콘 색상 */
}
/*상단 이동 버튼 끝*/
플로팅 목차 CSS
/*플로팅 목차*/
.toc-wrap.floating {
font-size:14px;
position: fixed;
top: 60px;
right: 0;
max-width: 250px;
z-index: 99;
background-color: rgba(255,255,255,0.1);
box-shadow: 0 1px 10px rgba(0,0,0,0.1);
padding: 0;
margin: 0;
border: 0;
border-radius: 5px;
max-height: 500px;
overflow-y: auto;
}
.toc-wrap.floating .toc-title {
border:none;
line-height: 45px;
color: var(--color-alpha-70);
display: flex;
margin: 0 3px;
}
/* 모바일 화면용 */
@media (max-width: 768px) {
.toc-wrap.floating .toc-title {
margin: 0;
}
}
.toc-wrap.floating.active {
margin: 0 20px 0 0;
background-color: rgba(255, 255, 255, 1); /* 활성화 시 완전 불투명 */
}
.toc-wrap.floating.active ul{
padding: 0 0 0 10px;
}
.toc-wrap.floating.active .toc-title {
border-bottom:1px solid #ccd0d7;
margin: 0 7px;
}
.toc-wrap.floating .toc-title .toc-title-strong {
display: none;
}
.toc-wrap.floating.active .toc-title .toc-title-strong {
display: block;
}
.toc-wrap.floating .toc-title .floating-toc-icon::before {
content:"\e241";
font-family:"Material Icons Outlined";
vertical-align:bottom;
font-size: 20px;
cursor: pointer;
}
@media (max-width: 768px) {
.toc-wrap.floating .toc-title .floating-toc-icon::before {
font-size: 16px;
}
}
.toc-wrap.floating.active .toc-title .floating-toc-icon::before {
font-size: 20px;
margin-right: 4px;
}
.toc-wrap.floating.active{
border-radius:10px;
}
.toc-wrap.floating.active .toc,.toc-wrap.floating.active .toc-close-icon {
display: block;
}
.toc-wrap.floating .toc,.toc-wrap.floating .toc-close-icon {
display: none;
}
.toc-wrap.floating.active .toc-close-icon {
margin-left: auto;
padding-left: 20px;
font-size: 17px;
cursor: pointer;
color: #333;
}
.toc-wrap.floating .toc-title:before {
color: #999;
}
.toc-wrap {
background-color:#f9f9f9;
border:1px solid #dadce0;
border-radius:10px;
padding:3px 10px;
margin:0 3px 30px 1px;
font-size:14px;
box-sizing: border-box;
position: relative;
box-shadow: 1px 2px 3px 1px rgba(0,0,0,.1);
}
.toc-wrap .toc-title {
border-bottom:1px solid #ccd0d7;
padding:0;
position:relative;
line-height: 40px;
display: flex;
}
.toc-wrap .toc-title .toc-icon:before {
content:"\e242";
font-family:"Material Icons Outlined";
font-size:20px;
margin-right:3px;
vertical-align:bottom;
}
.toc-wrap .toc-item a {
color: #3A4954CC!important;
text-decoration: none!important;
}
.toc-wrap .toc-item a:hover{
font-weight:600;
}
.toc-wrap .toc-item.h2 {
font-size:14px;
}
.toc-wrap .toc-item.h3 {
padding-left:20px;
font-size:14px;
}
.toc-wrap .toc-item.h2:before {
content:"\e315";
font-family:"Material Icons Outlined";
margin-right:5px;
font-size:16px;
vertical-align:bottom;
}
.toc-wrap .toc-item.h3:before {
content:"-";
margin-right:7px;
font-size:16px;
vertical-align:bottom;
}
.toc-wrap ul {
margin:0px;
}
.toc-wrap .toc li {
list-style:none;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin: 9px 0;
line-height: 1.3;
}
@media only screen and (max-width:450px) {
.toc-wrap.floating{
top:55px
}
}
/* 플로팅 목차 끝 */
코드 설명:
- 상단 이동 버튼 CSS:
.move-top-btn클래스는 버튼 자체의 모양(원형, 크기, 그림자 등)과 아이콘(content: "\eacf")을 정의합니다..floating-button클래스는 이 버튼을 화면 오른쪽 하단에 고정시키는 역할을 합니다.position: fixed와z-index속성이 핵심입니다. - 플로팅 목차 CSS:
.toc-wrap.floating: 플로팅 목차의 기본 스타일(화면 고정 위치, 크기, 배경, 그림자 등)을 정의합니다. 처음에는 반투명(background-color: rgba(255,255,255,0.1))하며 아이콘만 보입니다..toc-wrap.floating.active: 사용자가 목차 아이콘을 클릭하여 목차가 활성화(열린 상태)되었을 때의 스타일입니다. 배경이 불투명해지고, 내부 목록(ul.toc)과 닫기 버튼(.toc-close-icon)이 보이게 됩니다 (display: block).- 아이콘:
.floating-toc-icon::before는 닫힌 상태의 목차 아이콘(\e241),.toc-close-icon은 열린 상태의 닫기 버튼(x) 스타일을 정의합니다. - 목록 스타일:
.toc-item.h2,.toc-item.h3등은 H2, H3 태그에 해당하는 목차 항목의 들여쓰기와 아이콘/기호를 설정합니다. - 반응형:
@media쿼리는 화면 너비가 450px 이하일 때 플로팅 목차의 상단 위치를 조정하여 모바일 환경에서도 적절히 보이도록 합니다. - 모바일 화면에서, 플로팅 목차 아이콘 크기를 글의 본문 margin 크기(16px)로 맞췄습니다. 또한, 버튼의 margin을 0으로 하였습니다. 이로 인해, 모바일 화면에서는 플로팅 목차가 글 본문에 침범하는 일이 없습니다.
3단계: 자바스크립트 및 HTML 코드 추가
마지막으로 상단 이동 버튼의 클릭 이벤트 처리와 포스트 내 H2 태그를 감지하여 플로팅 목차를 동적으로 생성하는 자바스크립트 코드를 추가합니다. HTML 편집기에서 </body> 태그를 찾아 그 바로 위에 아래 코드를 삽입합니다.
<!--상단 이동 버튼 & 플로팅 목차 시작-->
<div class='floating-button'>
<a class='move-top-btn'/>
</div>
<script>
//<![CDATA[
function createFloatingTOC(){var t=document.querySelector(".post-body");if(!(!t||document.querySelector(".floating .toc-wrap"))){var e=t.querySelectorAll("h2");if(0!==e.length){var a=document.createElement("div");a.classList.add("floating-toc-space"),t.insertBefore(a,t.firstChild);var i=document.createElement("div");i.classList.add("toc-wrap","floating");var n=document.createElement("div");n.classList.add("toc-title");var c=document.createElement("div");c.classList.add("floating-toc-icon");var d=document.createElement("div");d.textContent="Contents",d.classList.add("toc-title-strong");var l=document.createElement("div");l.classList.add("toc-close-icon"),l.textContent="×",c.onclick=function(){i.classList.add("active")},l.onclick=function(){i.classList.remove("active")},n.appendChild(c),n.appendChild(d),n.appendChild(l),i.appendChild(n);var o=document.createElement("ul");o.classList.add("toc"),e.forEach(function(t,e){var a=document.createElement("li");a.classList.add("toc-item"),"H2"===t.tagName?a.classList.add("h2"):"H3"===t.tagName&&a.classList.add("h3");var i=document.createElement("a");i.href="#section-"+e,i.textContent=t.textContent,t.id="section-"+e,i.addEventListener("click",function(e){e.preventDefault();var a=document.getElementById(t.id);if(a){var i=a.getBoundingClientRect().top+window.pageYOffset-80;window.scrollTo({top:i,behavior:"smooth"})}}),a.appendChild(i),o.appendChild(a)}),i.appendChild(o),a.appendChild(i),s(),window.addEventListener("resize",s)}}function s(){window.innerWidth>=768?i.classList.add("active"):i.classList.remove("active")}}window.addEventListener("load",createFloatingTOC),$(document).ready(function(){$(".move-top-btn").on("click",function(){$("html, body").animate({scrollTop:0},500,"swing"),"function"==typeof detectTop&&detectTop()})});
//]]>
</script>
<!--상단 이동 버튼 & 플로팅 목차 끝-->
코드 설명:
- HTML (
<div class='floating-button'>...): 앞서 CSS에서 정의한.floating-button스타일을 적용할 컨테이너와 그 안에 실제 상단 이동 버튼(a.move-top-btn)을 생성합니다. - JavaScript:
createFloatingTOC():.post-body클래스(블로그 본문 영역)를 찾습니다.- 그 안의 모든
h2태그를 찾습니다. (H3는 현재 로직에서 자동으로 포함되지는 않으나, CSS 스타일은 준비되어 있습니다.) h2태그가 하나 이상 있으면, 플로팅 목차를 담을div(toc-wrap floating)를 동적으로 생성합니다.- 목차 제목 영역(
toc-title), 열기 아이콘(floating-toc-icon), 닫기 아이콘(toc-close-icon), 제목 텍스트(toc-title-strong)를 만들고, 각 아이콘 클릭 시.active클래스를 추가/제거하여 목차를 열고 닫는onclick이벤트를 설정합니다. - 각
h2태그를 순회하며 목록 항목(li.toc-item)과 링크(a)를 생성합니다. 링크의href는#section-숫자형태로, 해당h2태그에는id="section-숫자"가 부여됩니다. - 생성된 목차 링크 클릭 시
preventDefault()로 기본 동작(페이지 새로고침)을 막고,scrollTo()를 이용해 해당h2태그 위치로 부드럽게 스크롤합니다. (-80은 상단 메뉴 등에 가려지지 않도록 스크롤 위치를 약간 위로 조절하는 값입니다.) - 만들어진 목차 전체(
n)를 본문 시작 부분에 삽입된floating-toc-spacediv 안에 넣습니다.
tOChandleScroll(): 페이지 스크롤 이벤트를 감지합니다. 사용자가 200px 이상 스크롤하면createFloatingTOC()함수를 한 번만 실행하여 목차를 생성하고, 이후에는 스크롤 이벤트 리스너를 제거하여 불필요한 반복 실행을 막습니다. (페이지 로딩 시 바로 목차를 만들지 않고, 스크롤 시 만드는 것은 성능 최적화를 위함입니다.)$(document).ready(...): jQuery 코드입니다. 페이지 로딩이 완료되면.move-top-btn요소에 클릭 이벤트를 바인딩합니다. 버튼 클릭 시animate({scrollTop:0}, 500)을 통해 0.5초 동안 페이지 최상단으로 부드럽게 스크롤하는 애니메이션을 실행합니다. (대부분의 블로그스팟 테마는 jQuery를 기본 포함하고 있습니다.)
4단계: 저장 및 확인
모든 코드 삽입이 완료되었으면 HTML 편집기 우측 하단의 저장 버튼을 클릭합니다. 이제 블로그 포스트 페이지로 이동하여 스크롤을 조금 내리면 오른쪽 하단에 상단 이동 버튼이 나타나고, 오른쪽 상단에는 플로팅 목차 아이콘이 표시되는 것을 확인할 수 있습니다. 목차 아이콘을 클릭하여 목차가 제대로 열리고 닫히는지, 목차 항목을 클릭하면 해당 H2 제목으로 부드럽게 이동하는지 테스트해보세요.
이제 여러분의 구글 블로그에도 편리한 상단 이동 버튼과 플로팅 목차가 생겼습니다! 독자들이 더 쉽고 편리하게 블로그 콘텐츠를 탐색하는 데 도움이 되기를 바랍니다.