구글 블로그 테마 만들기 글 목록과 본문을 연결하는 완성 소스 가이드

구글 블로그 테마 만들기 글 목록과 본문을 연결하는 완성 소스 가이드


구글 블로그 테마 만들기 구글 블로거에서 글 목록과 본문을 완벽하게 구현하는 핵심 위젯 구조와 조건문 활용법을 상세히 분석합니다.


많은 분들이 나만의 개성 넘치는 구글 블로그를 운영하고 싶어 하지만, 복잡한 테마 구조와 XML 태그 문법 앞에서는 막막함을 느끼곤 합니다. 단순히 예쁜 스킨을 내려받아 설치하는 것을 넘어, 내가 원하는 대로 레이아웃을 수정하고 제어하려면 테마의 핵심 뼈대를 이해해야 합니다. 이번 글에서는 구글 블로그 테마 만들기 시리즈 2편으로, 지난 시간에 다룬 최소한의 기본 파일에 실제 작성한 글 리스트가 나타나고 이를 클릭했을 때 상세한 본문 글이 매끄럽게 출력되는 동적 화면 전환 구조를 단계별로 명쾌하게 정리해 드립니다.


요약 주제 구글 블로그 테마 만들기 2편 및 글 목록, 본문 구조화 가이드
핵심 요점 Blog1 위젯, b:loop 반복문, b:if 조건문을 조합한 목록 및 본문 분기 처리
추천 대상 구글 블로거 테마를 직접 커스텀하고 반응형 레이아웃을 빌드하려는 운영자

* 위 표는 본문의 내용을 요약한 구글 블로그 테마 커스텀 핵심 가이드입니다.



목차

1. 구글 블로그 데이터 출력의 심장 Blog1 위젯이란 무엇인가

2. 위젯 내부의 실제 실행 단위를 정의하는 b:includable main 역할

3. 수많은 게시글을 순서대로 나열하는 b:loop 반복문의 구동 원리

4. 메인 화면과 글 본문 페이지를 똑똑하게 가려내는 b:if 조건문

5. 글 목록 인터페이스를 화려하게 구성하는 내부 핵심 속성 파헤치기

6. 온전한 콘텐츠 몰입을 유도하는 상세 본문 페이지 영역의 구조 분석

7. 목록과 본문 기능이 완벽히 결합된 2편 커스텀 완성 소스 코드

8. 구글 블로그 테마 레이아웃 핵심 요약

9. 자주 묻는 질문


구글 블로그 데이터 출력의 심장 Blog1 위젯이란 무엇인가


구글 블로그 테마 환경에서 우리가 작성한 소중한 게시글들을 화면에 불러오기 위해서는 시스템이 인식할 수 있는 고유한 상자가 필요합니다. 이것이 바로 b:widget 태그이며 그중에서도 블로그 포스트 출력을 전담하는 핵심 객체가 바로 Blog1 위젯입니다. 이 태그가 누락되거나 비어 있으면 아무리 글을 열심히 작성해도 메인 화면이나 주소창에 아무런 데이터가 표시되지 않습니다.


서버에 저장된 수많은 글 중에서 정해진 개수만큼 데이터를 요청하고, 이를 테마 엔진으로 전달해 주는 매개체 역할을 수행한다고 이해하면 쉽습니다. 대량의 서적들이 꽂혀 있는 거대한 도서관에서 독자가 원하는 책들을 한 번에 10 권씩 카트에 담아 열람실 테이블로 날라다 주는 전용 수레와 같은 개념입니다. 이 수레가 정상적으로 작동해야만 비로소 화면에 글이 쌓이기 시작합니다.


알아두세요!
maxResults 속성 값을 조정하면 한 페이지에 노출될 최대 게시글 개수를 자유롭게 제어할 수 있어 로딩 속도 최적화에 유리합니다.


위젯 내부의 실제 실행 단위를 정의하는 b:includable main 역할

