HPSTR, a Jekyll theme

They say three times the charm, so here is another free Jekyll blog theme for you. I’ve learned a ton since open sourcing my first two themes on Github, and wanted to try a few new things this time around. If you’ve used my previous themes most of this should be familiar territory…


Screenshot of HPSTR Theme

Setup guide Live preview

What’s different with this Jekyll theme?

This time around I wanted to see how much of the “branding”1 I could remove and deemphasize to make the content sing in contrast. The primary way I went about doing this was by down playing anything that wasn’t part of a post or page’s content. Collapsing the blog’s navigation behind a drop down was one way I slimmed the header, to get at the content quicker.

On desktops and tablets (horizontal orientation) the menu is placed in the top left corner with position: fixed2 to remain in view as the page is scrolled. Mild CSS3 animations and transforms were utilized to progressively enhance the drop down menu for browsers that support these properties, and gracefully degrades on those that do not. The menu is also completely usable when JavaScript is disabled.

Everything that isn’t #main I view as support content— living one step down from a post or page in the overall hierarchy. In the case of author bylines, post dates, and social sharing links, I used a light gray color to push these elements back, and pull the main content forward. Related posts and comments are sectioned off just enough from the main to keep them connected but visually separated.

Grunt build script for development

Up until this point I’ve mostly used tools like CodeKit and Prepros to compile my LESS stylesheets and concatenate scripts. Flirting with Grunt on a few personal projects, I wanted to integrate it into this theme as a build tool for messing with the theme’s stylesheets.

For those who are unfamiliar with Grunt I encourage you to check out the getting started guide. Basically how this works is, you install Node.js, install Grunt and dependencies by running npm install, and then run various Grunt tasks defined in the project’s Gruntfile.js file.

Currently there are two Grunt tasks: one to build and optimize and the other to watch for changes to any LESS and JavaScript files. For now you need to run grunt to rebuild the CSS, concatenate JavaScript files, and optimize .jpg, .png, and .svg files in the images/ folder. And then run jekyll build to pull these changes in when developing locally.

There are some Jekyll Grunt plugins to help make things work more seamless, but I avoided them to keep the theme compatible with GitHub Pages. While not a perfect solution you can run grunt watch in combination with jekyll build --watch to watch for LESS and JS file updates to be processed by Grunt and auto-generated by Jekyll.


Grunt is no longer needed to build main.css. I’ve ported all of the Less stylesheets over to Sass to utilize Jekyll’s built-in support for preprocessing .scss files. Updating most colors and fonts is as easy as changing a few values in _sass/_variables.scss and running jekyll build (or deploying to GitHub if you host there).

Instead of using bulky JavaScript widgets provided by Facebook, Twitter, and Google I went with lightweight share links. Social sharing links are enabled by default on all posts and pages. To disable add share: false to the post’s YAML Front Matter.

social share button screenshot
How social sharing buttons look in HPSTR


Having a problem getting something to work or want to know why I setup something in a certain way? File a GitHub issue.


This theme is free and open source software, distributed under the MIT License. So feel free to modify it however you’d like without linking back to me or including a disclaimer.

  1. To me a blog’s masthead, logo, title, headline, and navigation are branding elements that can reinforce or distract from a central theme or feeling. I suppose downplaying or removing these elements could be see as a way of branding too… but that’s a discussion for another day. 

  2. On mobile I choose to remove the fixed positioning to keep the menu from interfering with the main content. 

Enjoyed this content?

Help keep it free by sending a donation or purchasing something from my Amazon Wish List. You can also subscribe to various site feeds to get notified of new posts or follow me on social media.


Felipe Oliveira on

Just for curiosity, what grid system you use in themes?

At one point I was using The Semantic Grid System, but gave up on it. Instead I took the easy way out and give all the content a 100% width for < 768px breakpoints, and everything else gets a max-width of around 900px.

Preboot’s grid system also appealed to me because I use LESS for my stylesheets.

Singularity looks quite nice too, but I’m not a Sass man so I haven’t given it a go yet.

I just pushed the whole branch to master and I found it’s not working. My CSS has screwed up as well. Tried jekyll serve in localhost but that’s also not working!

Did you set url: properly in _config.yml?

