Skip to content
back to top
Just the code, please

Shailesh Codes

TO BUILD A BLOG

Building my blog page (aka my first ever blog post)

By Shailesh Vasandani — Last updated on April 11, 2020 — Reading time: 6 min

to build a blog web design frontend
More from TO BUILD A BLOG
1
2

Tag, you're it — writing a JavaScript tagging library

You see these tags? If not, that's awkward, but if you do, you have this JavaScript library to thank.

3

Adding an estimated reading time to my blog

Blogs with estimated reading times can get over 410% click-through rates. Why wouldn't I add them?

I've heard from many places that the best way to make a good first impression is to write about what you know. Now, without overstating the accuracy of my sources (trust me I looked on Google for like 5 minutes), that doesn't sound like a bad idea. The thing is, I've spent the past few weeks building my personal website, which is a mixture of my online resume, photography portfolio, design portfolio, and this blog, and I've gotten really familiar with what it takes to build a static portfolio website. I'd eventually like to go through the entirety of the website, but that would take too long. So today, I'll be going over how I made my blog page.

A lot of the elements on the page were ported from the others, including the navigation menu, the top bar, and pretty much all the styling. The main novelty is the post collection. At the time of writing, this collection contains exactly one (1) post, but as more posts are added they are dynamically pulled into page and placed into one of four columns. This basic structure isn't that hard to achieve in HTML and CSS:

Hey, it looks like you're on a slightly narrower screen. The code blocks below might not look too good, but the rest of the article should be fine. You can hop on a wider screen if you want to follow along. I'm not going anywhere (promise).

        
      /* HTML */
      <div class="blog-tiles">
        <div class="col"></div>
        <div class="col"></div>
        <div class="col"></div>
        <div class="col"></div>
      </div>

      /* CSS */
      .blog-tiles {
        display: grid;
        width: 100%;
        grid-template-columns: 1fr 1fr 1fr 1fr;
        grid-gap: 15px;
      }

I am a huge fan of the CSS grid feature, and in this case it suits the purpose of the CSS semantically and stylistically. It also would be possible for each column to use CSS flexbox for more granular control, but the default flow of the page works well enough. But wait, I hear you ask. Aren't they just empty columns?

This is where the magic of JavaScript comes in: because I wanted my blog to be dynamic, I decided that I would make my page fill in all the blog posts as the page loads. All I have to do is give it a list of all the posts I want to include. So, that first line of HTML actually looks something like this:

        
      <div class="blog-tiles" data-count="1" data-links="a-fresh-start">

If you look at your URL bar, you'll notice that the URL you're on is the same as the one here: a-fresh-start. That's not a coincidence. The JavaScript on the blog page looked at the data-links that I gave it, and created the link that (probably) took you here. If you're not sure what the data- attributes are, think of them as a way to store data in an HTML element. In this case, I'm storing the number of blog posts I have and their links.

Now, we need to actually do something with that information. In JavaScript, we'll take those values, and loop through them. Since each link needs it's own card/post/box/thing, we'll create some functions to make the whole process a bit easier to understand. Here's what the loopy bit looks like:

        
      const tiles = document.querySelector(".blog-tiles");
      var columns = tiles.querySelectorAll(".col");
      var count = tiles.dataset.count;
      var links = tiles.dataset.links.split(",");

      function initializeColumns() {
        links.forEach((link, index) => {
          getData(link, index);
        });
      }

      window.addEventListener('load', initializeColumns);

As you can see, we first select the tiles element (using the querySelector() method). Then, we select all the columns inside the tiles element, as well as the number of posts and the links that were defined in the HTML. The function in the middle loops through each link, and calls our worker function getData(), and finally, the last line waits for the whole page to load before actually calling the initializeColumns() function.

Following the logic of the code, the program first declares all the variables, waits until the page loads. Once it does, it goes through each of the links and calls getData(). This function is the brains of the whole operation, and it looks like this:

        
      function getData(link, index) {
        var linkData = {};
        let url = urlPrefix + link;

        let xhttp = new XMLHttpRequest();
        xhttp.responseType = 'document';

        xhttp.onreadystatechange = () => {
          if (xhttp.status == 0 || (xhttp.status >= 200 && xhttp.status < 400)) {
            response = xhttp.response;
            if (response != null) {
              linkData["image"] = response.querySelector(".preview-image").innerHTML;
              linkData["title"] = response.querySelector(".preview-title").innerHTML;
              linkData["lede"] = response.querySelector(".preview-lede").innerHTML;

              populateBlogPost(link, linkData, url, index);
            }
          }
        }

        xhttp.open('GET', url, true);
        xhttp.send();
      }

