diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,32 @@
 # Revision history for skylighting
 
+## 0.5 -- 2017-12-10
+
+  * Fix line spacing and overflowing content in generated HTML
+    (David Baynard, #25, see jgm/pandoc#4128).
+
+    + Fix empty line height, explicitly
+    + Ensure long lines scroll on screen
+    + Only apply colour to the outer div
+    + Don't reset line number colour
+    + Fix borders on empty code lines
+    + Collapse divs correctly.
+
+  * Changes to Style types and JSON instances.  Previously we could not
+    successfully round-trip through JSON.
+
+    + `tokenStyles` is now a map rather than an association list.
+    + We now use `line-number-color` instead of `line-numbers` at
+      the top level in the JSON instances, falling back to
+      `line-numbers` in `editor-colors`, for KDE theme compatibility.
+    + We use `line-number-background-color` at the top level, falling
+      back to the text background color.
+    + We use `text-color` at the top level, falling back to the `text-color`
+      of the `Normal` token style if it exists, for KDE compatibility.
+    + We use `background-color` at the top level, falling back to
+      the `background-color` in `editor-colors`, for KDE compatibility.
+    + A round-trip JSON test has been added.
+
 ## 0.4.4.1 -- 2017-11-27
 
   * HTML formatting: fix color, bgcolor when numbering enabled.
diff --git a/skylighting.cabal b/skylighting.cabal
--- a/skylighting.cabal
+++ b/skylighting.cabal
@@ -1,5 +1,5 @@
 name:                skylighting
-version:             0.4.4.1
+version:             0.5
 synopsis:            syntax highlighting library
 description:         Skylighting is a syntax highlighting library with
                      support for over one hundred languages.  It derives
diff --git a/src/Skylighting/Format/HTML.hs b/src/Skylighting/Format/HTML.hs
--- a/src/Skylighting/Format/HTML.hs
+++ b/src/Skylighting/Format/HTML.hs
@@ -4,7 +4,8 @@
     , styleToCss
     ) where
 
-import Data.List (intersperse)
+import Data.List (intersperse, sort)
+import qualified Data.Map as Map
 import Data.Monoid ((<>))
 import Data.String (fromString)
 import qualified Data.Text as Text
@@ -60,6 +61,7 @@
 -- tokens are encoded.
 formatHtmlBlock :: FormatOptions -> [SourceLine] -> Html
 formatHtmlBlock opts ls =
+  H.div ! A.class_ (toValue "sourceCode") $
   H.pre ! A.class_ (toValue $ Text.unwords classes)
         $ wrapCode opts
         $ mconcat . intersperse (toHtml "\n")
@@ -137,16 +139,23 @@
 
 -- | Returns CSS for styling highlighted code according to the given style.
 styleToCss :: Style -> String