If it’s not set to your domain when pushing live or left blank (or http://localhost:4000) then the CSS/JS won’t load because they rely on absolute paths in my theme.

If it is set properly and still not working, link me to your repo and I’ll take a look.

Thank you. It’s working fine now. Btw, don’t you support Github flavored Markdown?

Jekyll supports whatever flavor of Markdown you want. I prefer Kramdown and that’s what the theme comes with by default. But you can switch it out easily. See jekyllrb.com for details on all that.

This theme looks great! I just migrated my gh pages site from so simple to hpstr. Good work!

How can a non-techie install on a WordPress blog? I am used to tweaking things in the WordPress admin panel, but am not familiar with Jekyll or coding.

Perhaps most of your audience is more tech savvy, but you attract general artists too I’m sure. Are you going to start a theme biz? I love your design, and even if I do not know how to install your themes, they are simple and beautiful, what I look to use. Enjoy your art and blog much.

Thanks Kat. This theme is only for Jekyll, I haven’t ported it over to WordPress. You’re right, Jekyll is a lot to take in.

Have no plans for starting a theme biz, I’m just doing this for fun and sharing what I’ve come up with by playing around with my own personal site. There are so many good Wordpress themes out there I don’t think I would be able to keep up with the competition.

With Jekyll there is barely any themes out there, so the expectations are much much lower. ;-)

prometheus2305 on

This is a really fantastic theme I am trying to use and works great when I serve it through localhost but for reason is not working when I upload my _site folder to s3? Any idea why that might be?

“Not working” is fairly vague so I’m just taking a stab here that your styles and such aren’t loading properly. The number one culprit for that is due to not setting site.url properly in _config.yml

When serving locally it needs to be either left blank or set to your localhost server (eg. http://localhost:4000). When uploading to your web server it needs match the domain you’re serving from or else you’ll experience broken links galore.

prometheus2305 on

Absolutely correct. Sorry about being vague but you understood exactly the issue. I had to remove the url from the _config.yml file all together and just use the config in s3_website.yml and it did the trick. Still learning how all of this works. Thank you again for the response and for creating one of the best themes I’ve seen.

Mitch Pronschinske on

Amazing theme. I am constantly in awe that this is how my blog looks.

One question: a problem I haven’t been able to solve…

I’ve tried modifying the pygments.less .font(15); section to make the code snippet text bigger and I’ve tried to make the entire blog’s body font bigger in variables.less @doc-font-size: 18;

I’m on Windows and node and grunt are installed properly. I ran npm install in the theme folder and then I tried modifying the fonts in those less files a couple times and then running grunt. I the min.css is recreated and I think it all runs properly except for the image minifier.

Running "recess:dist" (recess) task
File "assets/css/main.min.css" created.
Original: 68310 bytes.
Minified: 53648 bytes.
Running "uglify:dist" (uglify) task
File "assets/js/scripts.min.js" created.
Running "imagemin:dist" (imagemin) task
Fatal error: spawn ENOENT

But the fonts never change their size when I look at the blog after doing this and I also inspected the text to confirm that the fonts didn’t change. Am I missing something?

Thanks man!

Changing the the font-size on the .highlight class in pygments.less should have worked but I just noticed that I put a font-size on the pre element, and because of how the cascade works that size is overriding the one you set on .highlight.

If you edit the pre element’s font-size in typography.less on line 132 you should be all set.

I bounce back between Windows and Mac OS X and noticed the same error when I was running grunt on a Windows 7 setup. If I remember correctly when you run npm install from the CLI a few dependencies for grunt-contrib-imagemin don’t install properly and that’s what the ENOENT error is referring to.

I think the fix was to add a line to the package.json file to install an older jpegtran-bin dependency that will actually compile on a Windows 7 machine. If you add

"jpegtran-bin": "0.2.0" to devDependencies in package.json and then run npm install see if everything installs properly for grunt-contrib-imagemin and then try running grunt again. You might have to dump your node_modules folder first before running npm install, I’m not sure.

If imagemin still doesn’t work you could always use grunt-imgcompress instead and modify the grunt tasks or just remove it all together. That’s what I’m using on this site (see my Made Mistakes repo to lift the grunt tasks).

Let me know how it goes and if you hit any other hiccups.

Mitch Pronschinske on

I got the changes in pygments.less fonts to start working. I’m not sure the modifications to variables.less for the body font (@doc-font-size: ) are working. Here’s my blog with your theme :)

The new line in the package.json file didn’t let the npm install run properly (I also tried adding grunt- to the front of it to match the others items). How do you ‘dump’ the node_modules folder? Delete everything in it and paste in the folder from the original repo?

What files would I need to take from the Made Mistakes repo to be able to use grunt-imgcompress?

There are a few spots where I didn’t declare font-sizes on elements and just let them use browser defaults, so that could be why you’re not seeing any size changes. Just inspect the elements you want to alter in web dev tools and then apply an appropriate font-size in the .less files