깔끔한 코딩 작업용 모니터와 작업 환경
메인 템플릿 마크업 조리 공간 구성

수레를 통해 안전하게 배달된 글 데이터 뭉치들을 이제 어떻게 풀어헤쳐서 화면에 그릴지 구체적인 명령서 역할을 수행하는 영역이 필요합니다. 구글 블로거 테마 안에서 b:includable 태그는 특정 위젯이 실행될 때 호출되는 실질적인 작업 단위를 의미하며, 그중에서도 id가 main으로 지정된 블록은 위젯이 로드될 때 가장 먼저 무조건 실행되는 필수 메인 엔진룸입니다.


아무리 좋은 재료들이 박스 채로 주방에 입고되었다 하더라도, 이를 요리하기 위한 메인 조리대가 없다면 음식을 완성할 수 없는 것과 같은 이치입니다. 이 main 인클루더블 공간 영역 안에 앞으로 우리가 디자인할 목록 형태와 본문 페이지의 레이아웃 HTML 코드가 고스란히 담기게 되므로 전체 테마 소스 코드 중에서도 가장 집중해서 다뤄야 하는 핵심 구역입니다.


태그명주요 역할필수 여부
b:widget (Blog)구글 서버로부터 포스트 데이터를 요청 및 로드필수
b:includable (main)로드된 데이터를 화면에 출력하는 기본 연산 공간필수


수많은 게시글을 순서대로 나열하는 b:loop 반복문의 구동 원리


메인 조리대까지 확보되었다면 이제 데이터 뭉치에 들어 있는 여러 개의 글을 하나씩 차례대로 꺼내어 브라우저 화면에 뿌려줄 차례입니다. 서버에서 받아온 데이터는 배열 형태로 묶여 있기 때문에 이를 풀어주기 위해 b:loop 태그를 활용하게 됩니다. 이 태그는 저장된 글이 5개든 10개든 지정된 수만큼 내부 코드를 뱅글뱅글 반복 구동시키며 동적으로 리스트를 생성합니다.


이것은 공장에서 컨베이어 벨트가 돌아가며 제품을 하나씩 포장 상자에 담아내는 과정과 정확히 일치합니다. values 속성에 데이터 포스트 목록을 통째로 넘겨주고, var 속성에 지정한 임시 변수명을 매개로 삼아 반복문이 한 바퀴 돌 때마다 글의 제목, 작성일, 본문 요약 등의 세부 정보들을 순차적으로 뽑아내어 정돈된 리스트 레이아웃을 깔끔하게 빌드해 나갑니다.


반복문 구동 매커니즘 예시

데이터 전체 뭉치 -> 루프 작동 -> 1번 글 추출 및 HTML 결합 -> 2번 글 추출 및 HTML 결합 -> 설정한 최대 개수 도달 시 자동 종료


메인 화면과 글 본문 페이지를 똑똑하게 가려내는 b:if 조건문


블로그 운영 과정에서 사용자가 메인 홈 주소로 접속했을 때는 최신 글들이 정렬된 요약 목록 리스트가 보여야 하고, 특정 글의 제목을 클릭해 들어갔을 때는 온전한 전체 본문 내용만 넓게 표시되어야 합니다. 그렇다면 하나의 테마 파일 안에서 방문자의 접속 환경을 어떻게 감지하고 다른 화면을 보여줄 수 있을까요? 이때 구글 엔진이 제공하는 b:if cond 조건문이 등판합니다.


특히 data:view.isMultipleItems 구문은 현재 주소가 메인 페이지, 카테고리(라벨) 목록, 혹은 아카이브처럼 여러 개의 글을 동시에 노출해야 하는 다중 항목 화면인지를 판별하는 척도가 됩니다. 이 조건이 참일 때는 목록형 레이아웃인 아티클 박스를 보여주고, 참이 아닐 때(b:else)는 낱개의 완성된 상세 본문 콘텐츠 레이아웃으로 분기하여 화면을 완전히 전환시키는 스마트한 관문 역할을 수행합니다.


