RSS | Source | License

Blog with only Org Mode

Table of Contents

Nowadays you can choose from a handful of static blog frameworks, like hexo, pelican, etc. Most of them support Markdown, and you can use Org Mode along with them by exporting Org file to Markdown file. Some framework even has deeper integration. For example the package ox-hugo provides a dozen advanced export options and well intergrated hugo and Org Mode options/properties.

Using frameworks has some advantages and some disadvantages. On the one side, you get pretty themes, animation, dynamic(automatic) content generation, automatic publication, etc. On the other side, your cost is: learn a framework, choose from a limited selection of themes or make your own, etc.

For me, I don't need animation or pre-made themes. my blog contains few duplicated parts that need automation, and I can just write some quick snippet to handle that. Publication isn't a problem either because I host my blog in GitHub Pages. All I need is a trivial alias that commits everything and push them.

And the cost of a framework is just Too Much TroubleĀ® for me. I tried pelican and hugo and never liked them.

Turns out that, Org Mode already provides me with everything I need. The html export options in Org Mode helps build my blog with trivial effort. Plus, when building blog with plain HTML, JavaScript, CSS and Org Mode I have so much more control and flexibility. CSS is much easier because your are writing it directly to HTML, instead of some fancy tags that you don't know who defined. The blog your are currently reading from is built without any framework and looks pretty complete to me.

Below is how do I build my blog.

1 Organization

All my blog posts are under https://archive.casouri.co.uk/note/

|-- 2018
|   |-- bindings-in-web-page
|   |   `-- index.org
|   |-- blog-with-only-org-mode
|   |   `-- index.org
|   |-- fancy-startup-screen-for-emacs
|   |   |-- home.png
|   |   |-- index.html
|   |   |-- index.org
|   |   |-- moon.gif
|   |   `-- moon.png
|   `-- note-about-domain-and-dns
|       |-- index.html
|       `-- index.org
|-- index.html
|-- index.org
`-- style.css

5 directories, 12 files

Each sub directory is a year, and sub directories of that are individual posts. The index.org and (exported) index.html are the actual content. Other static contents of a page like images are under the same directory. Whenever I update an Org file, I re-export it by C-c C-e h h. Then commit both files. (I could have write a org publish pipeline but too lazy to do so, Magit is just too easy to use.)

Under the root directory (/note/), I have a style sheet, a index.org and a index.html in root directory. index.org and (exported) index.html is my home page. Every page under /note/ links to style.css.


2.1 Including Custom Style Sheet

Including style sheet(s) is quite easy. In each Org file that you want to link the style sheet, insert #+HTML_HEAD: or #+HTML_HEAD_EXTRA:.

Here is what I have in my Org file:

#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="/note/style.css"/>
#+HTML_HEAD_EXTRA: <script type="text/javascript" src="/note/script.js"></script>

The first line includes the global style sheet I use for pages across my whole personal web site. The second line includes the scripting file which I will talk about later.

Inside my local /note/style.css I have this snippet to import my global style sheet:

@import url("/style.css");

For all the classes Org Mode uses when exporting to HTML, you can find them here. However, that isn't the ultra complete list, the best way is probably look at the exported HTML file.

You can open the exported html file in your favorite browser and play with CSS by developer tool.

2.2 Disable Default Styling

To turn off the default CSS styling, insert #+OPTIONS: html-style:nil.

2.3 Floating TOC by CSS

Put this into your custom css file and you can get a floating TOC on the right of the screen. I use media rule so TOC only floats on desktop.

@media screen and (min-width: 800px) {
    #table-of-contents  {
        position: fixed;
        top: 5%;
        right: 2%;

2.4 Image Size

Because I use a MacBook, my screen shots and photos are usually enormous. It is great viewing them locally, but not so great when I put them on to the Web.

To fix those ridiculously large images, I set this rule in my CSS:

img {
    max-width: 400px;

and assign custom size with #+ATTR_HTML: :width 100px for individual images.

3 Add UP and HOME link

If you add these options, the exported HTML page will contain the hyperlink to upper level and home page on the top of the exported web page.

I linked both UP and HOME to my home page because there isn't any other layer between each post and home page.

#+HTML_LINK_UP: /note

4 TODO RSS feeds

A blog without RSS feeds isn't complete. But Org Mode didn't have a very good way to generate RSS feeds.


5 TODO Bind Emacs style shortcuts

6 Links

Links work just like paths: / is the root URL, for me it is arhive.casouri.co.uk; relative links like ./ and ../ works just like you would expected. Since my source files (Org files) and ouput files (HTML files) are under the same directory, I don't need to worry about path differences.

Internal links works without any problem either. This internal link to the next heding works in both Org file and the exported webpage.

Internal links are inserted just like external links: hit C-c C-l, and insert the heading or tag you want to link to, RET, insert the display name you want it to have (leave blank if you want none.)

Manual for external links and internal links

7 Meta data like date and title

You probably already know these stuff:


BTW, you can insert a time stamp by C-c .

Check out the complete list. You can use C-c C-e # to insert template with export options.

8 Further reading

Checkout the manual.

Written by Yuan Fu <casouri@gmail.com>

First Published on 2018-09-11 Tue 00:00

Last modified on 2018-11-11 Sun 19:19