5202

ein Blog über technische Fragen zu Blogger

Blogger: Ein eigenes Template entsteht - Teil 10 - Fefes Blog-Layout

von

Machen wir in der heutigen Folge von 'Ein eigenes Template entsteht' was cooles und zwar bauen wir ein Layout à la Fefes Blog.

Ungeachtet seines sehr einfachen Designs ist das übrigens eines der größten deutschen Blogs. Daran seht ihr: Erfolgreiche Blogs funktionieren nicht über das Layout, sondern immer über den Inhalt :D.

Nullform

Starten wir mit dem Basis-Layout. In dem Basis-Layout liegt ein Blog-Widget in der Nullform.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html>

 <head>
     <title><data:blog.pageTitle/></title>
<b:skin><![CDATA[
]]></b:skin>
</head>

<body>
<b:section id='main' class='main' >
  <b:widget id='Blog1' locked='false' title='Blogposts' type='Blog'>
    <b:includable id='main'/>
    <b:includable id='backlinkDeleteIcon'/>
    <b:includable id='backlinks'/>
    <b:includable id='comment-form'/>
    <b:includable id='commentDeleteIcon'/>
    <b:includable id='comment_count_picker'/>
    <b:includable id='comment_picker'/>
    <b:includable id='comments'/>
    <b:includable id='feedLinks'/>
    <b:includable id='feedLinksBody'/>
    <b:includable id='iframe_comments'/>
    <b:includable id='mobile-index-post'/>
    <b:includable id='mobile-main'/>
    <b:includable id='mobile-nextprev'/>
    <b:includable id='mobile-post'/>
    <b:includable id='nextprev'/>
    <b:includable id='post'/>
    <b:includable id='postQuickEdit'/>
    <b:includable id='shareButtons'/>
    <b:includable id='status-message'/>
    <b:includable id='threaded-comment-form'/>
    <b:includable id='threaded_comment_js'/>
    <b:includable id='threaded_comments'/>
  </b:widget>
</b:section>
</body>

</html>

Blog-Widget

Wir haben im letzten Post mithilfe der Daten-Elemente 'title' und 'body' eine Schleife formuliert:

  <b:loop values='data:posts' var='i'>
        <h2><data:i.title/></h2>
        <div><data:i.body/></div>
   </b:loop>

Lagern wir diese Daten-Elemente zunächst in die <b:includable id='post'/> aus.

<b:includable id='post'>
         <h2><data:i.title/></h2>
        <div><data:i.body/></div>
</b:includable>
Die includable rufen wir in der Schleife über einen include Tag auf:
  <b:widget id='Blog1' locked='false' title='Blogposts' type='Blog'>
    <b:includable id='main'>
        <b:loop values='data:posts' var='i'>    
            <b:include name='post' data='i'/>
       </b:loop>
    </b:includable>
    <b:includable id='backlinkDeleteIcon'/>
    <b:includable id='backlinks'/>
    <b:includable id='comment-form'/>
    <b:includable id='commentDeleteIcon'/>
    <b:includable id='comment_count_picker'/>
    <b:includable id='comment_picker'/>
    <b:includable id='comments'/>
    <b:includable id='feedLinks'/>
    <b:includable id='feedLinksBody'/>
    <b:includable id='iframe_comments'/>
    <b:includable id='mobile-index-post'/>
    <b:includable id='mobile-main'/>
    <b:includable id='mobile-nextprev'/>
    <b:includable id='mobile-post'/>
    <b:includable id='nextprev'/>
    <b:includable id='post' var='i'>
         <h2><data:i.title/></h2>
         <div><data:i.body/></div>
    </b:includable>
    <b:includable id='postQuickEdit'/>
    <b:includable id='shareButtons'/>
    <b:includable id='status-message'/>
    <b:includable id='threaded-comment-form'/>
    <b:includable id='threaded_comment_js'/>
    <b:includable id='threaded_comments'/>
  </b:widget>

Die Variable 'i' wird an den include Tag mit einem data Attribut übergegeben.

