Tutorial: Let's Build a Lightweight Blog System (part 2)

Download

As you remember from part 1, in this tutorial we are creating a lightweight blog system that stores posts as markdown files. It uses a number of libraries: for parsing markdown, for creating the RSS feed, and most importantly the Dispatch micro framework for giving the application structure.

In this part, we will create the views and the CSS that will make the site responsive on mobile devices.

The Views

As you remember from the first part, we used a configuration file - config.ini - to write down the configuration settings of the blog. The last two lines of the file hold the name of the file that holds the layout, and the path to the views:

app/config.ini (lines 12-14)

views.root = app/views
views.layout = layout

These settings are used internally by the Dispatch framework. The first line tells it where to find the views for the site (so that you only need to specify a name when rendering them) and the second is the layout. This is an HTML template that is included with every view that you render. This is a standard HTML5 document with a few additional meta tags to make it mobile-friendly:

app/views/layout.html.php

<!DOCTYPE html>
<html>
<head>
    <title><?php echo isset($title) ? _h($title) : config('blog.title') ?></title>

    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" user-scalable="no" />
    <meta name="description" content="<?php echo config('blog.description')?>" />

    <link rel="alternate" type="application/rss+xml" title="<?php echo config('blog.title')?>  Feed" href="<?php echo site_url()?>rss" />

    <link href="<?php echo site_url() ?>assets/css/style.css" rel="stylesheet" />
    <link href="http://fonts.googleapis.com/css?family=Open+Sans+Condensed:700&subset=latin,cyrillic-ext" rel="stylesheet" />

    <!--[if lt IE 9]>
        <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->

</head>
<body>

    <aside>

        <h1><a href="<?php echo site_url() ?>"><?php echo config('blog.title') ?></a></h1>

        <p class="description"><?php echo config('blog.description')?></p>

        <ul>
            <li><a href="<?php echo site_url() ?>">Home</a></li>
            <li><a href="https://tutorialzine.com/members/">Members area</a></li>
            <li><a href="https://tutorialzine.com/contact/">Contact Us</a></li>
        </ul>

        <p class="author"><?php echo config('blog.authorbio') ?></p>

    </aside>

    <section id="content">

        <?php echo content()?>

    </section>

</body>
</html>

In the head section I am also including a font from Google Web Fonts, and a HTML5 shim that will make it work on browsers as old as IE8. Throughout this view, I am printing the settings we put in config.ini, by using the config() function provided by Dispatch. This will let you customize the blog solely from the config file. Another function provided by dispatch is site_url() which gives you the absolute URL of your blog, so that you can include stylesheets, images or use it as the base for links.

Notice the call to the content() function. What this does, is print the HTML generated by one of the other views. This allows for other views to be "nested" inside it. For example running this code:

index.php (lines 29-33)

 render('main',array(
        'page' => $page,
        'posts' => $posts,
        'has_pagination' => has_pagination($page)
    ));

Will embed the main.html.php template you see below in the view. The page, posts and has_pagination members of the array will be available as variables:

app/views/main.html.php

<?php foreach($posts as $p):?>
    <div class="post">
        <h2><a href="<?php echo $p->url?>"><?php echo $p->title ?></a></h2>

        <div class="date"><?php echo date('d F Y', $p->date)?></div>

        <?php echo $p->body?>
    </div>
<?php endforeach;?>

<?php if ($has_pagination['prev']):?>
    <a href="?page=<?php echo $page-1?>" class="pagination-arrow newer">Newer</a>
<?php endif;?>

<?php if ($has_pagination['next']):?>
    <a href="?page=<?php echo $page+1?>" class="pagination-arrow older">Older</a>
<?php endif;?>

This will present a list of posts on the screen, with optional back/forward arrows. The other template that also operates with posts, is post.html.php, which shows a single post:

app/views/post.html.php

<div class="post">

    <h2><?php echo $p->title ?></h2>

    <div class="date"><?php echo date('d F Y', $p->date)?></div>

    <?php echo $p->body?>

</div>

This is the view that you would need to edit if you want to add social sharing buttons or comment widgets from Facebook or Disqus.

And lastly, here is the 404 page:

app/views/404.html.php

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />

    <title>404 Not Found | <?php echo config('blog.title') ?></title>
    <link href="<?php echo site_url() ?>assets/css/style.css" rel="stylesheet" />

    <!-- Include the Open Sans font -->
    <link href="http://fonts.googleapis.com/css?family=Open+Sans+Condensed:700&subset=latin,cyrillic-ext" rel="stylesheet" />

</head>
<body>

    <div class="center message">
        <h1>This page doesn't exist!</h1>
        <p>Would you like to try our <a href="<?php echo site_url() ?>">homepage</a> instead?</p>
    </div>

</body>
</html>

Note that this view is a complete HTML5 document. This is because it doesn't follow the same layout as the rest of the blog. In the Dispatch framework, you can render a view that does not get embedded in the site layout, by passing false as the last argument to render:

app/includes/functions.php (lines 95-97)

function not_found(){
    error(404, render('404', null, false));
}

Now that we have all the fancy HTML printed to the screen, let's style it!

The CSS

