diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,27 @@
 # Revision history for skylighting
 
+## 0.3.4 -- 2017-09-09
+
+  * HTML formatting changes (David Baynard).  Note that these
+    changes may require changes in hard-coded CSS that is
+    used with skylighting's HTML output.
+
+    + Wrap lines of source code in a `div` with `display` set to
+      `inline-block`.  The `div`s make per-line processing easier.
+      They cannot be set as `display: block` as that introduces extra
+      new lines when copying and pasting.
+    + Render line numbers in html using CSS pseudo elements rather than
+      a table.  The line numbers are always produced, as `data-line-number`
+      attributes, and css to display them as `::before` elements are
+      always produced. The option to switch on line numbering only
+      toggles a class; this means it is possible to toggle line numbering
+      without re-running skylighting.
+    + If the `linkAnchors` option is set, wrap with an `a` element rather
+      than a `div`, set so that clicking the line number (and only the
+      line number) will jump to that line.
+    + Code wraps by default when html is printed, with wrapped lines
+      indented.
+
 ## 0.3.3.1 -- 2017-06-26
 
   * Updated xml syntax definitions and clojure test.
diff --git a/skylighting.cabal b/skylighting.cabal
--- a/skylighting.cabal
+++ b/skylighting.cabal
@@ -1,5 +1,5 @@
 name:                skylighting
-version:             0.3.3.1
+version:             0.3.4
 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
@@ -5,6 +5,7 @@
     ) where
 
 import Data.List (intersperse)
+import Data.String (fromString)
 import qualified Data.Text as Text
 import Skylighting.Types
 import Text.Blaze.Html
@@ -50,7 +51,8 @@
                                                     $ Text.pack "sourceCode"
                                                       : codeClasses opts))
                                 . mconcat . intersperse (toHtml "\n")
-                                . map (sourceLineToHtml opts)
+                                . zipWith (sourceLineToHtml opts) [startNum..]
+   where startNum = LineNo $ startNumber opts
 
 tokenToHtml :: FormatOptions -> Token -> Html
 tokenToHtml _ (NormalTok, txt)  = toHtml txt
@@ -93,67 +95,87 @@
 short WarningTok        = "wa"
 short NormalTok         = ""
 
-sourceLineToHtml :: FormatOptions -> SourceLine -> Html
-sourceLineToHtml opts cont = mapM_ (tokenToHtml opts) cont
+-- | Each line of source is wrapped in an (inline-block) div that makes
+-- subsequent per-line processing (e.g. adding line numnbers) possible.
+sourceLineToHtml :: FormatOptions -> LineNo -> SourceLine -> Html
+sourceLineToHtml opts lno cont = wrapElement ! A.class_ sourceLine
+                                       ! A.id lineNum
+                                       ! A.href lineRef
+                                       ! H.dataAttribute (fromString "line-number") lineNum $
+                                mapM_ (tokenToHtml opts) cont
+  where  sourceLine = toValue "sourceLine"
+         lineNum = toValue . show . lineNo $ lno
+         lineRef = toValue . ('#':) . show . lineNo $ lno
+         wrapElement = if lineAnchors opts
+                then H.a
+                else H.div
 
 formatHtmlBlockPre :: FormatOptions -> [SourceLine] -> Html
 formatHtmlBlockPre opts = H.pre . formatHtmlInline opts
 
--- | Format tokens as an HTML @pre@ block. If line numbering is
--- selected, this is put into a table row with line numbers in the
--- left cell.  The whole code block is wrapped in a @div@ element
--- to aid styling (e.g. the overflow-x property).  See the
--- documentation for 'formatHtmlInline' for information about how
+-- | Format tokens as an HTML @pre@ block. Each line is wrapped in a div
+-- with the class ‘source-line’. The whole code block is wrapped in a @div@
+-- element to aid styling (e.g. the overflow-x property). If line numbering
+-- is selected, this surrounding div is given the class ‘number-source’,
+-- and the resulting html will display line numbers thanks to the included
+-- css. Note that the html produced will always include the line numbers as
+-- the 'data-line-number' attribute.
+-- See the documentation for 'formatHtmlInline' for information about how
 -- tokens are encoded.
 formatHtmlBlock :: FormatOptions -> [SourceLine] -> Html
 formatHtmlBlock opts ls = H.div ! A.class_ sourceCode $
-                            container ! A.class_ (toValue $ Text.unwords classes)
-  where  container = if numberLines opts
-                        then H.table $ H.tr ! A.class_ sourceCode $
-                                 nums >> source
-                        else pre
-         sourceCode = toValue "sourceCode"
+                            pre ! A.class_ (toValue $ Text.unwords classes)
+  where  sourceCode = toValue . Text.unwords $ Text.pack "sourceCode" :
+                      if numberLines opts
+                        then [Text.pack "numberSource"]
+                        else []
          classes = Text.pack "sourceCode" :
                    [x | x <- containerClasses opts, x /= Text.pack "sourceCode"]
          pre = formatHtmlBlockPre opts ls