Heads up! Das Attribut var='i' im <b:includable id='post'/> Tag ist nicht notwendig - aber es ist sauberer, wenn ihr Variablen immer deklariert!

Erweiterungen

Erweitern wir nun das Layout um ein Post Datum:

 <b:includable id='post' var='i'>
         <h2><data:i.dateHeader/></h2>
         <h3><data:i.title/></h3>
         <div><data:i.body/></div>
</b:includable>
Heads up! Beachtet die Definition für dieses Tag:

The date of this post, only present if this is the first post in the list that was posted on this day.

Das bedeutet, dass bei mehreren Posts am Tag nur einmal ein Datum angezeigt wird! Wenn ihr das nicht wollt, könnt ihr den timestamp Tag nehmen.

In der jetzigen Schreibweise wird bei mehreren Posts am Tag zwar kein Datum, aber ein h2 Tag geschrieben. Das ist hässlich und das ändern wir, indem wir einen konditionalen Tag formulieren:

    <b:includable id='post' var='i'>
       <b:if cond='data:i.dateHeader'>
         <h2><data:i.dateHeader/></h2>
      </b:if>
         <h3><data:i.title/></h3>
         <div><data:i.body/></div>
    </b:includable>

Damit wird der h2 Tag nur angezeigt, falls er existiert.

Post-Seiten

Bis jetzt haben wir nur mit der Startseite beschaftigen - wir wollen aber natürlich auch einen Link zu den Post-Seiten haben.

Einen solchen Link formulieren wir über den bereits bekannten expr Tag:

<b:includable id='post' var='i'>
       <b:if cond='data:i.dateHeader'>
         <h2><data:i.dateHeader/></h2>
      </b:if>
      <h3><a expr:href='data:i.url'><data:i.title/></a></h3>
         <div><data:i.body/></div>
    </b:includable>

Nicht immer besitzt ein Post einen Link - formulieren wir einen weiteren konditionalen Tag mit einem Platzhalter und zwar für den Fall, das der Post keinen Titel hat.

<b:includable id='post' var='i'>
       <b:if cond='data:i.dateHeader'>
         <h2><data:i.dateHeader/></h2>
      </b:if>
      <b:if cond='data:i.title'>
      <h3><a expr:href='data:i.url'><data:i.title/></a></h3>
        <b:else />
        <h3><a expr:href='data:i.url'>[1]</a></h3>
        </b:if>
         <div><data:i.body/></div>
    </b:includable>

Versteht ihr, was da passiert? Falls ein Post einen Titel hat, wird der normale Post-Titel mit Link angezeigt - andernfalls wird der Platzhalter [1] mit Link ausgeliefert.

Älterer Post - Neuerer Post

Was jetzt noch fehlt ist die Möglichkeit innerhalb des Blogs auf Älterer Post - Neuerer Post zu navigieren. Formulieren wir die entsprechenden Tags innerhalb der includable nextprev:

<b:includable id='nextprev'>
     <a class='blog-pager-newer-link' expr:href='data:newerPageUrl'><data:newerPageTitle/></a>
      <a  expr:href='data:olderPageUrl' ><data:olderPageTitle/></a>
</b:includable>

Nachdem es Posts gibt, die keinen Link zu einem älterer oder neueren Post haben und das auf einen Leser a bisserl verwirrend wirkt, schreiben wir diese Links doch innerhalb eines konditionalen Tags

<b:includable id='nextprev'>
    <b:if cond='data:newerPageUrl'>
     <a expr:href='data:newerPageUrl'>
       <data:newerPageTitle/>
      </a>
    </b:if>
    <b:if cond='data:olderPageUrl'>
      <a expr:href='data:olderPageUrl' >
        <data:olderPageTitle/>
      </a>
    </b:if>
    </b:includable>

Die includable rufen wir dann mit einem weiteren include Tag auf:

<b:include name='nextprev'/>

