diff --git a/lib/haml/engine.rb b/lib/haml/engine.rb
index dd4c7a2..d491d77 100644
--- a/lib/haml/engine.rb
+++ b/lib/haml/engine.rb
@@ -37,7 +37,7 @@ module Haml
       @options = {
         :suppress_eval => false,
         :attr_wrapper => "'",
-        :autoclose => ['meta', 'img', 'link', 'br', 'hr', 'input', 'area'],
+        :autoclose => %w(meta img link br hr input area param col base),
         :filters => {
           'sass' => Haml::Filters::Sass,
           'plain' => Haml::Filters::Plain,
@@ -47,7 +47,8 @@ module Haml
           'textile' => Haml::Filters::Textile,
           'markdown' => Haml::Filters::Markdown },
         :filename => '(haml)',
-        :ugly => false
+        :ugly => false,
+        :html4 => false
       }
       @options.rec_merge! options

diff --git a/lib/haml/precompiler.rb b/lib/haml/precompiler.rb
index e79438e..922e434 100644
--- a/lib/haml/precompiler.rb
+++ b/lib/haml/precompiler.rb
@@ -473,8 +473,9 @@ END
       result.compact.sort.join
     end

-    def prerender_tag(name, atomic, attributes)
-      "<#{name}#{Precompiler.build_attributes(@options[:attr_wrapper], attributes)}#{atomic ? ' />' : '>'}"
+    def prerender_tag(name, self_close, attributes)
+      attributes_string = Precompiler.build_attributes(@options[:attr_wrapper], attributes)
+      "<#{name}#{attributes_string}#{self_close && !@options[:html4] ? ' /' : ''}>"
     end

     # Parses a line into tag_name, attributes, attributes_hash, object_ref, action, value
@@ -502,7 +503,7 @@ END
       raise SyntaxError.new("Illegal element: classes and ids must have values.") if attributes =~ /[\.#](\.|#|\z)/

       case action
-      when '/'; atomic = true
+      when '/'; atomic = !@options[:html4]
       when '~'; parse = flattened = true
       when '='
         parse = true
@@ -521,12 +522,12 @@ END
       attributes = parse_class_and_id(attributes)
       Buffer.merge_attrs(attributes, static_attributes) if static_attributes

-      raise SyntaxError.new("Illegal Nesting: Nesting within an atomic tag is illegal.") if @block_opened && atomic
-      raise SyntaxError.new("Illegal Nesting: Content can't be both given on the same line as %#{tag_name} and nested within it.") if @block_opened && !value.empty?
-      raise SyntaxError.new("Tag has no content.") if parse && value.empty?
-      raise SyntaxError.new("Atomic tags can't have content.") if atomic && !value.empty?
+      raise SyntaxError, "Illegal Nesting: Nesting within an atomic tag is illegal." if @block_opened && atomic
+      raise SyntaxError, "Illegal Nesting: Content can't be both given on the same line as %#{tag_name} and nested within it." if @block_opened && !value.empty?
+      raise SyntaxError, "Tag has no content." if parse && value.empty?
+      raise SyntaxError, "Atomic tags can't have content." if atomic && !value.empty?

-      atomic = true if !@block_opened && value.empty? && @options[:autoclose].include?(tag_name)
+      atomic ||= !!( !@block_opened && value.empty? && @options[:autoclose].include?(tag_name) )

       if object_ref == "nil" && attributes_hash.nil? && !flattened && (parse || Buffer.one_liner?(value))
         # This means that we can render the tag directly to text and not process it in the buffer
@@ -600,22 +601,32 @@ END
     def text_for_doctype(text)
       text = text[3..-1].lstrip.downcase
       if text[0...3] == "xml"
+        return nil if @options[:html4]
         wrapper = @options[:attr_wrapper]
         return ""
       end

       version, type = text.scan(DOCTYPE_REGEX)[0]
-      if version == "1.1"
-        return ''
-      end
+      
+      unless @options[:html4]
+        if version == "1.1"
+          return ''
+        end

-      case type
-      when "strict";   return ''
-      when "frameset"; return ''
-      else             return ''
+        case type
+        when "strict";   return ''
+        when "frameset"; return ''
+        else             return ''
+        end
+      else
+        case type
+        when "strict";   return ''
+        when "frameset"; return ''
+        else             return ''
+        end
       end
     end
-
+    
     # Starts a filtered block.
     def start_filtered(name)
       raise SyntaxError.new('Filters must have nested text.') unless @block_opened
diff --git a/test/haml/engine_test.rb b/test/haml/engine_test.rb
index 7bc9842..5e5644c 100644
--- a/test/haml/engine_test.rb
+++ b/test/haml/engine_test.rb
@@ -394,4 +394,28 @@ class EngineTest < Test::Unit::TestCase
     assert_equal("

#{'s' * 75}

\n", render("%p= 's' * 75", :ugly => true)) end + + # HTML 4.0 + + def test_html_has_no_self_closing_tags + assert_equal "

\n
\n

\n", render("%p\n %br", :html4 => :true) + assert_equal "
\n", render("%br/", :html4 => :true) + end + + def test_html_renders_empty_node_with_closing_tag + assert_equal %{
\n
\n}, render(".foo", :html4 => :true) + end + + def test_html_ignores_explicit_self_closing_declaration + assert_equal "\n\n", render("%a/", :html4 => :true) + end + + def test_html_ignores_xml_prolog_declaration + assert_equal "\n", render('!!! XML', :html4 => :true) + end + + def test_html_has_different_doctype + assert_equal %{\n}, + render('!!!', :html4 => :true) + end end