-styleToCss f = unlines $ divspec ++ numberspec ++ colorspec ++ linkspec ++ map toCss (tokenStyles f)
-   where colorspec = case (defaultColor f, backgroundColor f) of
-                          (Nothing, Nothing) -> []
-                          (Just c, Nothing)  -> ["pre, code { color: " ++ fromColor c ++ "; }"]
-                          (Nothing, Just c)  -> ["pre, code { background-color: " ++ fromColor c ++ "; }"]
-                          (Just c1, Just c2) -> ["pre, code { color: " ++ fromColor c1 ++ "; background-color: " ++
-                                                  fromColor c2 ++ "; }"]
+styleToCss f = unlines $
+  divspec ++ numberspec ++ colorspec ++ linkspec ++
+    sort (map toCss (Map.toList (tokenStyles f)))
+   where colorspec = [
+           "div.sourceCode\n  { "
+           ++ case (defaultColor f, backgroundColor f) of
+                (Nothing, Nothing) -> ""
+                (Just c, Nothing)  -> "color: " ++ fromColor c ++ ";"
+                (Nothing, Just c)  -> "background-color: " ++ fromColor c ++ ";"
+                (Just c1, Just c2) -> "color: " ++ fromColor c1
+                     ++ "; background-color: " ++ fromColor c2 ++ ";"
+           ++ " }"]
          numberspec = [
             "pre.numberSource a.sourceLine"
           , "  { position: relative; }"
+          , "pre.numberSource a.sourceLine:empty"
+          , "  { position: absolute; }"
           , "pre.numberSource a.sourceLine::before"
           , "  { content: attr(data-line-number);"
           , "    position: absolute; left: -5em; text-align: right; vertical-align: baseline;"
@@ -165,17 +174,23 @@
               " padding-left: 4px; }"
           ]
          divspec = [
-            "a.sourceLine { display: inline-block; min-height: 1.25em; }"
+            "a.sourceLine { display: inline-block; line-height: 1.25; }"
           , "a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }"
-          , ".sourceCode { overflow: visible; }"
-          , "code.sourceCode { white-space: pre; }"
+          , "a.sourceLine:empty { height: 1.2em; position: absolute; }" -- correct empty line height
+          , ".sourceCode { overflow: visible; }" -- needed for line numbers
+          , "code.sourceCode { white-space: pre; position: relative; }" -- position relative needed for absolute contents
+          , "div.sourceCode { margin: 1em 0; }" -- Collapse neighbours correctly
+          , "pre.sourceCode { margin: 0; }" -- Collapse neighbours correctly
+          , "@media screen {"
+          , "div.sourceCode { overflow: auto; }" -- do not overflow on screen
+          , "}"
           , "@media print {"
           , "code.sourceCode { white-space: pre-wrap; }"
           , "a.sourceLine { text-indent: -1em; padding-left: 1em; }"
           , "}"
           ]
          linkspec = [ "@media screen {"
-          , "a.sourceLine::before { text-decoration: underline; color: initial; }"
+          , "a.sourceLine::before { text-decoration: underline; }"
           , "}"
           ]
 
diff --git a/src/Skylighting/Format/LaTeX.hs b/src/Skylighting/Format/LaTeX.hs
--- a/src/Skylighting/Format/LaTeX.hs
+++ b/src/Skylighting/Format/LaTeX.hs
@@ -7,7 +7,9 @@
        ) where
 
 import Control.Monad (mplus)
+import qualified Data.Map as Map
 import Data.Char (isSpace)
+import Data.List (sort)
 import Data.Monoid
 import Data.Text (Text)
 import qualified Data.Text as Text
@@ -100,7 +102,8 @@
                             ,Text.pack
                               (printf "\\definecolor{shadecolor}{RGB}{%d,%d,%d}" r g b)
                             ,"\\newenvironment{Shaded}{\\begin{snugshade}}{\\end{snugshade}}"])
-  ++ map (macrodef (defaultColor f) (tokenStyles f)) (enumFromTo KeywordTok NormalTok)
+  ++ sort (map (macrodef (defaultColor f) (Map.toList (tokenStyles f)))
+            (enumFromTo KeywordTok NormalTok))
 
 macrodef :: Maybe Color -> [(TokenType, TokenStyle)] -> TokenType -> Text
 macrodef defaultcol tokstyles tokt = "\\newcommand{\\"
diff --git a/src/Skylighting/Styles.hs b/src/Skylighting/Styles.hs
--- a/src/Skylighting/Styles.hs
+++ b/src/Skylighting/Styles.hs
@@ -9,6 +9,7 @@
   , monochrome
   , zenburn) where
 
+import qualified Data.Map as Map
 import Data.Aeson (eitherDecode)
 import Data.ByteString.Lazy (ByteString)
 import Skylighting.Types
