31

I export org-mode files quite often, and almost all of them have code in them. When I do export code, it ends up coloring the text depending on my theme, however, I switch between a dark theme and a light theme regularly. In the case of the light theme, the <code> blocks need to have a light background, and for a dark theme they need to have a dark background (otherwise I end up with light yellow text on a greyish background and it's unreadable).

I have to add this line for dark backgrounds:

#+HTML_HEAD: <style>pre.src {background-color: #303030; color: #e5e5e5;}</style>

And then remember to remove it any time I switch to a light colored background

Is there a way I can automatically detect the background color of the current theme at export time and use it in the exported HTML's CSS?

EDIT

I'm going with Jordon's answer (thanks Jordon, you get the karma points!), however I wanted to post the solution I ended up adding to my code, since it was a slightly modified version of his answer:

(defun my/org-inline-css-hook (exporter)
  "Insert custom inline css to automatically set the
background of code to whatever theme I'm using's background"
  (when (eq exporter 'html)
    (let* ((my-pre-bg (face-background 'default))
           (my-pre-fg (face-foreground 'default)))
      (setq
       org-html-head-extra
       (concat
        org-html-head-extra
        (format "<style type=\"text/css\">\n pre.src {background-color: %s; color: %s;}</style>\n"
                my-pre-bg my-pre-fg))))))

(add-hook 'org-export-before-processing-hook 'my/org-inline-css-hook)

This sets not only the background color, but also the foreground color. It also appends the line to the existing org-html-head-extra setting so other HTML isn't overwritten accidentally. I've tested and this works great for me!

5
  • 1
    I'm sure there's a way, but wouldn't it be better instead to always enforce the same theme when exporting? Or do you intentionally export with different themes?
    – Malabarba
    Nov 11, 2014 at 13:11
  • @Malabarba the intent is to be able to export which whichever theme I am currently using and have the code be readable. Since many themes do not cleanly switch (even with disable-theme), I do not want to have to restart Emacs with a separate theme just to export HTML, which I do many times a day.
    – Lee H
    Nov 11, 2014 at 13:27
  • 1
    If I understand correctly, your current setup already uses the theme's colors on the code blocks, and the problem you're having is that the theme's background is not used. If I got it wrong, please feel free to rollback the edit I made to your title.
    – Malabarba
    Nov 13, 2014 at 12:28
  • @Malabarba my current setup does not specify the background color of code blocks (though I can hard-code a background color in the css if that would help). I would like the background color of the theme to be used for the org-mode code blocks. The new title works for me.
    – Lee H
    Nov 13, 2014 at 13:24
  • There are two problems with the above solution. First, colors like 'gray80' won't get translated correctly to CSS values, and won't get set. Secondly, every time the export runs, the org-html-head-extra gets appended to, leading to unbounded growth, though functionality of the style won't be impaired. Nov 8, 2015 at 0:39

1 Answer 1

16
+50

First, I believe org can use htmlize to automatically color your source code blocks according to your theme.

Alternatively.

Check out http://definitelyaplug.b0.cx/post/custom-inlined-css-in-org-mode-html-export/. It has a great example of how to use the org-export-before-processing-hook to throw custom css onto an org document before an html export.

Here's the code in case the site goes down:

Here on an html export, org will look for a file called styles.css in the current directory or a default file in the .emacs.d directory and inject that css into the document. This is nice but not perfect for your use case.

(defun my-org-inline-css-hook (exporter)
  "Insert custom inline css"
  (when (eq exporter 'html)
    (let* ((dir (ignore-errors (file-name-directory (buffer-file-name))))
           (path (concat dir "style.css"))
           (homestyle (or (null dir) (null (file-exists-p path))))
           (final (if homestyle "~/.emacs.d/org-style.css" path)))
      (setq org-html-head-include-default-style nil)
      (setq org-html-head (concat
                           "<style type=\"text/css\">\n"
                           "<!--/*--><![CDATA[/*><!--*/\n"
                           (with-temp-buffer
                             (insert-file-contents final)
                             (buffer-string))
                           "/*]]>*/-->\n"
                           "</style>\n")))))

(add-hook 'org-export-before-processing-hook 'my-org-inline-css-hook)

You can customize this in a few ways to make it work how you'd like.

One way would be to manually build the css based on your theme and insert that.

Here is a modified version that sets the background of pre.src to the hex value of the default faces :background property.

(defun my-org-inline-css-hook (exporter)
  "Insert custom inline css"
  (when (eq exporter 'html)
    (let ((my-pre-bg (face-background 'default)))
      (setq org-html-head-include-default-style nil)
      (setq org-html-head
            (format "<style type=\"text/css\">\n pre.src { background-color: %s;}</style>\n" my-pre-bg)))))

(add-hook 'org-export-before-processing-hook 'my-org-inline-css-hook)
1
  • 1
    Thanks Jordon, this is great! I've update my original question with my slightly edited version, but you get the bounty and solution!
    – Lee H
    Nov 14, 2014 at 10:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.