Um an der Stelle mal wieder a bisserl Überblick zu bekommen, hier das gesamte Widget am Stück:

  <b:widget id='Blog1' locked='false' title='Blogposts' type='Blog'>
    <b:includable id='main'>
       <b:loop values='data:posts' var='i'>    
            <b:include data='i' name='post'/>
       </b:loop>
      <b:include name='nextprev'/>
    </b:includable>
    <b:includable id='backlinkDeleteIcon'/>
    <b:includable id='backlinks'/>
    <b:includable id='comment-form'/>
    <b:includable id='commentDeleteIcon'/>
    <b:includable id='comment_count_picker'/>
    <b:includable id='comment_picker'/>
    <b:includable id='comments'/>
    <b:includable id='feedLinks'/>
    <b:includable id='feedLinksBody'/>
    <b:includable id='iframe_comments'/>
    <b:includable id='mobile-index-post'/>
    <b:includable id='mobile-main'/>
    <b:includable id='mobile-nextprev'/>
    <b:includable id='mobile-post'/>
    <b:includable id='nextprev'>
    <b:if cond='data:newerPageUrl'>
     <a expr:href='data:newerPageUrl'>
       <data:newerPageTitle/>
      </a>
    </b:if>
    <b:if cond='data:olderPageUrl'>
      <a expr:href='data:olderPageUrl' >
        <data:olderPageTitle/>
      </a>
    </b:if>
    </b:includable>
    <b:includable id='post' var='i'>
       <b:if cond='data:i.dateHeader'>
         <h2><data:i.dateHeader/></h2>
      </b:if>
      <b:if cond='data:i.title'>
      <h3><a expr:href='data:i.url'><data:i.title/></a></h3>
        <b:else />
        <h3><a expr:href='data:i.url'>[1]</a></h3>
        </b:if>
      <div><data:i.body/></div>
    </b:includable>
    <b:includable id='postQuickEdit'/>
    <b:includable id='shareButtons'/>
    <b:includable id='status-message'/>
    <b:includable id='threaded-comment-form'/>
    <b:includable id='threaded_comment_js'/>
    <b:includable id='threaded_comments'/>
  </b:widget>

Fefes Layout

Wir haben gesagt, wir orientieren uns heute an dem Layout von Fefes Blog. Wie ihr mit einem kurzen Blick in das Chrome Entwicklertool feststellen könnt, sind die Posts in Fefes Blog in Form einer unsortierten Liste angeordnet.

Bauen wir diesen Effekt nach:

 <b:includable id='post' var='i'>
    <b:if cond='data:i.dateHeader'>
       <h2><data:i.dateHeader/></h2>
     </b:if>
      <ul>
         <li>
            <b:if cond='data:i.title'>
                <a expr:href='data:i.url'><data:i.title/></a>
            <b:else/>
                 <a expr:href='data:i.url'>[1]</a>
            </b:if>
            <span><data:i.body/></span>
         </li>
       </ul>
  </b:includable>

Damit schaut das Blog-Widget nun so aus:

  <b:widget id='Blog1' locked='false' title='Blogposts' type='Blog'>
    <b:includable id='main'>
       <b:loop values='data:posts' var='i'>    
            <b:include data='i' name='post'/>
       </b:loop>
      <b:include name='nextprev'/>
    </b:includable>
    <b:includable id='backlinkDeleteIcon'/>
    <b:includable id='backlinks'/>
    <b:includable id='comment-form'/>
    <b:includable id='commentDeleteIcon'/>
    <b:includable id='comment_count_picker'/>
    <b:includable id='comment_picker'/>
    <b:includable id='comments'/>
    <b:includable id='feedLinks'/>
    <b:includable id='feedLinksBody'/>
    <b:includable id='iframe_comments'/>
    <b:includable id='mobile-index-post'/>
    <b:includable id='mobile-main'/>
    <b:includable id='mobile-nextprev'/>
    <b:includable id='mobile-post'/>
    <b:includable id='nextprev'>
    <b:if cond='data:newerPageUrl'>
     <a expr:href='data:newerPageUrl'>
       <data:newerPageTitle/>
      </a>
    </b:if>
    <b:if cond='data:olderPageUrl'>
      <a expr:href='data:olderPageUrl' >
        <data:olderPageTitle/>
      </a>
    </b:if>
    </b:includable>
    <b:includable id='post' var='i'>
       <b:if cond='data:i.dateHeader'>
         <h2><data:i.dateHeader/></h2>
      </b:if>
         <ul>
         <li>
        <b:if cond='data:i.title'>
        <a expr:href='data:i.url'><data:i.title/></a>
         <b:else/>
        <a expr:href='data:i.url'>[1]</a>
         </b:if>
         <span><data:i.body/></span>
        </li>
       </ul>
    </b:includable>
    <b:includable id='postQuickEdit'/>
    <b:includable id='shareButtons'/>
    <b:includable id='status-message'/>
    <b:includable id='threaded-comment-form'/>
    <b:includable id='threaded_comment_js'/>
    <b:includable id='threaded_comments'/>
  </b:widget>