@@ -23,7 +24,7 @@
 -- | Style based on kate's default colors.
 kate :: Style
 kate = Style{
-      tokenStyles =
+      tokenStyles = Map.fromList
         [ ( KeywordTok, defStyle { tokenColor = Just (RGB 31 28 27), tokenBold = True })
         , ( DataTypeTok, defStyle { tokenColor = Just (RGB 0 87 174) })
         , ( DecValTok, defStyle { tokenColor = Just (RGB 176 128 0) })
@@ -65,7 +66,7 @@
 -- | Style from the breeze-dark KDE syntax highlighting theme.
 breezeDark :: Style
 breezeDark = Style
-    { tokenStyles =
+    { tokenStyles = Map.fromList
         [ ( KeywordTok, defStyle { tokenColor = Just (RGB 207 207 194) })
         , ( DataTypeTok, defStyle { tokenColor = Just (RGB 41 128 185) })
         , ( DecValTok, defStyle { tokenColor = Just (RGB 246 116 0) })
@@ -111,7 +112,7 @@
   , defaultColor = Nothing
   , lineNumberColor = color 0xaaaaaa
   , lineNumberBackgroundColor = Nothing
-  , tokenStyles =
+  , tokenStyles = Map.fromList
     [ (KeywordTok, defStyle{ tokenColor = color 0x007020, tokenBold = True })
     , (DataTypeTok, defStyle{ tokenColor = color 0x902000 })
     , (DecValTok, defStyle{ tokenColor = color 0x40a070 })
@@ -152,7 +153,7 @@
   , defaultColor = Nothing
   , lineNumberColor = color 0xaaaaaa
   , lineNumberBackgroundColor = Nothing
-  , tokenStyles =
+  , tokenStyles = Map.fromList
     [ (KeywordTok, defStyle{ tokenColor = color 0x204a87, tokenBold = True })
     , (DataTypeTok, defStyle{ tokenColor = color 0x204a87 })
     , (DecValTok, defStyle{ tokenColor = color 0x0000cf })
@@ -191,7 +192,7 @@
   , defaultColor = color 0xBDAE9D
   , lineNumberColor = color 0xBDAE9D
   , lineNumberBackgroundColor = color 0x2A211C
-  , tokenStyles =
+  , tokenStyles = Map.fromList
     [ (KeywordTok, defStyle{ tokenColor = color 0x43A8ED, tokenBold = True })
     , (DataTypeTok, defStyle{ tokenUnderline = True })
     , (DecValTok, defStyle{ tokenColor = color 0x44AA43 })
@@ -230,7 +231,7 @@
   , defaultColor = Nothing
   , lineNumberColor = color 0xaaaaaa
   , lineNumberBackgroundColor = Nothing
-  , tokenStyles =
+  , tokenStyles = Map.fromList
     [ (KeywordTok, defStyle{ tokenColor = color 0x0000FF })
     , (CharTok, defStyle{ tokenColor = color 0x008080 })
     , (StringTok, defStyle{ tokenColor = color 0x008080 })
@@ -265,7 +266,7 @@
   , defaultColor = Nothing
   , lineNumberColor = Nothing
   , lineNumberBackgroundColor = Nothing
-  , tokenStyles =
+  , tokenStyles = Map.fromList
     [ (KeywordTok, defStyle{ tokenBold = True })
     , (DataTypeTok, defStyle{ tokenUnderline = True })
     , (CommentTok, defStyle{ tokenItalic = True })
@@ -288,7 +289,7 @@
   , defaultColor = color 0xcccccc
   , lineNumberColor = Nothing
   , lineNumberBackgroundColor = Nothing
-  , tokenStyles =
+  , tokenStyles = Map.fromList
     [ (KeywordTok, defStyle{ tokenColor = color 0xf0dfaf })
     , (DataTypeTok, defStyle{ tokenColor = color 0xdfdfbf })
     , (DecValTok, defStyle{ tokenColor = color 0xdcdccc })
diff --git a/src/Skylighting/Types.hs b/src/Skylighting/Types.hs
--- a/src/Skylighting/Types.hs
+++ b/src/Skylighting/Types.hs
@@ -37,11 +37,14 @@
               , defaultFormatOpts
               ) where
 
+import Control.Monad (mplus)
+import Data.Aeson.Types (toJSONKeyText)
 import Data.Aeson
 import Data.Bits
 import Data.CaseInsensitive (FoldCase(..))
 import Data.Binary (Binary)
 import Data.Data (Data)
+import Data.Maybe (fromMaybe)
 import qualified Data.Map as Map
 import qualified Data.Set as Set
 import Data.Text (Text)
@@ -208,15 +211,25 @@
 instance Binary TokenType
 
 instance ToJSON TokenType where
-  toEncoding t = toEncoding (Text.stripSuffix "Tok" $ Text.pack $ show t)
+  toEncoding = toEncoding . Text.stripSuffix "Tok" . Text.pack . show
 
--- | JSON @"Keyword"@ corresponds to 'KeywordTok', and so on.
+instance ToJSONKey TokenType where
+  toJSONKey = toJSONKeyText
+    (fromMaybe "Unknown" . Text.stripSuffix "Tok" . Text.pack . show)
+
 instance FromJSON TokenType where
   parseJSON (String t) =
+     case readMay (Text.unpack t ++ "Tok") of
+          Just tt -> return tt
+          Nothing -> fail "Not a token type"
+  parseJSON _ = mempty
+
+-- | JSON @"Keyword"@ corresponds to 'KeywordTok', and so on.
+instance FromJSONKey TokenType where
+  fromJSONKey = FromJSONKeyTextParser (\t ->
     case readMay (Text.unpack t ++ "Tok") of
          Just tt -> return tt
-         Nothing -> fail "Not a token type"
-  parseJSON _ = mempty
+         Nothing -> fail "Not a token type")
 
 -- | A line of source: a list of labeled tokens.
 type SourceLine = [Token]
@@ -327,7 +340,7 @@
 -- color for normal tokens.  Line numbers can have a different
 -- color and background color.
 data Style = Style {
-    tokenStyles               :: [(TokenType, TokenStyle)]
+    tokenStyles               :: Map.Map TokenType TokenStyle
   , defaultColor              :: Maybe Color
   , backgroundColor           :: Maybe Color
   , lineNumberColor           :: Maybe Color
@@ -342,15 +355,23 @@
 instance FromJSON Style where
   parseJSON (Object v) = do
     (tokstyles :: Map.Map Text TokenStyle) <- v .: "text-styles"
-    (editorColors :: Map.Map Text Color) <- v .: "editor-colors"
-    return Style{ defaultColor = case Map.lookup "Normal" tokstyles of
-                                      Nothing -> Nothing
-                                      Just ts -> tokenColor ts
-                , backgroundColor = Map.lookup "background-color" editorColors
-                , lineNumberColor = Map.lookup "line-numbers" editorColors
-                , lineNumberBackgroundColor = Map.lookup "background-color"
-                                                editorColors
-                , tokenStyles = Map.toList $
+    (editorColors :: Map.Map Text Color) <- v .:? "editor-colors" .!= mempty
+    mbBackgroundColor <- v .:? "background-color"
+    mbLineNumberColor <- v .:? "line-number-color"
+    mbDefaultColor <- v .:? "text-color"
+    mbLineNumberBackgroundColor <- v .:? "line-number-background-color"
+    return Style{ defaultColor = mbDefaultColor `mplus`
+                     (case Map.lookup "Normal" tokstyles of
+                           Nothing -> Nothing
+                           Just ts -> tokenColor ts)
+                , backgroundColor = mbBackgroundColor `mplus`
+                     Map.lookup "background-color" editorColors
+                , lineNumberColor = mbLineNumberColor `mplus`
+                     Map.lookup "line-numbers" editorColors
+                , lineNumberBackgroundColor =
+                     mbLineNumberBackgroundColor `mplus`
+                       Map.lookup "background-color" editorColors
+                , tokenStyles =
                      Map.mapKeys (\s -> maybe OtherTok id $
                                      readMay (Text.unpack s ++ "Tok")) tokstyles }
   parseJSON _ = mempty
@@ -359,7 +380,9 @@
   toJSON s = object [ "text-styles" .= toJSON (tokenStyles s)
                     , "background-color" .= toJSON (backgroundColor s)
                     , "text-color" .= toJSON (defaultColor s)
-                    , "line-numbers" .= toJSON (lineNumberColor s)
+                    , "line-number-color" .= toJSON (lineNumberColor s)
+                    , "line-number-background-color" .=
+                         toJSON (lineNumberBackgroundColor s)
                     ]
 
 -- | Options for formatting source code.
diff --git a/test/test-skylighting.hs b/test/test-skylighting.hs
--- a/test/test-skylighting.hs
+++ b/test/test-skylighting.hs
@@ -2,7 +2,7 @@
 {-# LANGUAGE OverloadedStrings   #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 module Main where
-import Data.Aeson (decode)
+import Data.Aeson (decode, encode)
 import Data.Monoid ((<>))
 import Data.Algorithm.Diff
 import qualified Data.ByteString.Lazy as BL
@@ -58,6 +58,8 @@
             decode "{ \"text-color\": \"#1f1c1b\", \"bold\": true }"
        , testCase "decode KDE theme to Style" $
             Just kate @=? decode defaultTheme
+       , testCase "round trip style -> theme -> style" $
+            Just kate @=? decode (encode kate)
        ]
     , testGroup "Skylighting.Regex" $
       [ testCase "convertOctalEscapes" $
