defsnippet only matches a specific part of your html (which is why it takes a selector as an argument), and transforms it. deftemplate takes the entire html, and transforms it. Also, defsnippet returns a Clojure data structure while deftemplates returns a vector of strings, so a defsnippet is usually used within a deftemplate.
To give you an idea of what the data returned by a snippet (or selector) look like:
(enlive/html-snippet "<div id='foo'><p>Hello there</p></div>")
;=({:tag :div, :attrs {:id "foo"}, :content ({:tag :p, :attrs nil, :content ("Hello there")})})
In your case you want something like:
header.html:
<div id="my-header-root">
...
</div>
Clojure code:
(enlive/defsnippet header "path/to/header.html" [:#my-header-root] []
identity)
(enlive/defsnippet footer "path/to/footer.html" [enlive/root] []
identity)
(enlive/deftemplate layout "layout.html" [header footer]
[:head] (enlive/content header)
[:body] (enlive/append footer))
(defroutes home-routes
(GET "/" [] (layout (header) (footer))
The identity function used in the snippets returns it's argument, which in this case is the data structure selected by the :#my-header-root selector (we don't do any transformation). If you want to include everything in i.e head.html you can use the root selector-step that comes with enlive.
You can view the html generated from a defsnippet using something like this:
(print (apply str (enlive/emit* (my-snippet))))
I also recommend the tutorial: https://github.com/swannodette/enlive-tutorial/
and the one by Brian Marick for some more details of how the defsnippet and deftemplate macros work.
Last tip, you can experiment with selectors and transformations using the sniptest macro that comes with enlive:
(enlive/sniptest "<p>Replace me</p>"
[:p] (enlive/content "Hello world!"))
;= "<p>Hello world!</p>"