주의하세요!
조건문 태그가 제대로 닫히지 않거나 속성 오타가 발생하면 테마 저장 시 컴파일 에러가 발생하여 블로그 전체 화면이 먹통이 될 수 있으므로 태그 쌍을 철저히 확인해야 합니다.


글 목록 인터페이스를 화려하게 구성하는 내부 핵심 속성 파헤치기


방문자가 들어왔을 때 가장 먼저 마주하는 다중 목록 화면 영역에서는 제목과 요약 글, 그리고 시선을 사로잡는 대표 이미지가 조화롭게 어우러져야 체류 시간이 늘어납니다. 구글 테마 코드 내부를 살펴보면 하이퍼링크의 목적지를 동적으로 연결하는 expr:href 구문과 시스템에 저장된 실제 제목 텍스트를 파싱하는 data:post.title 구문이 단단하게 맞물려 작동함을 알 수 있습니다.


여기에 썸네일 노출 여부를 영리하게 판단해 주는 조건문이 결합하여 글 작성을 할 때 대표 사진을 등록한 경우에만 우측이나 좌측에 정돈된 크기의 이미지가 쏙 나타나도록 제어합니다. 만약 글에 이미지가 전혀 없다면 텍스트 영역이 알아서 공간을 넓게 차지하도록 레이아웃 유연성을 확보해 주므로 깔끔하고 일관성 있는 디자인 밸런스를 상시 유지할 수 있게 됩니다.


목록 구성 요소 매핑 관계

  • expr:href='data:post.url': 글 고유 주소를 링크에 대입
  • data:post.snippets.long: 본문 상단 내용을 3줄 내외로 깔끔하게 추출한 요약본
  • data:post.featuredImage: 글 내부 첫 번째 이미지를 썸네일 경로로 자동 호출


온전한 콘텐츠 몰입을 유도하는 상세 본문 페이지 영역의 구조 분석


목록에서 원하는 제목을 클릭해 들어온 독자가 마주하게 되는 최종 상세 페이지는 화려한 요소들을 최대한 덜어내고 텍스트 본연의 가독성에만 집중할 수 있는 구조를 갖추어야 최적의 사용자 경험을 전달할 수 있습니다. 본문 영역을 뜻하는 아티클 구조 내부에는 글의 대제목 역할을 수행하는 h1 태그와 실제 정성스레 작성한 방대한 글 내용이 통째로 출력되는 데이터 바디 구문이 위치하게 됩니다.


데이터 바디 태그는 우리가 에디터 창에서 입력한 단락, 서식, 인용구, 첨부 이미지 등 모든 멀티미디어 요소를 왜곡 없이 100% 온전하게 렌더링해 주는 핵심 전송관입니다. 여기에 추가적으로 하단에 추천 글 스크립트 영역을 유기적으로 배치하여 현재 읽고 있는 글의 라벨(카테고리) 정보를 수집하고 연관성 높은 다른 유익한 포스팅을 자연스럽게 제안하는 확장성까지 깔끔하게 구현할 수 있습니다.


알아두세요!
본문 내부에 포함된 자바스크립트는 현재 포스트의 첫 번째 라벨 변수명을 추출하여 향후 동적 연관 게시글 고도화를 진행할 때 핵심 앵커 역할을 수행합니다.


목록과 본문 기능이 완벽히 결합된 2편 커스텀 완성 소스 코드