Vollständiges Template

Bauen wir nun mit diesem Widget und dem erweiterten Basis-Layout ein vollständiges Template:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html>

 <head>
     <title><data:blog.pageTitle/></title>
&lt;style type=&quot;text/css&quot;&gt;
&lt;!-- /*
 <b:skin><![CDATA[*/
 ]]></b:skin>
</head>

<body>
  <b:section class='header' id='header'>
  </b:section>
<b:section class='main' id='main'>
  <b:widget id='Blog1' locked='false' title='Blogposts' type='Blog'>
    <b:includable id='main'>
       <b:loop values='data:posts' var='i'>    
            <b:include data='i' name='post'/>
       </b:loop>
      <b:include name='nextprev'/>
    </b:includable>
    <b:includable id='backlinkDeleteIcon'/>
    <b:includable id='backlinks'/>
    <b:includable id='comment-form'/>
    <b:includable id='commentDeleteIcon'/>
    <b:includable id='comment_count_picker'/>
    <b:includable id='comment_picker'/>
    <b:includable id='comments'/>
    <b:includable id='feedLinks'/>
    <b:includable id='feedLinksBody'/>
    <b:includable id='iframe_comments'/>
    <b:includable id='mobile-index-post'/>
    <b:includable id='mobile-main'/>
    <b:includable id='mobile-nextprev'/>
    <b:includable id='mobile-post'/>
    <b:includable id='nextprev'>
    <b:if cond='data:newerPageUrl'>
     <a expr:href='data:newerPageUrl'>
       <data:newerPageTitle/>
      </a>
    </b:if>
    <b:if cond='data:olderPageUrl'>
      <a expr:href='data:olderPageUrl' >
        <data:olderPageTitle/>
      </a>
    </b:if>
    </b:includable>
    <b:includable id='post' var='i'>
       <b:if cond='data:i.dateHeader'>
         <h2><data:i.dateHeader/></h2>
      </b:if>
         <ul>
         <li>
        <b:if cond='data:i.title'>
        <a expr:href='data:i.url'><data:i.title/></a>
         <b:else/>
        <a expr:href='data:i.url'>[1]</a>
         </b:if>
         <span><data:i.body/></span>
        </li>
       </ul>
    </b:includable>
    <b:includable id='postQuickEdit'/>
    <b:includable id='shareButtons'/>
    <b:includable id='status-message'/>
    <b:includable id='threaded-comment-form'/>
    <b:includable id='threaded_comment_js'/>
    <b:includable id='threaded_comments'/>
  </b:widget>
</b:section>
&lt;!-- </body> --&gt; &lt;/body&gt; 

</html>

Header

Was noch fehlt ist ein Header mit dem Blog-Titel. Bauen wir dazu ein ganz primitives Header-Widget:

<b:widget id='Header1' locked='false' type='Header'>
      <b:includable id='main'>
        <h1><b:include name='title'/></h1>
        </b:includable>
      <b:includable id='description'/>
      <b:includable id='title'>
       <b:if cond='data:blog.url == data:blog.homepageUrl'>
        <data:title/>
       <b:else/>
        <a expr:href='data:blog.homepageUrl'><data:title/></a>
        </b:if>
