diff --git a/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -480,6 +480,32 @@
 - `$gendate$`:   the date the page was generated
 - `$sitetitle$`:   the site title from `config.yaml`
 - `$pagetitle$`:   the page title as defined in `index.yaml`
+- `$root$`: the path to the website's root, relative to the page being
+  rendered.  So, for example, if we are rendering `rooms/room503.html`,
+  `$root$` will have the value `../`. Put `$root$` in front of relative URLs
+  in your layout file, so that the links aren't broken on pages in
+  subdirectories.
+
+### Previewing a site
+
+If you use only relative URLs in your site, you can preview it by
+opening any of the HTML files in site in your web browser. If you use
+absolute links, this won't work, but you can use Jinjing Wang's simple
+static web server `maid`:
+
+    cabal update
+    cabal install maid
+
+To use maid to preview your site, just change to the site directory and
+start `maid`:
+
+    cd site
+    maid
+
+The site will appear at <http://localhost:3000>.  If you want to serve it
+at another port, just pass the port number as an argument to `maid`:
+
+    maid 5999
 
 
 [string template]: http://www.stringtemplate.org/
diff --git a/Yst/Render.hs b/Yst/Render.hs
--- a/Yst/Render.hs
+++ b/Yst/Render.hs
@@ -26,6 +26,7 @@
 import Text.XHtml hiding (option, (</>))
 import Data.Char
 import Data.List (intercalate)
+import Data.List.Split (wordsBy)
 import Text.StringTemplate
 import Data.Maybe (fromMaybe)
 import System.FilePath
@@ -34,14 +35,40 @@
 import Data.Time
 import Control.Monad
 
+-- | @relUrl a b@ returns a URL for @b@ relative to @a@.  So, for
+-- example, @relUrl "a" "a/b.html" = "b.html"@,
+-- @relUrl "" "a/b.html" = "a/b.html"@, and @relUrl "a" "b.html" = "../b.html"@
+relUrl :: String -> String -> String
+relUrl relto url = intercalate "/" $ relPath ++ [urlBase]
+  where relPath = relPaths reltoPaths urlPaths
+        (reltoPaths, urlPaths) = dropCommon (wordsBy (=='/') relto) (wordsBy (=='/') urlDir)
+        urlBase = takeUrlBase url
+        urlDir = takeUrlDir url
+
+takeUrlBase :: String -> String
+takeUrlBase = reverse . takeWhile (/= '/') . reverse
+
+takeUrlDir :: String -> String
+takeUrlDir = reverse . dropWhile (== '/') . dropWhile (/= '/') . reverse
+
+relPaths :: [String] -> [String] -> [String]
+relPaths [] ys = ys
+relPaths (_:xs) ys  = ".." : relPaths xs ys
+
+dropCommon :: (Eq a) => [a] -> [a] -> ([a],[a])
+dropCommon (x:xs) (y:ys) | x == y = dropCommon xs ys
+dropCommon xs ys = (xs,ys)
+
 renderNav :: String -> [NavNode] -> String
 renderNav targeturl nodes = renderHtmlFragment $
   ulist ! [theclass "nav"] << map (renderNavNode targeturl) nodes
 
 renderNavNode :: String -> NavNode -> Html
 renderNavNode targeturl (NavPage tit pageurl) =
-  li ! attrs << hotlink pageurl << tit
-    where attrs = if pageurl == targeturl
+  li ! attrs << hotlink pageurl' << tit
+    where targetdir = takeUrlDir targeturl
+          pageurl' = relUrl targetdir pageurl
+          attrs = if pageurl == targeturl
                      then [theclass "current"]
                      else []
 renderNavNode targeturl (NavMenu tit nodes) =
@@ -85,11 +112,15 @@
   layoutTempl <- getTemplate layout g
   let format = formatFromExtension (stripStExt layout)
   let contents = converterForFormat format rawContents