In this part of the tutorial, we will write the CSS that will make the blog pretty and responsive. All these styles are located in the file assets/css/styles.css that you can edit to your liking. One of the reason this blog is so fast to load is because the design is entirely CSS-based, and I haven't used any images (thanks to a data url trick that you will see in a moment).

Let's start with the headings:

h1{
    font: 14px 'Open Sans Condensed', sans-serif;
    text-transform:uppercase;
    margin-bottom: 24px;
}

h2{
    font: 48px 'Open Sans Condensed', sans-serif;
}

h1 a, h2 a{
    color:#4f4f4f !important;
    text-decoration: none !important;
}

Next is the content and posts. Notice the background image to .post .date:before.

#content{
    position: absolute;
    font: 16px/1.5 'PT Serif', Times, Cambria, serif;
    width: 580px;
    left: 50%;
    margin-left: -100px;
}

#content p,
#content ul{
    margin-bottom:25px;
}

#content ul{
    padding-left:20px;
}

#content li{
    margin-bottom:5px;
}

/* The actual post styles */

.post{
    padding: 50px 0 15px 0;
    border-bottom: 1px solid #dfdfdf;
}

.post .date{
    font: bold 12px 'Open Sans Condensed', sans-serif;
    text-transform: uppercase;
    color: #a7a7a7;
    margin: 24px 0 30px 20px;
    position: relative;
}

/* The calendar icon is set as a data url */

.post .date:before{
    width:18px;
    height:18px;
    position:absolute;
    content:'';
    left: -22px;
    top: -1px;
    background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA..')
}

This is the Data URI scheme, which allows for data which would normally be a separate file to to be presented inline. So by encoding the icon in base64 and placing it directly in the background property, I am saving a request to the server.

Next, we have the left static bar, which always takes up the full height of the page:

aside{
    position: fixed;
    width: 250px;
    height: auto;
    top: 0;
    left: 50%;
    bottom: 0;
    margin-left: -460px;
    padding-top: 65px;
}

aside p.description{
    font-size: 13px;
    line-height: 1.8;
    margin-bottom: 40px;
    color:#787878;
}

/* The main navigation links */
aside ul{
    font: bold 18px 'Open Sans Condensed', sans-serif;
    text-transform: uppercase;
    list-style:none;
}

aside ul li a{
    text-decoration:none !important;
    display:inline-block;
    padding:0 3px;
    margin:2px 0 2px 10px;
}

aside ul li a:hover{
    background-color:#389dc1;
    color:#fff;
}

aside p.author{
    position: absolute;
    bottom: 20px;
    height: 30px;
    font-size: 12px;
    color: #888;
}
simple-php-blogging-system.png

After this, we will style the pagination arrows:

.pagination-arrow{
    display: inline-block;
    font: bold 16px/1 'Open Sans Condensed', sans-serif;
    border: 1px solid #ccc;
    border-radius: 3px;
    margin: 20px 15px;
    color: #555 !important;
    padding: 8px 12px;
    text-decoration: none !important;
    text-transform: uppercase;
    position: relative;
}

.pagination-arrow.newer{
    padding-left: 20px;
}

.pagination-arrow.older{
    padding-right: 20px;
    float:right;
}

.pagination-arrow.newer:before,
.pagination-arrow.older:before{
    content: '';
    border: 5px solid #555;
    border-color: transparent #555 transparent transparent;
    width: 0;
    height: 0;
    position: absolute;
    left: 3px;
    top: 12px;
}

.pagination-arrow.older:before{
    left:auto;
    right:3px;
    border-color: transparent transparent transparent #555;
}

I am using an old border trick to create triangular arrows with CSS. Next are the styles, specific to the 404 page:

.message{
    padding-top:50px;
}

.message h1{
    font-size:36px;
    margin-bottom: 18px;
}

.message p{
    font-size:13px;
}

.center{
    text-align:center;
}

And lastly, we have the media queries, that will tweak the layout depending on the resolution of the device:

/* Small tablets */

@media all and (max-width: 1024px) {
    aside{
        left: 5%;
        margin-left: 0;
        width: 25%;
    }

    #content{
        left: 35%;
        margin-left: 0;
        width: 60%;
    }
}

/* Smartphones */

@media all and (max-width: 840px) {

    h2{
        font-size:36px;
    }

    aside{
        margin-left: 0;
        position: static;
        width: 90%;
        padding: 5% 5% 0 5%;
        text-align: center;
    }

    aside .description{
        margin-bottom: 25px;
    }

    aside li {
        display: inline-block;
    }

    aside ul{
        text-align: center;
    }

    aside .author{
        display: none;
    }

    #content{
        position: static;
        padding: 5%;
        padding-top: 0;
        width: 90%;
    }
}

With this our lightweight flat-file blog is ready!

Done!

One benefit of using a flat file system is that it is much simpler to set up and deploy. Thanks to the markdown format, it is also incredibly easy to write blog posts. As everything is a file in the blog folder, you can use git to manage your blog's revisions and to deploy it. The system is also highly customizable and with some CSS you can adapt it to your existing website.

Bootstrap Studio

The revolutionary web design tool for creating responsive websites and apps.

Learn more

Related Articles