지금까지 배운 이론과 세부 핵심 태그들을 하나의 파일로 정밀하게 엮어낸 전체 완성 코드를 아래에 공유합니다. 이 소스 코드는 구글 블로거 시스템의 최신 마크업 표준 버전을 준수하며 데스크톱 화면은 물론이고 모바일 환경에서도 화면이 깨지지 않고 부드럽게 재배치되는 고도의 미디어 쿼리 반응형 CSS 스타일까지 내장되어 있어 곧바로 실전에 대입할 수 있는 강력한 뼈대가 됩니다.


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html b:css='false' b:defaultwidgetversion='2' b:layoutsversion='3' b:responsive='true' xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2004/bml' xmlns:data='http://www.google.com/2004/bml/data' xmlns:expr='http://www.google.com/2004/bml/expr' expr:dir='data:blog.languageDirection' expr:lang='data:blog.locale'>
<head>
	<meta content='width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1' name='viewport'/>
	<title><data:view.title.escaped/></title>
	<b:include data='blog' name='all-head-content'/>
	<b:skin><![CDATA[	
	/*
    [관리자 레이아웃 편집기용] - 오직 관리자 레이아웃 화면에만 사용되는 CSS
    */
    body#layout #content {
        display: block !important;
        max-width: 1200px !important;
        width: 100% !important;
        margin: auto;
    }
	
	body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; line-height: 1.7; color: #333; }
	/* 2편에서 변경된 css */
	#content {
		width: 1024px;
		margin: auto;
		padding: 30px;
	}
	
	/* 2편에서 추가된 css */
	/*
    메인 포스트 목록 레이아웃 관련
    */
    article { margin-bottom: 40px; border-bottom: 1px solid #eee; padding-bottom: 30px; }
    .post-item-wrapper {
		display: flex;
		gap: 20px;
		justify-content: space-between;
		align-items: flex-start;
    }
    .post-text-side {
		flex: 1; 
    }
    .post-text-side h2 {
		margin-top: 0;
		margin-bottom: 10px;
		font-size: 22px;
    }
    .post-text-side h2 a {
		color: #333;
    }
    .post-text-side h2 a:hover {
		color: #0066cc;
    }
	.clean-snippet {
		margin: 0;
		color: #666;
		font-size: 14px;
		display: -webkit-box;
		-webkit-line-clamp: 3; 
		-webkit-box-orient: vertical;
		overflow: hidden;
    }
    .post-thumb-side {
		width: 200px; 
		flex-shrink: 0;
    }
    .post-thumb {
		width: 100%;
		height: 130px;
		object-fit: cover;
		display: block;
		border-radius: 6px;
    }
    /* [모바일대응] 반응형 미디어 쿼리 */
    @media (max-width: 768px) {
		.post-item-wrapper {
			flex-direction: column-reverse; 
			gap: 15px;
		}
		.post-thumb-side {
			width: 100%; 
		}
		.post-thumb {
			height: 200px;
		}
		.post-text-side h2 {
			font-size: 18px;
		}
    }
	]]></b:skin>
</head>
<body>
	<b:section id='content' showaddelement='yes'>
	  <b:widget id='Blog1' locked='true' title='Blog Posts' type='Blog' maxResults='10'>
        <b:includable id='main'>
          <b:loop values='data:posts' var='post'>
            <b:if cond='data:view.isMultipleItems'>
                <article>
                  <div class='post-item-wrapper'>
                    <div class='post-text-side'>
                      <h2><a expr:href='data:post.url'><data:post.title/></a></h2>
                      <p class="clean-snippet">
                        <data:post.snippets.long/>
                      </p>
                    </div>                    
                    <b:if cond='data:post.featuredImage'>
                      <div class='post-thumb-side'>
                        <a expr:href='data:post.url'>
                          <img class='post-thumb' expr:src='data:post.featuredImage' expr:alt='data:post.title'/>
                        </a>
                      </div>
                    </b:if>
                  </div>
                </article>
            <b:else/>
              <article>
                <header class='post-title' aria-label='게시글 제목 영역'><h1><data:post.title/></h1></header>
                <div class='post-body'><data:post.body/></div>
              </article>
            </b:if>
          </b:loop>
        </b:includable>
      </b:widget>
	</b:section>  
