UP | HOME

Literate CSS

One of the benefits of writing my blog in Org-Mode in Emacs, is that my blog posts are a functional literate programming environment. Which is pretty handy for keeping track of things like "how does my CSS work", for example.

Well, in general Org-Mode injects a basic set of CSS into web pages as it exports them, but I'm planning to amend that slightly as I go forward. Meaning this blog post will be a bit of a living document, evolving over time. Hi, future me! Hope you like it.

Let's start with some basic legibility enhancements. Margin around the edges of the page, maximum width for huge monitors, slightly gray text to avoid excessive eye strain. (Note to future me: probably swap this to slightly off-white background and black text instead, which I find less of a punch in the face…)

body {
  margin: 40px max;
  auto-width: 900px;
  line-height: 1.6;
  font-size: 16px;
  color: #222;
  padding: 0 10px;
  font-family: sans-serif;
}

Little bit more white space around titles, and a touch of colour.

h1,
h2 {
   line-height: 1.2;
   font-family: sans-serif;
   color: #859900;
   text-decoration: underline;
}
h3 {
  line-height: 1.2;
  font-family: sans-serif;
  color: #859900;
}

And make sure that images are a decent size. I might drop this rule in the future; I'm not sure how universal it really is.

img {
  width: 750px;
  border-radius: 10px;
}

Make code monospace, set up default background/foreground colours distinct from the main text:

pre.src {
  font-family: monospace;
  background: #f6f7f8;
  color: #555;
  overflow-x: auto;
  word-wrap: normal;
  white-space: pre;
  position: relative;
  overflow-x: auto;
  overflow-y: visible;
  padding-top: 1.2em;
}
code {
  color: #555;
  background: #f6f7f8;
  font-family: monospace;
  padding: 0px 5px 0px 5px;
}