If this looks scary, don't worry - I'm scared of Ajax calls too. What matters is knowing how to use them; the rest you can sell to the JavaScript devil. It's better than selling your soul. Let's go through what's happening here.

Since we're gonna be dynamically creating these links, I decided to store the title and description hidden in the page of each post. The code then performs an Ajax call, which you can think of as opening the webpage and getting its data. This has the really nice added benefit of caching the post, so it's stored on the user's device when they click on the link. This is also all done asynchronously, which means the user's browser has a bunch of little worker processes fetching each webpage and bringing back what it's found.

The linkData variable is where we're going to store our data, and the url variable is just the whole link to the post. Then, we (essentially) create one of those little processes, stored in the xhttp variable, and before sending it off, we tell it what to do when it has the information it needs. Since it's getting the whole post, we need to isolate the preview image, title, and lede. We then store those in the linkData variable, and then call another function to actually do something with all of this information.

Remember, though, that all this only happens after our worker process has fetched all the data. Right now, we haven't even pointed it in the right direction. We do that next, by telling it to 'GET' from the url variable that we just created. Then, we send it off to do its thing, while we move on to the next link. Now let's see what it actually does with that data.

        
      function populateBlogPost(link, linkData, url, index) {
        let blogPost = document.createElement("div");
        blogPost.setAttribute("tabindex", "0");
        blogPost.addEventListener('click', function() {
          window.location.href = url;
        });
        blogPost.classList.add("blog-post");
        if (index == 0) blogPost.classList.add("new");

        if (!(linkData["image"].trim() === "")) {
          let blogImg = document.createElement("img");
          blogImg.setAttribute("src", linkData["image"]);
          blogPost.appendChild(blogImg);
        }

        let blogTitle = document.createElement("h4");
        blogTitle.append(document.createTextNode(linkData["title"]));
        blogPost.appendChild(blogTitle);

        let blogLede = document.createElement("p");
        blogLede.append(document.createTextNode(linkData["lede"]));
        blogPost.appendChild(blogLede);

        refreshColumns();
        columns[shortestColumn()].append(blogPost);
      }

This is the final step in creating the blog page, and while it looks dense, it's fairly straightforward. First, we create a new div element to hold our post. We make sure that it's focusable (for accessibility, since it is an interactive element), and then we make sure that clicking it takes the user to the correct post. Then, we give it the blog-post class (for CSS purposes), and finally, we check to see if it's the very first post. If it is, then we add a little badge in the top right that lets the user know that it's a new post.

After that, we check to see if the post also contains an image. If it does, which is probably the case, we add an img element to the div from earlier, and set its src to be whatever is defined in the post. We do the same thing for both the title and the lede, setting their text to be whatever is defined in the post that they reference.

Finally, with all the work out of the way, we find the shortest column (by looping through them and comparing their heights), and append the post to the shortest one. That way, the columns stay around the same height, even if each post is different.

That just about wraps it up. There are definitely other things I'd like to add to this system, perhaps to make it load more posts as you scroll down, but given that I only have the one right now, I think it's safe to put that on the backburner. Another idea is to use the tagging system to filter through all my posts. In any case, what we've ended up with is a simple dynamic page where each post is loaded asynchronously, and cached too. Not a bad effort! That's all from me, so I'll see you next time.

Subscribe to my mailing list!

Hey there! Subscribe to my mailing list to get monthly updates on my most useful posts, and any special announcements I have. No spam, ever — promise. All fields are required.
Recommended for you

Low risk, high reward

An intro to site reliability engineering

CPR for your app: some tricks to try

What to do when your app just isn't running.

How to store data with IndexedDB

It's well supported, allows you to store large files, and isn't even that bad to work with.

Real-life examples of JavaScript's filter function

The third and final part of a series on JavaScript's array functions.

Comments

Write a comment!

All comments are moderated, and will only be published if they're constructive and add to the discussion. Thanks in advance! All fields are required.

copy