</b:includable>

88-Zeilen-Layout!

Das war's -- mission accomplished. Wir habe jetzt ein voll funktionsfähiges Blog-Layout mit insgesamt 88 Zeilen Code!

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html>

 <head>
     <title><data:blog.pageTitle/></title>
&lt;style type=&quot;text/css&quot;&gt;
&lt;!-- /*
 <b:skin><![CDATA[*/
 ]]></b:skin>
</head>

<body>
  <b:section class='header' id='header'>
    <b:widget id='Header1' locked='false' type='Header'>
      <b:includable id='main'>
        <h1><b:include name='title'/></h1>
        </b:includable>
      <b:includable id='description'/>
      <b:includable id='title'>
       <b:if cond='data:blog.url == data:blog.homepageUrl'>
        <data:title/>
       <b:else/>
        <a expr:href='data:blog.homepageUrl'><data:title/></a>
        </b:if>
</b:includable>
    </b:widget>
  </b:section>
<b:section class='main' id='main'>
  <b:widget id='Blog1' locked='false' title='Blogposts' type='Blog'>
    <b:includable id='main'>
       <b:loop values='data:posts' var='i'>    
            <b:include data='i' name='post'/>
       </b:loop>
      <b:include name='nextprev'/>
    </b:includable>
    <b:includable id='backlinkDeleteIcon'/>
    <b:includable id='backlinks'/>
    <b:includable id='comment-form'/>
    <b:includable id='commentDeleteIcon'/>
    <b:includable id='comment_count_picker'/>
    <b:includable id='comment_picker'/>
    <b:includable id='comments'/>
    <b:includable id='feedLinks'/>
    <b:includable id='feedLinksBody'/>
    <b:includable id='iframe_comments'/>
    <b:includable id='mobile-index-post'/>
    <b:includable id='mobile-main'/>
    <b:includable id='mobile-nextprev'/>
    <b:includable id='mobile-post'/>
    <b:includable id='nextprev'>
    <b:if cond='data:newerPageUrl'>
     <a expr:href='data:newerPageUrl'>
       <data:newerPageTitle/>
      </a>
    </b:if>
    <b:if cond='data:olderPageUrl'>
      <a expr:href='data:olderPageUrl'>
        <data:olderPageTitle/>
      </a>
    </b:if>
    </b:includable>
    <b:includable id='post' var='i'>
       <b:if cond='data:i.dateHeader'>
         <h2><data:i.dateHeader/></h2>
      </b:if>
         <ul>
         <li>
        <b:if cond='data:i.title'>
        <a expr:href='data:i.url'><data:i.title/></a>
         <b:else/>
        <a expr:href='data:i.url'>[1]</a>
         </b:if>
         <span><data:i.body/></span>
        </li>
       </ul>
    </b:includable>
    <b:includable id='postQuickEdit'/>
    <b:includable id='shareButtons'/>
    <b:includable id='status-message'/>
    <b:includable id='threaded-comment-form'/>
    <b:includable id='threaded_comment_js'/>
    <b:includable id='threaded_comments'/>
  </b:widget>
</b:section>
&lt;!-- </body> --&gt; &lt;/body&gt; 

</html>
Alle Posts der Reihe

Anmerkung

Mir ist natürlich klar, dass Fefes Blog ein minimalistisches Extremdesign ist. Ich weiß, dass das für die meisten von euch viel zu 'primitiv' ist. Aber: Ihr müsst euch damit mal die Ladezeit von eurem Blog anschauen -- > 0.5s :D.

An dieser kleinen Demo könnt ihr sehen, wie einfach ein Blogger-Layout sein kann, wenn ihr es selber baut. Ich komme hier mit 88 Zeilen Code aus - das Blogger Standard Template 'Simple' hat dagegen 3970 Zeilen Code.

Im nächsten Post schauen wir uns verschiedene Möglichkeiten an, das Blog-Widget auf unterschiedliche Seiten unterschiedlich zu gestalten.