And start colouring the code. There's a slightly interesting quirk here as each language can define its own custom token types as well as the more general shared set

 /* Based on the mccarthy theme:
    https://github.com/owainlewis/emacs-color-themes/blob/master/themes/mccarthy-theme.el
*/
.org-keyword { color: #3b5998; }
.org-constant { color: #008080; }
.org-string { color: #e9c; }
.org-number { color: #5b93fc; }
.org-type { color: #d14; }
.org-function-name { color: #1b1e2b; }
.org-variable-name { color: #d14; }
.org-comment { color: #2c5115; }
.org-comment-delimiter { color: #2c5115; }
.org-rainbow-delimiters-depth-1 { color: #2c3140; }
.org-rainbow-delimiters-depth-2 { color: #2c3140; }
.org-rainbow-delimiters-depth-3 { color: #2c3140; }
.org-rainbow-delimiters-depth-4 { color: #2c3140; }
.org-rainbow-delimiters-depth-5 { color: #2c3140; }
.org-rainbow-delimiters-depth-6 { color: #2c3140; }
.org-rainbow-delimiters-depth-7 { color: #2c3140; }
.org-rainbow-delimiters-depth-8 { color: #2c3140; }
.org-rainbow-delimiters-depth-9 { color: #2c3140; }

.org-typescript-access-modifier { color: #3b5998; }
.org-typescript-primitive { color: #2c3140; }

Everything below this point is modified from the default org style sheet, that normally gets embedded into every page. I'm going to separate it out here so that I can start hacking on it, and then set the export not to inject it every time.

.title  { text-align: center;
           margin-bottom: .2em; }
.subtitle { text-align: center;
            font-size: medium;
            font-weight: bold;
            margin-top:0; }
.todo   { font-family: monospace; color: red; }
.done   { font-family: monospace; color: green; }
.priority { font-family: monospace; color: orange; }
.tag    { background-color: #eee; font-family: monospace;
          padding: 2px; font-size: 80%; font-weight: normal; }
.timestamp { color: #bebebe; }
.timestamp-kwd { color: #5f9ea0; }
.org-right  { margin-left: auto; margin-right: 0px;  text-align: right; }
.org-left   { margin-left: 0px;  margin-right: auto; text-align: left; }
.org-center { margin-left: auto; margin-right: auto; text-align: center; }
.underline { text-decoration: underline; }
#postamble p, #preamble p { font-size: 90%; margin: .2em; }
p.verse { margin-left: 3%; }
pre {
  border: 1px solid #ccc;
  box-shadow: 3px 3px 3px #eee;
  padding: 8pt;
  font-family: monospace;
  overflow: auto;
  margin: 1.2em;
}
pre.src:before {
  display: none;
  position: absolute;
  background-color: white;
  top: 10px;
  right: 10px;
  padding: 3px;
  border: 1px solid black;
}
pre.src:hover:before { display: inline;}
/* Languages per Org manual */
pre.src-asymptote:before { content: 'Asymptote'; }
pre.src-awk:before { content: 'Awk'; }
pre.src-C:before { content: 'C'; }
/* pre.src-C++ doesn't work in CSS */
pre.src-clojure:before { content: 'Clojure'; }
pre.src-css:before { content: 'CSS'; }
pre.src-D:before { content: 'D'; }
pre.src-ditaa:before { content: 'ditaa'; }
pre.src-dot:before { content: 'Graphviz'; }
pre.src-calc:before { content: 'Emacs Calc'; }
pre.src-emacs-lisp:before { content: 'Emacs Lisp'; }
pre.src-fortran:before { content: 'Fortran'; }
pre.src-gnuplot:before { content: 'gnuplot'; }
pre.src-haskell:before { content: 'Haskell'; }
pre.src-hledger:before { content: 'hledger'; }
pre.src-java:before { content: 'Java'; }
pre.src-js:before { content: 'Javascript'; }
pre.src-latex:before { content: 'LaTeX'; }
pre.src-ledger:before { content: 'Ledger'; }
pre.src-lisp:before { content: 'Lisp'; }
pre.src-lilypond:before { content: 'Lilypond'; }
pre.src-lua:before { content: 'Lua'; }
pre.src-matlab:before { content: 'MATLAB'; }
pre.src-mscgen:before { content: 'Mscgen'; }
pre.src-ocaml:before { content: 'Objective Caml'; }
pre.src-octave:before { content: 'Octave'; }
pre.src-org:before { content: 'Org mode'; }
pre.src-oz:before { content: 'OZ'; }
pre.src-plantuml:before { content: 'Plantuml'; }
pre.src-processing:before { content: 'Processing.js'; }
pre.src-python:before { content: 'Python'; }
pre.src-R:before { content: 'R'; }
pre.src-ruby:before { content: 'Ruby'; }
pre.src-sass:before { content: 'Sass'; }
pre.src-scheme:before { content: 'Scheme'; }
pre.src-screen:before { content: 'Gnu Screen'; }
pre.src-sed:before { content: 'Sed'; }
pre.src-sh:before { content: 'shell'; }
pre.src-sql:before { content: 'SQL'; }
pre.src-sqlite:before { content: 'SQLite'; }
/* additional languages in org.el's org-babel-load-languages alist */
pre.src-forth:before { content: 'Forth'; }
pre.src-io:before { content: 'IO'; }
pre.src-J:before { content: 'J'; }
pre.src-makefile:before { content: 'Makefile'; }
pre.src-maxima:before { content: 'Maxima'; }
pre.src-perl:before { content: 'Perl'; }
pre.src-picolisp:before { content: 'Pico Lisp'; }
pre.src-scala:before { content: 'Scala'; }
pre.src-shell:before { content: 'Shell Script'; }
pre.src-ebnf2ps:before { content: 'ebfn2ps'; }
/* additional language identifiers per "defun org-babel-execute"
     in ob-*.el */
pre.src-cpp:before  { content: 'C++'; }
pre.src-abc:before  { content: 'ABC'; }
pre.src-coq:before  { content: 'Coq'; }
pre.src-groovy:before  { content: 'Groovy'; }
/* additional language identifiers from org-babel-shell-names in
   ob-shell.el: ob-shell is the only babel language using a lambda to put
   the execution function name together. */
pre.src-bash:before  { content: 'bash'; }
pre.src-csh:before  { content: 'csh'; }
pre.src-ash:before  { content: 'ash'; }
pre.src-dash:before  { content: 'dash'; }
pre.src-ksh:before  { content: 'ksh'; }
pre.src-mksh:before  { content: 'mksh'; }
pre.src-posh:before  { content: 'posh'; }
/* Additional Emacs modes also supported by the LaTeX listings package */
pre.src-ada:before { content: 'Ada'; }
pre.src-asm:before { content: 'Assembler'; }
pre.src-caml:before { content: 'Caml'; }
pre.src-delphi:before { content: 'Delphi'; }
pre.src-html:before { content: 'HTML'; }
pre.src-idl:before { content: 'IDL'; }
pre.src-mercury:before { content: 'Mercury'; }
pre.src-metapost:before { content: 'MetaPost'; }
pre.src-modula-2:before { content: 'Modula-2'; }
pre.src-pascal:before { content: 'Pascal'; }
pre.src-ps:before { content: 'PostScript'; }
pre.src-prolog:before { content: 'Prolog'; }
pre.src-simula:before { content: 'Simula'; }
pre.src-tcl:before { content: 'tcl'; }
pre.src-tex:before { content: 'TeX'; }
pre.src-plain-tex:before { content: 'Plain TeX'; }
pre.src-verilog:before { content: 'Verilog'; }
pre.src-vhdl:before { content: 'VHDL'; }
pre.src-xml:before { content: 'XML'; }
pre.src-nxml:before { content: 'XML'; }
/* add a generic configuration mode; LaTeX export needs an additional
   (add-to-list 'org-latex-listings-langs '(conf " ")) in .emacs */
pre.src-conf:before { content: 'Configuration File'; }

/* added manually after generation */
pre.src-typescript:before { content: 'TypeScript'; }
pre.src-fsharp:before { content: 'F#'; }

table { border-collapse:collapse; }
caption.t-above { caption-side: top; }
caption.t-bottom { caption-side: bottom; }
td, th { vertical-align:top;  }
th.org-right  { text-align: center;  }
th.org-left   { text-align: center;   }
th.org-center { text-align: center; }
td.org-right  { text-align: right;  }
td.org-left   { text-align: left;   }
td.org-center { text-align: center; }
dt { font-weight: bold; }
.footpara { display: inline; }
.footdef  { margin-bottom: 1em; }
.figure { padding: 1em; }
.figure p { text-align: center; }
.equation-container {
  display: table;
  text-align: center;
  width: 100%;
}
.equation {
  vertical-align: middle;
}
.equation-label {
  display: table-cell;
  text-align: right;
  vertical-align: middle;
}
.inlinetask {
  padding: 10px;
  border: 2px solid gray;
  margin: 10px;
  background: #ffffcc;
}
#org-div-home-and-up
 { text-align: right; font-size: 70%; white-space: nowrap; }
textarea { overflow-x: auto; }
.linenr { font-size: smaller }
.code-highlighted { background-color: #ffff00; }
.org-info-js_info-navigation { border-style: none; }
#org-info-js_console-label
  { font-size: 10px; font-weight: bold; white-space: nowrap; }
.org-info-js_search-highlight
  { background-color: #ffff00; color: #000000; font-weight: bold; }
.org-svg { width: 90%; }