-         source = H.td ! A.class_ sourceCode $ pre
-         startNum = startNumber opts
-         nums = H.td ! A.class_ (toValue "lineNumbers")
-                     $ H.pre
-                     $ mapM_ lineNum [startNum..(startNum + length ls - 1)]
-         lineNum n = if lineAnchors opts
-                        then (H.a ! A.id (toValue nStr) ! A.href (toValue $ "#" ++ nStr) $ toHtml $ show n)
-                              >> toHtml "\n"
-                        else toHtml $ show n ++ "\n"
-           where nStr = show n
 
 -- | Returns CSS for styling highlighted code according to the given style.
 styleToCss :: Style -> String
-styleToCss f = unlines $ divspec ++ tablespec ++ colorspec ++ map toCss (tokenStyles f)
+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 ++ "; }"]
-         tablespec = [
-           "table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {"
-          ,"  margin: 0; padding: 0; vertical-align: baseline; border: none; }"
-          ,"table.sourceCode { width: 100%; line-height: 100%; " ++
-             maybe "" (\c -> "background-color: " ++ fromColor c ++ "; ") (backgroundColor f) ++
-             maybe "" (\c -> "color: " ++ fromColor c ++ "; ") (defaultColor f) ++
-             "}"
-          ,"td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; " ++
-             maybe "" (\c -> "background-color: " ++ fromColor c ++ "; ") (lineNumberBackgroundColor f) ++
-             maybe "" (\c -> "color: " ++ fromColor c ++ "; ") (lineNumberColor f) ++
-             maybe "" (\c -> "border-right: 1px solid " ++ fromColor c ++ "; ") (lineNumberColor f) ++
-             "}"
-          ,"td.sourceCode { padding-left: 5px; }"
+         numberspec = [
+            ".numberSource div.sourceLine, .numberSource a.sourceLine"
+          , "  { position: relative; }"
+          , ".numberSource div.sourceLine::before, .numberSource a.sourceLine::before"
+          , "  { content: attr(data-line-number);"
+          , "    position: absolute; left: -5em; text-align: right; vertical-align: baseline;"
+          , "    border: none; pointer-events: all;"
+          , "    -webkit-touch-callout: none; -webkit-user-select: none;"
+          , "    -khtml-user-select: none; -moz-user-select: none;"
+          , "    -ms-user-select: none; user-select: none;"
+          , "    padding: 0 4px; width: 4em; }"
+          , ".numberSource pre.sourceCode { margin-left: 3em; " ++
+              maybe "" (\c -> "border-left: 1px solid " ++ fromColor c ++ "; ") (lineNumberColor f) ++
+              maybe "" (\c -> "background-color: " ++ fromColor c ++ "; ") (lineNumberBackgroundColor f) ++
+              maybe "" (\c -> "color: " ++ fromColor c ++ "; ") (lineNumberColor f) ++
+              " padding-left: 4px; }"
           ]
-         divspec = [ "div.sourceCode { overflow-x: auto; }" ]
+         divspec = [ "div.sourceCode { overflow-x: auto; }"
+          , "div.sourceLine, a.sourceLine { display: inline-block; min-height: 1.25em; }"
+          , "a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }"
+          , ".sourceCode { overflow: visible; }"
+          , "code.sourceCode { white-space: pre; }"
+          , "@media print {"
+          , "code.sourceCode { white-space: pre-wrap; }"
+          , "div.sourceLine, a.sourceLine { text-indent: -1em; padding-left: 1em; }"
+          , "}"
+          ]
+         linkspec = [ "@media screen {"
+          , "a.sourceLine::before { text-decoration: underline; color = initial; }"
+          , "}"
+          ]
 
 toCss :: (TokenType, TokenStyle) -> String
-toCss (t,tf) = "code > span." ++ short t ++ " { "
+toCss (t,tf) = "code span." ++ short t ++ " { "
                 ++ colorspec ++ backgroundspec ++ weightspec ++ stylespec
                 ++ decorationspec ++ "} /* " ++ showTokenType t ++ " */"
   where colorspec = maybe "" (\col -> "color: " ++ fromColor col ++ "; ") $ tokenColor tf
diff --git a/src/Skylighting/Types.hs b/src/Skylighting/Types.hs
--- a/src/Skylighting/Types.hs
+++ b/src/Skylighting/Types.hs
@@ -4,6 +4,7 @@
 {-# LANGUAGE OverloadedStrings    #-}
 {-# LANGUAGE ScopedTypeVariables  #-}
 {-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
 
 -- | Basic types for Skylighting.
 module Skylighting.Types (
@@ -23,6 +24,7 @@
               , Token
               , TokenType(..)
               , SourceLine
+              , LineNo(..)
               -- * Styles
               , TokenStyle(..)
               , defStyle
@@ -216,6 +218,9 @@
 -- | A line of source: a list of labeled tokens.
 type SourceLine = [Token]
 
+-- | Line numbers
+newtype LineNo = LineNo { lineNo :: Int } deriving (Show, Enum)
+
 -- | A 'TokenStyle' determines how a token is to be rendered.
 data TokenStyle = TokenStyle {
     tokenColor      :: Maybe Color
@@ -345,7 +350,6 @@
        , titleAttributes  :: Bool     -- ^ Html titles with token types
        , codeClasses      :: [Text]   -- ^ Additional classes for Html code tag
        , containerClasses :: [Text]   -- ^ Additional classes for Html container tag
-                                      --   (pre or table depending on numberLines)
        } deriving (Show, Read, Eq, Ord, Data, Typeable, Generic)
 
 instance Binary FormatOptions
