{"id":4209,"date":"2025-05-14T08:32:24","date_gmt":"2025-05-14T08:32:24","guid":{"rendered":"https:\/\/ingenio.vip\/?post_type=tools-pages&#038;p=4209"},"modified":"2025-05-14T08:32:28","modified_gmt":"2025-05-14T08:32:28","slug":"html-formatter","status":"publish","type":"tools-pages","link":"https:\/\/ingenio.vip\/zh\/tools-pages\/html-formatter\/","title":{"rendered":"HTML Formatter"},"content":{"rendered":"<h2 class=\"wp-block-heading\">\ud83c\udf10 Free Online HTML Formatter &amp; Beautifier<\/h2>\n\n\n\n<p>Clean up messy HTML code in seconds with our free HTML Formatter tool. Whether you&#8217;re debugging, optimizing, or just making your code easier to read, this tool helps you beautify, minify, and validate HTML effortlessly\u2014no registration required.<\/p>\n\n\n\r\n<div class=\"ingenio-tool html-formatter-wrapper\" role=\"region\" aria-labelledby=\"html-formatter-title\">\r\n  <div class=\"html-formatter\">\r\n    <h2 id=\"html-formatter-title\">\u2728 HTML Formatter<\/h2>\r\n    \r\n    <div class=\"formatter-controls\">\r\n      <div class=\"input-section\">\r\n        <div class=\"tabs\">\r\n          <button class=\"tab-btn active\" data-target=\"html-input-tab\">HTML Input<\/button>\r\n          <button class=\"tab-btn\" data-target=\"url-input-tab\">Fetch from URL<\/button>\r\n        <\/div>\r\n        \r\n        <div class=\"tab-content active\" id=\"html-input-tab\">\r\n          <textarea id=\"html-input\" rows=\"12\" placeholder=\"Paste your HTML code here...\"><\/textarea>\r\n        <\/div>\r\n        \r\n        <div class=\"tab-content\" id=\"url-input-tab\">\r\n          <div class=\"url-input-group\">\r\n            <input type=\"url\" id=\"html-url\" placeholder=\"https:\/\/example.com\/page\">\r\n            <button id=\"fetch-html-btn\" class=\"fetch-btn\">\ud83c\udf10 Fetch HTML<\/button>\r\n          <\/div>\r\n          <div id=\"fetch-status\"><\/div>\r\n        <\/div>\r\n        \r\n        <div class=\"file-actions\">\r\n          <button id=\"paste-html-btn\" class=\"action-btn\">\ud83d\udccb Paste HTML<\/button>\r\n          <input type=\"file\" id=\"file-upload\" accept=\".html,.htm,.php,.asp,.aspx,.jsp\">\r\n          <label for=\"file-upload\" class=\"action-btn\">\ud83d\udcc1 Upload File<\/label>\r\n          <span id=\"file-name\">No file selected<\/span>\r\n        <\/div>\r\n      <\/div>\r\n      \r\n      <div class=\"formatting-options\">\r\n        <div class=\"option-group\">\r\n          <label for=\"format-type\">Action:<\/label>\r\n          <select id=\"format-type\">\r\n            <option value=\"beautify\">Beautify<\/option>\r\n            <option value=\"minify\">Minify<\/option>\r\n            <option value=\"compress\">Compress (Keep Comments)<\/option>\r\n            <option value=\"validate\">Validate<\/option>\r\n          <\/select>\r\n        <\/div>\r\n        \r\n        <div class=\"option-group\">\r\n          <label for=\"indent-type\">Indentation:<\/label>\r\n          <select id=\"indent-type\">\r\n            <option value=\"spaces\">Spaces<\/option>\r\n            <option value=\"tabs\">Tabs<\/option>\r\n          <\/select>\r\n          <input type=\"number\" id=\"indent-size\" min=\"1\" max=\"8\" value=\"2\">\r\n        <\/div>\r\n        \r\n        <div class=\"option-group\">\r\n          <label><input type=\"checkbox\" id=\"wrap-attributes\" checked> Wrap Attributes<\/label>\r\n          <label><input type=\"checkbox\" id=\"preserve-newlines\"> Preserve Newlines<\/label>\r\n          <label><input type=\"checkbox\" id=\"inline-elements\"> Handle Inline Elements<\/label>\r\n        <\/div>\r\n        \r\n        <div class=\"option-group\">\r\n          <label for=\"max-line-length\">Max Line Length:<\/label>\r\n          <input type=\"number\" id=\"max-line-length\" min=\"40\" max=\"200\" value=\"80\">\r\n        <\/div>\r\n        \r\n        <div class=\"action-buttons\">\r\n          <button id=\"format-btn\" class=\"format-btn primary\">\ud83e\ude84 Format HTML<\/button>\r\n          <button id=\"clear-btn\" class=\"format-btn secondary\">\ud83d\uddd1\ufe0f Clear<\/button>\r\n          <button id=\"copy-html-btn\" class=\"format-btn\">\ud83d\udccb Copy<\/button>\r\n        <\/div>\r\n        \r\n        <div class=\"stats-summary\">\r\n          <div class=\"stat\">\r\n            <span class=\"stat-label\">Original Size:<\/span>\r\n            <span id=\"original-size\" class=\"stat-value\">0 bytes<\/span>\r\n          <\/div>\r\n          <div class=\"stat\">\r\n            <span class=\"stat-label\">Formatted Size:<\/span>\r\n            <span id=\"formatted-size\" class=\"stat-value\">0 bytes<\/span>\r\n          <\/div>\r\n          <div class=\"stat\">\r\n            <span class=\"stat-label\">Reduction:<\/span>\r\n            <span id=\"reduction-percent\" class=\"stat-value\">0%<\/span>\r\n          <\/div>\r\n        <\/div>\r\n      <\/div>\r\n    <\/div>\r\n    \r\n    <div class=\"output-section\">\r\n      <label for=\"html-output\">Formatted HTML:<\/label>\r\n      <textarea id=\"html-output\" rows=\"12\" readonly><\/textarea>\r\n      <div class=\"output-actions\">\r\n        <button id=\"download-html-btn\" class=\"output-btn\">\ud83d\udcbe Download<\/button>\r\n        <button id=\"view-source-btn\" class=\"output-btn\">\ud83d\udc41\ufe0f View Source<\/button>\r\n        <button id=\"preview-btn\" class=\"output-btn\">\ud83d\udd0d Preview<\/button>\r\n      <\/div>\r\n    <\/div>\r\n    \r\n    <div id=\"preview-modal\" class=\"modal\">\r\n      <div class=\"modal-content\">\r\n        <span class=\"close-modal\">&times;<\/span>\r\n        <iframe id=\"html-preview-frame\"><\/iframe>\r\n      <\/div>\r\n    <\/div>\r\n    \r\n    <div class=\"pro-tips\">\r\n      <h3>\ud83d\udca1 Professional Tips<\/h3>\r\n      <ul>\r\n        <li>Beautified HTML improves readability and debugging<\/li>\r\n        <li>Minified HTML reduces file size for production<\/li>\r\n        <li>Consistent indentation helps team collaboration<\/li>\r\n        <li>Validate HTML before deployment<\/li>\r\n        <li>Use \"View Source\" to check rendered output<\/li>\r\n      <\/ul>\r\n    <\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<style>\r\n  .html-formatter-wrapper {\r\n    background-color: var(--bg, #f5f5fa);\r\n    padding: 1rem;\r\n  }\r\n\r\n  .html-formatter {\r\n    max-width: 1400px;\r\n    margin: auto;\r\n    background: var(--bg, #fff);\r\n    border-radius: 10px;\r\n    padding: 25px;\r\n    box-shadow: 0 4px 12px rgba(0,0,0,0.08);\r\n    font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen-Sans, Ubuntu, Cantarell, \"Helvetica Neue\", sans-serif;\r\n  }\r\n\r\n  .html-formatter h2 {\r\n    text-align: center;\r\n    font-size: 1.8rem;\r\n    color: var(--primary, #E91E63);\r\n    margin-bottom: 1.5rem;\r\n  }\r\n\r\n  .formatter-controls {\r\n    display: flex;\r\n    gap: 20px;\r\n    margin-bottom: 20px;\r\n  }\r\n\r\n  .input-section {\r\n    flex: 2;\r\n  }\r\n\r\n  .tabs {\r\n    display: flex;\r\n    border-bottom: 1px solid #ddd;\r\n    margin-bottom: 10px;\r\n  }\r\n\r\n  .tab-btn {\r\n    padding: 8px 15px;\r\n    background: none;\r\n    border: none;\r\n    border-bottom: 2px solid transparent;\r\n    cursor: pointer;\r\n    font-size: 0.9rem;\r\n    color: #666;\r\n  }\r\n\r\n  .tab-btn.active {\r\n    color: var(--primary, #E91E63);\r\n    border-bottom-color: var(--primary, #E91E63);\r\n    font-weight: 500;\r\n  }\r\n\r\n  .tab-content {\r\n    display: none;\r\n  }\r\n\r\n  .tab-content.active {\r\n    display: block;\r\n  }\r\n\r\n  .url-input-group {\r\n    display: flex;\r\n    gap: 10px;\r\n    margin-bottom: 10px;\r\n  }\r\n\r\n  .url-input-group input {\r\n    flex: 1;\r\n    padding: 8px;\r\n    border: 1px solid #ddd;\r\n    border-radius: 4px;\r\n  }\r\n\r\n  .fetch-btn {\r\n    padding: 8px 15px;\r\n    background: var(--primary, #E91E63);\r\n    color: white;\r\n    border: none;\r\n    border-radius: 4px;\r\n    cursor: pointer;\r\n  }\r\n\r\n  .fetch-btn:hover {\r\n    background: var(--primary-dark, #C2185B);\r\n  }\r\n\r\n  #fetch-status {\r\n    font-size: 0.9rem;\r\n    color: #666;\r\n    min-height: 20px;\r\n  }\r\n\r\n  .input-section textarea,\r\n  .output-section textarea {\r\n    width: 100%;\r\n    padding: 12px;\r\n    border: 1px solid #ddd;\r\n    border-radius: 6px;\r\n    font-family: monospace;\r\n    font-size: 0.95rem;\r\n    resize: vertical;\r\n    min-height: 300px;\r\n  }\r\n\r\n  .file-actions {\r\n    display: flex;\r\n    align-items: center;\r\n    gap: 10px;\r\n    margin-top: 10px;\r\n    flex-wrap: wrap;\r\n  }\r\n\r\n  .action-btn {\r\n    padding: 8px 15px;\r\n    background: #f0f0f0;\r\n    border: 1px solid #ddd;\r\n    border-radius: 4px;\r\n    cursor: pointer;\r\n    transition: all 0.2s;\r\n    font-size: 0.9rem;\r\n    display: inline-flex;\r\n    align-items: center;\r\n    gap: 5px;\r\n  }\r\n\r\n  .action-btn:hover {\r\n    background: #e0e0e0;\r\n  }\r\n\r\n  #file-upload {\r\n    display: none;\r\n  }\r\n\r\n  #file-name {\r\n    font-size: 0.9rem;\r\n    color: #666;\r\n    margin-left: auto;\r\n  }\r\n\r\n  .formatting-options {\r\n    width: 350px;\r\n  }\r\n\r\n  .option-group {\r\n    margin-bottom: 15px;\r\n  }\r\n\r\n  .option-group label {\r\n    display: block;\r\n    margin-bottom: 8px;\r\n    font-weight: 500;\r\n    color: #555;\r\n  }\r\n\r\n  .option-group select,\r\n  .option-group input[type=\"number\"] {\r\n    width: 100%;\r\n    padding: 8px;\r\n    border-radius: 4px;\r\n    border: 1px solid #ddd;\r\n  }\r\n\r\n  .option-group input[type=\"number\"] {\r\n    margin-top: 5px;\r\n  }\r\n\r\n  .option-group label input[type=\"checkbox\"] {\r\n    margin-right: 8px;\r\n  }\r\n\r\n  .action-buttons {\r\n    display: flex;\r\n    gap: 10px;\r\n    margin: 20px 0;\r\n  }\r\n\r\n  .format-btn {\r\n    padding: 10px 15px;\r\n    border: none;\r\n    border-radius: 5px;\r\n    cursor: pointer;\r\n    font-size: 0.95rem;\r\n    transition: all 0.2s;\r\n    display: flex;\r\n    align-items: center;\r\n    justify-content: center;\r\n    gap: 6px;\r\n    flex: 1;\r\n  }\r\n\r\n  .format-btn.primary {\r\n    background: var(--primary, #E91E63);\r\n    color: white;\r\n  }\r\n\r\n  .format-btn.secondary {\r\n    background: #f5f5f5;\r\n    color: #333;\r\n    border: 1px solid #ddd;\r\n  }\r\n\r\n  .format-btn:hover {\r\n    transform: translateY(-1px);\r\n    box-shadow: 0 2px 5px rgba(0,0,0,0.1);\r\n  }\r\n\r\n  .format-btn.primary:hover {\r\n    background: var(--primary-dark, #C2185B);\r\n  }\r\n\r\n  .format-btn.secondary:hover {\r\n    background: #eee;\r\n  }\r\n\r\n  .stats-summary {\r\n    background: #f9f9f9;\r\n    border-radius: 8px;\r\n    padding: 15px;\r\n    margin-top: 15px;\r\n  }\r\n\r\n  .stat {\r\n    display: flex;\r\n    justify-content: space-between;\r\n    margin-bottom: 8px;\r\n    font-size: 0.95rem;\r\n  }\r\n\r\n  .stat:last-child {\r\n    margin-bottom: 0;\r\n  }\r\n\r\n  .stat-label {\r\n    color: #555;\r\n  }\r\n\r\n  .stat-value {\r\n    font-weight: bold;\r\n    color: var(--primary, #E91E63);\r\n  }\r\n\r\n  .output-actions {\r\n    display: flex;\r\n    gap: 10px;\r\n    margin-top: 10px;\r\n  }\r\n\r\n  .output-btn {\r\n    padding: 8px 15px;\r\n    background: #f0f0f0;\r\n    border: 1px solid #ddd;\r\n    border-radius: 4px;\r\n    cursor: pointer;\r\n    transition: all 0.2s;\r\n    font-size: 0.9rem;\r\n    display: inline-flex;\r\n    align-items: center;\r\n    justify-content: center;\r\n    gap: 5px;\r\n    flex: 1;\r\n  }\r\n\r\n  .output-btn:hover {\r\n    background: #e0e0e0;\r\n  }\r\n\r\n  \/* Modal styles *\/\r\n  .modal {\r\n    display: none;\r\n    position: fixed;\r\n    z-index: 1000;\r\n    left: 0;\r\n    top: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    background-color: rgba(0,0,0,0.7);\r\n  }\r\n\r\n  .modal-content {\r\n    background-color: #fefefe;\r\n    margin: 5% auto;\r\n    padding: 20px;\r\n    border: 1px solid #888;\r\n    width: 90%;\r\n    height: 80%;\r\n    border-radius: 5px;\r\n    position: relative;\r\n  }\r\n\r\n  .close-modal {\r\n    color: #aaa;\r\n    float: right;\r\n    font-size: 28px;\r\n    font-weight: bold;\r\n    cursor: pointer;\r\n  }\r\n\r\n  .close-modal:hover {\r\n    color: black;\r\n  }\r\n\r\n  #html-preview-frame {\r\n    width: 100%;\r\n    height: calc(100% - 30px);\r\n    border: none;\r\n    margin-top: 10px;\r\n  }\r\n\r\n  .pro-tips {\r\n    background: #FCE4EC;\r\n    border-radius: 10px;\r\n    padding: 15px 20px;\r\n    border-left: 4px solid var(--primary, #E91E63);\r\n    margin-top: 25px;\r\n  }\r\n\r\n  .pro-tips h3 {\r\n    margin-top: 0;\r\n    margin-bottom: 10px;\r\n    font-size: 1.1rem;\r\n  }\r\n\r\n  .pro-tips ul {\r\n    margin: 0;\r\n    padding-left: 20px;\r\n  }\r\n\r\n  .pro-tips li {\r\n    margin-bottom: 5px;\r\n  }\r\n\r\n  @media (max-width: 1200px) {\r\n    .formatter-controls {\r\n      flex-direction: column;\r\n    }\r\n    \r\n    .formatting-options {\r\n      width: 100%;\r\n    }\r\n  }\r\n<\/style>\r\n\r\n<script>\r\ndocument.addEventListener(\"DOMContentLoaded\", function() {\r\n  \/\/ DOM elements\r\n  const htmlInput = document.getElementById('html-input');\r\n  const htmlOutput = document.getElementById('html-output');\r\n  const htmlUrl = document.getElementById('html-url');\r\n  const fetchHtmlBtn = document.getElementById('fetch-html-btn');\r\n  const fetchStatus = document.getElementById('fetch-status');\r\n  const fileUpload = document.getElementById('file-upload');\r\n  const fileName = document.getElementById('file-name');\r\n  const pasteHtmlBtn = document.getElementById('paste-html-btn');\r\n  const formatType = document.getElementById('format-type');\r\n  const indentType = document.getElementById('indent-type');\r\n  const indentSize = document.getElementById('indent-size');\r\n  const wrapAttributes = document.getElementById('wrap-attributes');\r\n  const preserveNewlines = document.getElementById('preserve-newlines');\r\n  const inlineElements = document.getElementById('inline-elements');\r\n  const maxLineLength = document.getElementById('max-line-length');\r\n  const formatBtn = document.getElementById('format-btn');\r\n  const clearBtn = document.getElementById('clear-btn');\r\n  const copyHtmlBtn = document.getElementById('copy-html-btn');\r\n  const downloadHtmlBtn = document.getElementById('download-html-btn');\r\n  const viewSourceBtn = document.getElementById('view-source-btn');\r\n  const previewBtn = document.getElementById('preview-btn');\r\n  const previewModal = document.getElementById('preview-modal');\r\n  const closeModal = document.querySelector('.close-modal');\r\n  const previewFrame = document.getElementById('html-preview-frame');\r\n  const tabBtns = document.querySelectorAll('.tab-btn');\r\n  const tabContents = document.querySelectorAll('.tab-content');\r\n  \r\n  \/\/ Stats elements\r\n  const originalSizeEl = document.getElementById('original-size');\r\n  const formattedSizeEl = document.getElementById('formatted-size');\r\n  const reductionPercentEl = document.getElementById('reduction-percent');\r\n\r\n  \/\/ Event listeners\r\n  fileUpload.addEventListener('change', handleFileUpload);\r\n  pasteHtmlBtn.addEventListener('click', pasteFromClipboard);\r\n  fetchHtmlBtn.addEventListener('click', fetchHtmlFromUrl);\r\n  formatBtn.addEventListener('click', formatHtml);\r\n  clearBtn.addEventListener('click', clearAll);\r\n  copyHtmlBtn.addEventListener('click', copyHtml);\r\n  downloadHtmlBtn.addEventListener('click', downloadHtml);\r\n  viewSourceBtn.addEventListener('click', viewSource);\r\n  previewBtn.addEventListener('click', showPreview);\r\n  closeModal.addEventListener('click', hidePreview);\r\n  window.addEventListener('click', outsideModalClick);\r\n  \r\n  \/\/ Tab switching\r\n  tabBtns.forEach(btn => {\r\n    btn.addEventListener('click', function() {\r\n      const target = this.dataset.target;\r\n      \r\n      \/\/ Update active tab\r\n      tabBtns.forEach(b => b.classList.remove('active'));\r\n      tabContents.forEach(c => c.classList.remove('active'));\r\n      \r\n      this.classList.add('active');\r\n      document.getElementById(target).classList.add('active');\r\n    });\r\n  });\r\n\r\n  \/\/ Handle file upload\r\n  function handleFileUpload(e) {\r\n    const file = e.target.files[0];\r\n    if (!file) return;\r\n    \r\n    fileName.textContent = file.name;\r\n    \r\n    const reader = new FileReader();\r\n    reader.onload = function(e) {\r\n      htmlInput.value = e.target.result;\r\n      updateStats();\r\n    };\r\n    reader.readAsText(file);\r\n  }\r\n\r\n  \/\/ Paste from clipboard\r\n  async function pasteFromClipboard() {\r\n    try {\r\n      const text = await navigator.clipboard.readText();\r\n      htmlInput.value = text;\r\n      updateStats();\r\n    } catch (err) {\r\n      alert('Failed to read clipboard contents. Please paste manually.');\r\n    }\r\n  }\r\n\r\n  \/\/ Fetch HTML from URL\r\n  async function fetchHtmlFromUrl() {\r\n    const url = htmlUrl.value.trim();\r\n    if (!url) {\r\n      fetchStatus.textContent = 'Please enter a valid URL';\r\n      return;\r\n    }\r\n    \r\n    try {\r\n      fetchStatus.textContent = 'Fetching HTML...';\r\n      fetchStatus.style.color = '#666';\r\n      \r\n      \/\/ Use a proxy to avoid CORS issues\r\n      const proxyUrl = `https:\/\/api.allorigins.win\/get?url=${encodeURIComponent(url)}`;\r\n      const response = await fetch(proxyUrl);\r\n      \r\n      if (!response.ok) throw new Error('Network response was not ok');\r\n      \r\n      const data = await response.json();\r\n      \r\n      if (data.contents) {\r\n        htmlInput.value = data.contents;\r\n        fetchStatus.textContent = 'HTML fetched successfully!';\r\n        fetchStatus.style.color = '#4CAF50';\r\n        updateStats();\r\n      } else {\r\n        throw new Error('No content received');\r\n      }\r\n    } catch (error) {\r\n      fetchStatus.textContent = `Error: ${error.message}`;\r\n      fetchStatus.style.color = '#F44336';\r\n    }\r\n  }\r\n\r\n  \/\/ Format HTML\r\n  function formatHtml() {\r\n    const html = htmlInput.value.trim();\r\n    if (!html) {\r\n      alert('Please enter some HTML to format');\r\n      return;\r\n    }\r\n    \r\n    const action = formatType.value;\r\n    const indentChar = indentType.value === 'tabs' ? '\\t' : ' '.repeat(indentSize.value);\r\n    const maxLineLen = parseInt(maxLineLength.value);\r\n    \r\n    try {\r\n      let formattedHtml = html;\r\n      \r\n      switch(action) {\r\n        case 'beautify':\r\n          formattedHtml = beautifyHtml(html, {\r\n            indent: indentChar,\r\n            wrap_line_length: maxLineLen,\r\n            wrap_attributes: wrapAttributes.checked ? 'force' : 'auto',\r\n            preserve_newlines: preserveNewlines.checked,\r\n            inline: inlineElements.checked ? ['a', 'span', 'strong', 'em', 'b', 'i', 'u'] : []\r\n          });\r\n          break;\r\n          \r\n        case 'minify':\r\n          formattedHtml = minifyHtml(html, {\r\n            collapseWhitespace: true,\r\n            removeComments: true,\r\n            removeAttributeQuotes: true,\r\n            removeEmptyAttributes: true,\r\n            removeRedundantAttributes: true\r\n          });\r\n          break;\r\n          \r\n        case 'compress':\r\n          formattedHtml = minifyHtml(html, {\r\n            collapseWhitespace: true,\r\n            keepClosingSlash: true,\r\n            removeAttributeQuotes: false,\r\n            removeEmptyAttributes: false\r\n          });\r\n          break;\r\n          \r\n        case 'validate':\r\n          formattedHtml = validateHtml(html);\r\n          break;\r\n      }\r\n      \r\n      htmlOutput.value = formattedHtml;\r\n      updateStats();\r\n    } catch (error) {\r\n      alert('Error formatting HTML: ' + error.message);\r\n    }\r\n  }\r\n\r\n  \/\/ Beautify HTML (simplified implementation)\r\n  function beautifyHtml(html, options) {\r\n    \/\/ This is a simplified version - in production you'd use a library like js-beautify\r\n    const { indent, wrap_line_length, wrap_attributes, preserve_newlines } = options;\r\n    \r\n    \/\/ Basic indentation\r\n    let level = 0;\r\n    let result = '';\r\n    const lines = html.split('\\n');\r\n    \r\n    for (let line of lines) {\r\n      line = line.trim();\r\n      if (!line) continue;\r\n      \r\n      \/\/ Decrease level for closing tags\r\n      if (line.match(\/^<\\\/\\w\/)) {\r\n        level = Math.max(0, level - 1);\r\n      }\r\n      \r\n      \/\/ Add indentation\r\n      result += indent.repeat(level) + line + '\\n';\r\n      \r\n      \/\/ Increase level for opening tags\r\n      if (line.match(\/^<\\w[^>]*[^\/]>$\/) || line.match(\/^<\\w[^>]*[^\/]>.*<\\\/\\w>$\/)) {\r\n        level++;\r\n      }\r\n    }\r\n    \r\n    return result;\r\n  }\r\n\r\n  \/\/ Minify HTML (simplified implementation)\r\n  function minifyHtml(html, options) {\r\n    \/\/ This is a simplified version - in production you'd use a library like html-minifier\r\n    return html\r\n      .replace(\/\/g, '') \/\/ Remove comments if specified\r\n      .replace(\/\\s+\/g, ' ') \/\/ Collapse whitespace\r\n      .replace(\/>\\s+<\/g, '><'); \/\/ Remove spaces between tags\r\n  }\r\n\r\n  \/\/ Validate HTML (simplified implementation)\r\n  function validateHtml(html) {\r\n    \/\/ This would use a proper HTML validator in production\r\n    const errors = [];\r\n    \r\n    \/\/ Check for unclosed tags (simplified)\r\n    const openTags = [];\r\n    const tagRegex = \/<\\\/?([a-z][a-z0-9]*)[^>]*>\/gi;\r\n    let match;\r\n    \r\n    while ((match = tagRegex.exec(html)) !== null) {\r\n      const tag = match[1].toLowerCase();\r\n      if (match[0].startsWith('<\/')) {\r\n        \/\/ Closing tag\r\n        if (openTags.length === 0 || openTags.pop() !== tag) {\r\n          errors.push(`Mismatched closing tag: <\/${tag}>`);\r\n        }\r\n      } else if (!match[0].endsWith('\/>')) {\r\n        \/\/ Opening tag (not self-closing)\r\n        openTags.push(tag);\r\n      }\r\n    }\r\n    \r\n    if (openTags.length > 0) {\r\n      errors.push(`Unclosed tags: ${openTags.join(', ')}`);\r\n    }\r\n    \r\n    if (errors.length === 0) {\r\n      return html + '\\n\\n\/* HTML validation: No errors found *\/';\r\n    } else {\r\n      return html + '\\n\\n\/* HTML validation errors:\\n' + errors.join('\\n') + '\\n*\/';\r\n    }\r\n  }\r\n\r\n  \/\/ Update statistics\r\n  function updateStats() {\r\n    const originalHtml = htmlInput.value;\r\n    const formattedHtml = htmlOutput.value;\r\n    \r\n    const originalSize = new Blob([originalHtml]).size;\r\n    const formattedSize = formattedHtml ? new Blob([formattedHtml]).size : 0;\r\n    \r\n    originalSizeEl.textContent = formatBytes(originalSize);\r\n    formattedSizeEl.textContent = formattedHtml ? formatBytes(formattedSize) : '0 bytes';\r\n    \r\n    if (originalSize > 0 && formattedSize > 0) {\r\n      const reduction = ((originalSize - formattedSize) \/ originalSize * 100).toFixed(1);\r\n      reductionPercentEl.textContent = `${reduction}%`;\r\n      reductionPercentEl.style.color = reduction > 0 ? '#4CAF50' : '#F44336';\r\n    } else {\r\n      reductionPercentEl.textContent = '0%';\r\n      reductionPercentEl.style.color = '#666';\r\n    }\r\n  }\r\n\r\n  \/\/ Format bytes for display\r\n  function formatBytes(bytes) {\r\n    if (bytes === 0) return '0 bytes';\r\n    \r\n    const k = 1024;\r\n    const sizes = ['bytes', 'KB', 'MB', 'GB'];\r\n    const i = Math.floor(Math.log(bytes) \/ Math.log(k));\r\n    \r\n    return parseFloat((bytes \/ Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\r\n  }\r\n\r\n  \/\/ Copy HTML to clipboard\r\n  function copyHtml() {\r\n    if (!htmlOutput.value) {\r\n      alert('No formatted HTML to copy');\r\n      return;\r\n    }\r\n    \r\n    htmlOutput.select();\r\n    document.execCommand('copy');\r\n    \r\n    \/\/ Visual feedback\r\n    const originalText = copyHtmlBtn.textContent;\r\n    copyHtmlBtn.textContent = '\u2713 Copied!';\r\n    setTimeout(() => {\r\n      copyHtmlBtn.textContent = originalText;\r\n    }, 2000);\r\n  }\r\n\r\n  \/\/ Download HTML\r\n  function downloadHtml() {\r\n    if (!htmlOutput.value) {\r\n      alert('No formatted HTML to download');\r\n      return;\r\n    }\r\n    \r\n    const blob = new Blob([htmlOutput.value], { type: 'text\/html' });\r\n    const url = URL.createObjectURL(blob);\r\n    const a = document.createElement('a');\r\n    a.href = url;\r\n    a.download = `formatted-${new Date().toISOString().slice(0, 10)}.html`;\r\n    document.body.appendChild(a);\r\n    a.click();\r\n    document.body.removeChild(a);\r\n    URL.revokeObjectURL(url);\r\n  }\r\n\r\n  \/\/ View source in new window\r\n  function viewSource() {\r\n    if (!htmlOutput.value) {\r\n      alert('No formatted HTML to view');\r\n      return;\r\n    }\r\n    \r\n    const sourceWindow = window.open('', '_blank');\r\n    sourceWindow.document.write('<pre>' + htmlOutput.value + '<\/pre>');\r\n    sourceWindow.document.close();\r\n  }\r\n\r\n  \/\/ Show HTML preview\r\n  function showPreview() {\r\n    if (!htmlOutput.value) {\r\n      alert('No formatted HTML to preview');\r\n      return;\r\n    }\r\n    \r\n    previewFrame.srcdoc = htmlOutput.value;\r\n    previewModal.style.display = 'block';\r\n  }\r\n\r\n  \/\/ Hide preview modal\r\n  function hidePreview() {\r\n    previewModal.style.display = 'none';\r\n  }\r\n\r\n  \/\/ Close modal when clicking outside\r\n  function outsideModalClick(e) {\r\n    if (e.target === previewModal) {\r\n      hidePreview();\r\n    }\r\n  }\r\n\r\n  \/\/ Clear all fields\r\n  function clearAll() {\r\n    htmlInput.value = '';\r\n    htmlOutput.value = '';\r\n    fileUpload.value = '';\r\n    fileName.textContent = 'No file selected';\r\n    originalSizeEl.textContent = '0 bytes';\r\n    formattedSizeEl.textContent = '0 bytes';\r\n    reductionPercentEl.textContent = '0%';\r\n    reductionPercentEl.style.color = '#666';\r\n    fetchStatus.textContent = '';\r\n  }\r\n\r\n  \/\/ Initialize\r\n  updateStats();\r\n});\r\n<\/script>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u2728 Key Features<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2705 <strong>Beautify HTML<\/strong> \u2013 Organize and indent your HTML for better readability<\/li>\n\n\n\n<li>\ud83d\udcc9 <strong>Minify HTML<\/strong> \u2013 Compress your code to improve load times<\/li>\n\n\n\n<li>\ud83e\uddea <strong>Validate HTML Syntax<\/strong> \u2013 Detect errors and improve structure<\/li>\n\n\n\n<li>\ud83d\udccb <strong>Copy &amp; Download Options<\/strong> \u2013 Use formatted code instantly<\/li>\n\n\n\n<li>\ud83d\udd12 <strong>100% Secure<\/strong> \u2013 Your code stays private and is never stored<\/li>\n\n\n\n<li>\ud83d\udeab <strong>No Account Needed<\/strong> \u2013 Use it anytime, free of charge<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\ude80 How It Works<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Paste your HTML code<\/strong> into the editor<\/li>\n\n\n\n<li>Choose to <strong>Beautify<\/strong> or <strong>Minify<\/strong> your HTML<\/li>\n\n\n\n<li>Click the button and <strong>instantly format your code<\/strong><\/li>\n\n\n\n<li><strong>Copy, edit, or download<\/strong> your clean HTML<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\uddd1\u200d\ud83d\udcbb Who Should Use This Tool?<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Web Developers<\/strong> \u2013 Format messy code or minify for performance<\/li>\n\n\n\n<li><strong>Students &amp; Educators<\/strong> \u2013 Learn and teach clean coding practices<\/li>\n\n\n\n<li><strong>UI\/UX Designers<\/strong> \u2013 Ensure readable and structured HTML<\/li>\n\n\n\n<li><strong>Bloggers &amp; Content Creators<\/strong> \u2013 Clean up embeds and custom HTML<\/li>\n\n\n\n<li><strong>SEO Experts<\/strong> \u2013 Optimize HTML structure for search engines<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udca1 Why Use a Formatter?<\/h2>\n\n\n\n<p>Poorly formatted HTML can be hard to debug and maintain. A clean structure:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Improves readability<\/li>\n\n\n\n<li>Makes collaboration easier<\/li>\n\n\n\n<li>Reduces page load time (when minified)<\/li>\n\n\n\n<li>Helps avoid errors in rendering<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u2705 Try Our Free HTML Formatter Now<\/h2>\n\n\n\n<p>Simplify your workflow and write clean, professional HTML with our fast and reliable formatter. No downloads, no sign-ups\u2014just paste, click, and go.<\/p>\n\n\n\n<p>\ud83d\udc49 <strong>[Format My HTML Now]<\/strong><\/p>","protected":false},"excerpt":{"rendered":"<p>\ud83c\udf10 Free Online HTML Formatter &amp; Beautifier Clean up messy HTML code in seconds with our free HTML Formatter tool. Whether you&#8217;re debugging, optimizing, or just making your code easier to read, this tool helps you beautify, minify, and validate HTML effortlessly\u2014no registration required. \u2728 HTML Formatter HTML Input Fetch from URL \ud83c\udf10 Fetch HTML [&hellip;]<\/p>\n<\/p><div class=\"more-link\"><a href=\"https:\/\/ingenio.vip\/zh\/tools-pages\/html-formatter\/\" class=\"btn btn-small btn--dark btn-hover-shadow\"><span class=\"text\">Continue Reading<\/span><i class=\"seoicon-right-arrow\"><\/i><\/a><\/div>","protected":false},"author":1,"featured_media":0,"menu_order":0,"template":"","meta":{"_acf_changed":false,"googlesitekit_rrm_CAowrpbbCw:productID":"","footnotes":""},"tools-categories":[],"class_list":["post-4209","tools-pages","type-tools-pages","status-publish","hentry"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/ingenio.vip\/zh\/wp-json\/wp\/v2\/tools-pages\/4209","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ingenio.vip\/zh\/wp-json\/wp\/v2\/tools-pages"}],"about":[{"href":"https:\/\/ingenio.vip\/zh\/wp-json\/wp\/v2\/types\/tools-pages"}],"author":[{"embeddable":true,"href":"https:\/\/ingenio.vip\/zh\/wp-json\/wp\/v2\/users\/1"}],"version-history":[{"count":1,"href":"https:\/\/ingenio.vip\/zh\/wp-json\/wp\/v2\/tools-pages\/4209\/revisions"}],"predecessor-version":[{"id":4210,"href":"https:\/\/ingenio.vip\/zh\/wp-json\/wp\/v2\/tools-pages\/4209\/revisions\/4210"}],"wp:attachment":[{"href":"https:\/\/ingenio.vip\/zh\/wp-json\/wp\/v2\/media?parent=4209"}],"wp:term":[{"taxonomy":"tools-categories","embeddable":true,"href":"https:\/\/ingenio.vip\/zh\/wp-json\/wp\/v2\/tools-categories?post=4209"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}