To make the change to grunt-imgcompress I basically swapped out any reference to imagemin with it. Here’s a gist that you can grab the modified package.json and Gruntfile.js files. After you copy those into your repo just delete the node_modules folder and then run npm install. It’ll download and install everything it needs and rebuild the modules.

That should hopefully clear everything up for you. I’m still new to Node and Grunt myself, so I’m by no means a pro.

Mitch Pronschinske on

Nice. The grunt command runs without errors now. Still can’t figure out how to change the body font size though. And somehow I made the menu text smaller, which is not what I want. Any clue what I could have done? repo

That’s good to hear. I think I mentioned it before but I didn’t declare font sizes on all the text elements, so that could be why changing the doc-font-size variable has no effect. To change the entry content size look play around with the font-size set on .entry-content. Anywhere else you might have to add a font-size declaration to the element to override any browser defaults I didn’t clear out in the CSS reset.

Hi! Just want to say that the theme looks great! I would really like to use it for a site I’m making. However, I’m running into some trouble with linking back to home page. I’m currently leaving the url field in _config.yml blank because I’m using Github Pages to host but I am unable to link back to the Home page from some of the other pages. Should I set the url field to the url of the github page?

Yup. Set the domain to whatever your GH one is and those home links should work. Make sure you set it back to blank or http://localhost:4000 when working locally or all your links will be goofed.

nwatkins on

I’d like to have the main page load with the navigation menu open, but closed on other pages. Would this be possible to hack up?

I’m sure it’s possible but you’ll have to hack up the CSS and JS a bit to do it. I’d start with finding a way you’re happy with applying a id or class to the body tag… on just the homepage. That will give you a hook to style the menu differently on just that page and hopefully allow you to keep it open there and revert to the close position on every other page.

Hi, I’ve forked hpstr and I’m working to make it RTL’ed! I’ve made some changes in /hpstr-jekyll-theme/tree/master/assets/css, but they are not affected on my site while any change in _config.yml is effected.

Did you edit main.min.css or main.css? The theme uses the minified version so if you only made changes to main.css that’s why they’re not showing up.

Oops, Now it’s working by editing main.min.css. thanks.

Another question: How to exchange > with < that is shown under menu (Notice to About)?

For people: these are some code that I have added them to main.min.css to make RTL this awesome template: http://paste.ubuntu.com/8217972/

Those characters are added using :after pseudo classes on the list items in the menu. It’s easier to follow what’s going on in the source less file so I’d suggest making your edits there and compiling it into main.min.css or I suppose you could just work with the minified .css directly.

Basically I’m using the Font Awesome webfont on those elements and inserting a Font Awesome icon using CSS content declarations. Look around line 101.

To swap the icon you’ll need to find the one you want and use the corresponding Unicode. For example, to flip > to < you’d change \f105 to \f104.

Hope this helps.

Great; I did it via main.min.css simply by changing 105 to 104 :)

my last questions: 2011-03-10-sample-post.md –> SAMPLE POST WAS PUBLISHED ON MARCH 10, 2011 (REVISED: 05/31/2013) MICHAEL ROSE –> It’s working with Gregorian calendar, while native date, here, is Hegirae! (Also copyright date at footer)

You need to modify the theme’s layouts. If you look for occurrences of {{ <a href="http://page.date">page.date</a> }} and {{ <a href="http://post.date">post.date</a> }} in the various _layouts they have Liquid filters applied to convert the date into different formats.

Here’s a good blog post showing how they work and a bunch of examples.

how modify highlight font?

By editing the site’s CSS. The main stylesheet is broken up into various Sass partials. I’d start with _variables.scss since that defines most of the themes colors and fonts.

Anything else and you’ll have to poke around the other partials

Thanks, I modified the main.min.css

Tim Erwin on

I love the menu on this theme and I’m using it as inspiration for one I’m doing. excellent work! one issue I noticed is that you mentioned the menu is totally usable when javascript is disabled, so I tried it and the menu completely disappeared? I’m using latest chrome on mac.

Looks like you found a bug in the CSS. When I converted the menu styles into Sass partials I must have left out a few declarations that used to display the menu expanded when JS is disabled. I just pushed a quick fix to GitHub.

JohnWatsonDev on

Dear Michael Rose~

Thx for the post. I’m an android developer without any web skill, I want use this theme.

Thx in advance~

Check out the theme’s documentation on GitHub. I explain all the features and how to set it up with Jekyll.

Jian Jin on

Thank you for this awesome template! I love it! May I connect with you on LinkedIn?

Comments are closed

If you have a question concerning the content of this page, please feel free to contact me.