+  let root' = case length (filter (=='/') $ pageUrl page) of
+                    0  -> ""
+                    n  -> concat $ replicate n "../"
   return $ render
          . setAttribute "sitetitle" (siteTitle site)
          . setAttribute "pagetitle" (pageTitle page)
          . setAttribute "gendate" todaysDate 
          . setAttribute "contents" contents
+         . setAttribute "root" root'
          . setAttribute "nav" menuHtml
          $ layoutTempl
 
diff --git a/Yst/Yaml.hs b/Yst/Yaml.hs
--- a/Yst/Yaml.hs
+++ b/Yst/Yaml.hs
@@ -20,14 +20,26 @@
 where
 import Yst.Types
 import Yst.Util
-import Data.Yaml.Syck
+import Data.Yaml.Syck hiding (unpackBuf, packBuf)
+import qualified Data.Yaml.Syck (unpackBuf, packBuf)
 import Data.Time
 import System.Locale (defaultTimeLocale)
-import Prelude hiding (readFile)
-import System.IO.UTF8
+import Codec.Binary.UTF8.String (encodeString, decodeString)
+import qualified Data.ByteString.Char8 as B (ByteString, readFile)
 
+-- Note: Syck isn't unicode aware, so we use parseYamlBytes and do our
+-- own encoding and decoding.
+
+type Buf = B.ByteString
+
+unpackBuf :: Buf -> String
+unpackBuf = decodeString . Data.Yaml.Syck.unpackBuf
+
+packBuf :: String -> Buf
+packBuf = Data.Yaml.Syck.packBuf . encodeString
+
 readYamlFile :: FilePath -> IO Node
-readYamlFile f = catch (readFile f >>= parseYaml >>= return . yamlNodeToNode)
+readYamlFile f = catch (B.readFile f >>= parseYamlBytes >>= return . yamlNodeToNode)
                    (\e -> errorExit 11 ("Error parsing " ++ f ++ ": " ++ show e) >> return NNil)
 
 yamlNodeToNode :: YamlNode -> Node
diff --git a/demo/events.st b/demo/events.st
--- a/demo/events.st
+++ b/demo/events.st
@@ -7,5 +7,5 @@
 </dl>
 
 Click [here](april_events.tex) for a LaTeX version
-of the list of April events, generated form the same
+of the list of April events, generated from the same
 YAML data file.
diff --git a/demo/layout.html.st b/demo/layout.html.st
--- a/demo/layout.html.st
+++ b/demo/layout.html.st
@@ -2,10 +2,10 @@
 <head>
    <title>$sitetitle$ - $pagetitle$</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-   <link rel="stylesheet" type="text/css" href="css/screen.css" />
-   <link rel="stylesheet" type="text/css" media="print" href="css/print.css" />
+   <link rel="stylesheet" type="text/css" href="$root$css/screen.css" />
+   <link rel="stylesheet" type="text/css" media="print" href="$root$css/print.css" />
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
-   <script src="js/nav.js" type="text/javascript"></script>
+   <script src="$root$js/nav.js" type="text/javascript"></script>
 </head>
 <body>
   <div id="doc3" class="yui-t1">
diff --git a/yst.cabal b/yst.cabal
--- a/yst.cabal
+++ b/yst.cabal
@@ -1,5 +1,5 @@
 name:                yst
-version:             0.2.1
+version:             0.2.2
 Cabal-version:       >= 1.2
 build-type:          Simple
 synopsis:            Builds a static website from templates and data in YAML or
@@ -48,6 +48,7 @@
                      Yst.Render, Yst.Build, Yst.CSV
   build-depends:     base >=3 && < 5, HStringTemplate >= 0.6.1, HsSyck, csv,
                      filepath, containers, directory, utf8-string, time,
-                     old-locale, old-time, parsec, xhtml, pandoc
+                     old-locale, old-time, parsec, xhtml, pandoc, bytestring,
+                     split
   ghc-options:       -Wall -threaded -fno-warn-orphans
   ghc-prof-options:  -auto-all -caf-all