</body>
</html>


구글 블로거는 계정당 최대 100개까지 독립된 스페이스 블로그를 전면 무료로 무제한 생성할 수 있는 엄청난 혜택을 제공합니다. 따라서 기존에 잘 운영 중인 본진 플랫폼 레이아웃을 건드리는 리스크를 감수할 필요 없이 테스트용 서브 계정을 하나 가볍게 개설한 뒤, 위 코드를 빈 테마에 덮어쓰기 하여 직접 구동해 보는 방식을 적극 권장합니다. 코드를 저장하고 글을 2~3개 테스트용으로 작성해 보면 왜 이 태그가 필요했는지 단박에 온몸으로 체감할 수 있습니다.


또한 테마 저장을 완료하면 구글 서버 시스템이 내부적으로 블로그 구동에 필수적인 보안 메타 데이터나 기본 부가 스크립트 코드들을 우리가 작성한 소스 앞뒤로 자동으로 친절하게 삽입해 줍니다. 이렇게 생성된 최종 화면에서 브라우저 우클릭 후 소스 보기(View Source) 메뉴를 눌러 변경된 전체 날것의 리얼 소스를 꼼꼼히 역추적하며 비교 분석해 보면, 구조를 독학하고 스킨 커스텀 실력을 비약적으로 끌어올리는 데 이보다 더 좋은 교과서는 없다고 단언합니다.


구글 블로그 테마 레이아웃 핵심 요약

본문에서 다룬 가장 중요한 핵심 제어 기법을 요약하면 다음과 같습니다.


  1. Blog1 위젯 빌드: 포스트 데이터를 불러오는 수레 역할이자 핵심 필수 상자입니다.
  2. 반복문과 분기 처리: b:loop문으로 글을 순차 추출하고 b:if 조건문으로 홈 목록과 내부 본문 화면을 완벽 분리합니다.
  3. 무료 테스트 실천: 100개까지 무료인 점을 이용해 테스트 블로그에서 소스 분석 방식으로 학습 효율을 극대화합니다.


자주 묻는 질문

Q: 위 코드를 복사해서 저장하는데 XML 파싱 에러가 발생합니다. 원인이 무엇인가요?
A: 구글 테마는 철저한 XML 규칙을 따르기 때문에 태그가 열린 후 제대로 닫히지 않았거나, 특수 기호(< 또는 >)를 조건문 내부에서 이스케이프 처리하지 않았을 때 발생합니다. 코드 블록에 표기된 형태 그대로 대소문자 구분을 확실히 하여 붙여넣기 하셨는지 재확인해 보세요.
Q: 메인 화면에서 글 요약본 길이를 더 길게 하거나 짧게 조절할 수 있나요?
A: 네, 가능합니다. 본문 소스에 사용된 data:post.snippets.long 대신에 더 짧은 영역을 제공하는 data:post.snippets.short를 사용하거나, CSS 코드 내에 위치한 webkit-line-clamp 속성의 숫자 3을 4나 5로 변경하면 화면에 노출되는 텍스트 줄 수를 기호에 맞게 마음대로 늘릴 수 있습니다.
Q: 썸네일 이미지 크기가 화면 크기에 따라 일정하게 찌그러지지 않게 하려면 어떻게 하나요?
A: 제공해 드린 스타일시트 완성 코드 내부를 보시면 .post-thumb 요소에 object-fit: cover 속성이 이미 정밀하게 내장되어 있습니다. 이 속성이 지정되어 있으면 가로세로 비율이 깨지거나 가로로 늘어나는 왜곡 현상 없이, 정해진 사각형 프레임 크기에 맞춰 원본 사진 중심부를 기준으로 깔끔하게 크롭 처리가 이루어집니다.


태그: 구글블로그, 블로그테마, 테마만들기, HTML레이아웃, 블로거코딩, 구글 블로그 테마 만들기