Guías HTML para meta
Aprende a identificar y corregir errores comunes de validación HTML marcados por el W3C Validator, para que tus páginas cumplan con los estándares y se muestren correctamente en todos los navegadores. También consulta nuestras Guías de accesibilidad.
A character encoding declaration tells the browser how to interpret the raw bytes of your document into readable characters. For HTML documents, the standard way to declare this is with <meta charset="utf-8">. The HTML specification requires that this element be serialized completely within the first 1024 bytes of the document. This means that everything from the start of the file—including the doctype, the <html> tag, the <head> tag, and the <meta charset> element itself—must fit within that 1024-byte window.
If the <meta charset> element appears after the first 1024 bytes, the browser must use other heuristics or fallback encodings to guess how to decode the document. This can cause several problems:
- Garbled or broken text: Characters outside the ASCII range (such as accented letters, CJK characters, or emoji) may render incorrectly.
- Security vulnerabilities: Certain encoding-sniffing behaviors have historically been exploited for cross-site scripting (XSS) attacks, which is one reason the spec enforces this strict limit.
- Inconsistent rendering: Different browsers may fall back to different default encodings, meaning your page could look different depending on the user’s browser or system locale.
This issue typically occurs when a large number of <meta> tags, inline <style> blocks, lengthy comments, or <script> elements are placed in the <head> before the <meta charset> declaration. Even excessive whitespace or server-injected content can push it past the 1024-byte boundary.
To fix this, ensure that <meta charset="utf-8"> is the first child element of <head>, appearing before any <title>, <link>, <script>, <style>, or other <meta> tags. Remove or relocate any unnecessary content that precedes it.
Examples
❌ Incorrect: <meta charset> pushed past 1024 bytes
In this example, a large inline style block and several meta tags appear before the charset declaration, easily exceeding the 1024-byte limit:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="description" content="A very long description...">
<meta name="keywords" content="many, keywords, here, ...">
<meta name="author" content="Some Author">
<link rel="stylesheet" href="styles.css">
<style>
/* Hundreds of bytes of inline CSS rules...
...pushing the total well past 1024 bytes
before the charset declaration appears */
body { font-family: sans-serif; margin: 0; padding: 0; }
.container { max-width: 1200px; margin: 0 auto; }
/* ...many more rules... */
</style>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello world</p>
</body>
</html>
✅ Correct: <meta charset> as the first element in <head>
Move the charset declaration to the very first position inside <head>:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
<meta name="description" content="A very long description...">
<meta name="keywords" content="many, keywords, here, ...">
<meta name="author" content="Some Author">
<link rel="stylesheet" href="styles.css">
<style>
body { font-family: sans-serif; margin: 0; padding: 0; }
.container { max-width: 1200px; margin: 0 auto; }
</style>
</head>
<body>
<p>Hello world</p>
</body>
</html>
✅ Minimal correct example
For simpler documents, the pattern is straightforward—just keep <meta charset> first:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello world</p>
</body>
</html>
As a general rule of thumb, always make <meta charset="utf-8"> the very first thing after the opening <head> tag. This guarantees it falls well within the 1024-byte limit regardless of what follows, and it ensures the browser knows the correct encoding before it encounters any other content.
Both <meta charset="UTF-8"> and <meta http-equiv="content-type" content="text/html; charset=UTF-8"> instruct the browser which character encoding to use when interpreting the document’s bytes into text. Having both declarations in the same document creates a redundant and potentially conflicting situation. The HTML specification explicitly forbids including both, because if they ever specified different encodings, the browser would have to decide which one to trust, leading to unpredictable behavior.
Character encoding is critical for correctly displaying text. If the encoding is wrong or ambiguous, characters like accented letters, emoji, or symbols from non-Latin scripts can appear as garbled text (often called “mojibake”). By requiring a single, unambiguous declaration, the spec ensures browsers can reliably determine the encoding.
The <meta charset="UTF-8"> syntax was introduced with HTML5 as a shorter, cleaner alternative to the older <meta http-equiv="content-type"> approach. Both are valid on their own, but modern best practice strongly favors <meta charset="UTF-8"> for its simplicity. Whichever you choose, it should appear as early as possible within the <head> element — ideally as the first child — and must appear within the first 1024 bytes of the document so the browser can detect the encoding before parsing the rest of the content.
To fix this issue, search your document’s <head> for both forms of the declaration and remove one of them. In most cases, you should keep <meta charset="UTF-8"> and remove the <meta http-equiv="content-type"> element.
Examples
Incorrect: both declarations present
This triggers the validation error because both methods of declaring the character encoding are used simultaneously.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Correct: using <meta charset> (recommended)
This is the modern, preferred approach for HTML5 documents.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Correct: using <meta http-equiv="content-type">
This older syntax is also valid on its own. You might encounter it in legacy codebases or when serving documents as application/xhtml+xml.
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Common scenario: declarations split across includes
In templating systems or CMS platforms, the two declarations sometimes end up in different partial files — for example, one in a base layout and another injected by a plugin or theme. If you encounter this error unexpectedly, check all files that contribute to your <head> section, not just the main template.
<!-- base-layout.html -->
<head>
<meta charset="UTF-8">
<!-- ...other tags... -->
</head>
<!-- plugin-head-snippet.html (remove this duplicate) -->
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
Audit your includes and partials to ensure only one character encoding declaration ends up in the final rendered <head>.
The <meta charset> element tells the browser which character encoding to use when interpreting the bytes of the HTML document. The HTML specification explicitly states that there must be no more than one <meta> element with a charset attribute per document. This declaration should appear within the first 1024 bytes of the document, so placing it as the first child of <head> (right after the opening <head> tag) is the recommended practice.
Duplicate charset declarations typically happen when code is assembled from multiple templates, partials, or snippets — each contributing its own <meta charset>. It can also occur when a developer manually adds a charset declaration without realizing one is already present, or when migrating from an older <meta http-equiv="Content-Type"> approach and adding a new <meta charset> without removing the old equivalent.
Why this matters
- Standards compliance: The WHATWG HTML living standard mandates at most one <meta charset> per document. Violating this produces a validation error.
- Unpredictable behavior: When a browser encounters conflicting or duplicate charset declarations, the behavior is undefined. While most modern browsers will use the first one encountered, relying on this is fragile and could lead to garbled text or encoding issues in edge cases.
- Maintainability: Multiple charset declarations signal disorganized or duplicated template logic, making the codebase harder to maintain.
How to fix it
- Search your HTML document (including any templates, layouts, or partials that compose the final output) for all instances of <meta charset> or <meta charset="...">.
- Keep exactly one <meta charset="utf-8"> declaration, placed as the first element inside <head>.
- Remove all other <meta charset> elements.
- If you also have a legacy <meta http-equiv="Content-Type" content="text/html; charset=utf-8">, remove it — the shorter <meta charset="utf-8"> form is the modern replacement, and having both counts as duplicate charset declarations.
Examples
❌ Incorrect: multiple charset declarations
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
The second <meta charset="utf-8"> triggers the validation error, even though both specify the same encoding.
❌ Incorrect: mixing old and new charset syntax
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Both elements declare a character encoding, so the validator treats this as a duplicate.
✅ Correct: single charset declaration
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
A single <meta charset="utf-8"> appears first in <head>, before any other elements or content. This is the correct and recommended approach. UTF-8 is the strongly recommended encoding for all new HTML documents.
The <meta name="description"> element provides a brief summary of a page’s content. According to the WHATWG HTML living standard, there must be no more than one <meta> element per document where the name attribute has the value "description". This is a conformance requirement — not just a best practice — meaning that including duplicates produces invalid HTML.
Why this matters
Standards compliance: The HTML specification explicitly states that certain metadata names, including "description", must be unique within a document. Violating this makes your HTML non-conforming.
Search engine behavior: Search engines like Google use the meta description to generate snippet text in search results. When multiple description meta tags are present, search engines must decide which one to use — or may ignore them entirely and pull text from the page body instead. This can result in a less relevant or less compelling snippet, potentially reducing click-through rates.
Maintainability: Duplicate meta descriptions often arise from template conflicts — for example, a CMS injecting one description while a theme or plugin adds another. Having duplicates makes it unclear which description is actually intended, creating confusion for developers maintaining the code.
Common causes
- A CMS or static site generator automatically inserts a <meta name="description"> tag, while the template or theme also hardcodes one.
- Multiple HTML partials or includes each contribute their own description meta tag to the <head>.
- Copy-paste errors when building or editing the <head> section.
How to fix it
- Search your HTML source for all instances of <meta name="description".
- Decide which description best represents the page’s content.
- Remove all duplicate instances, keeping only one.
- If your content comes from templates or includes, trace where each tag is generated and ensure only one source outputs the description.
Examples
❌ Invalid: duplicate description meta tags
<!DOCTYPE html>
<html lang="en">
<head>
<title>About Us</title>
<meta name="description" content="Learn about our company and mission.">
<meta name="description" content="We are a team of passionate developers.">
</head>
<body>
<h1>About Us</h1>
<p>Welcome to our about page.</p>
</body>
</html>
The validator will report an error because two <meta> elements share name="description".
✅ Valid: single description meta tag
<!DOCTYPE html>
<html lang="en">
<head>
<title>About Us</title>
<meta name="description" content="Learn about our company, mission, and the team of passionate developers behind it.">
</head>
<body>
<h1>About Us</h1>
<p>Welcome to our about page.</p>
</body>
</html>
Here, the two descriptions have been merged into a single, more comprehensive meta description. Alternatively, you could simply keep whichever original description was more accurate and discard the other.
❌ Invalid: duplicates from mixed sources (common template issue)
<head>
<title>Blog Post</title>
<!-- Injected by CMS -->
<meta name="description" content="Auto-generated summary of the blog post.">
<!-- Hardcoded in theme template -->
<meta name="description" content="A blog about web development tips and tricks.">
<meta name="author" content="Jane Smith">
</head>
✅ Valid: single source of truth
<head>
<title>Blog Post</title>
<!-- Injected by CMS (theme duplicate removed) -->
<meta name="description" content="Auto-generated summary of the blog post.">
<meta name="author" content="Jane Smith">
</head>
When fixing template-driven duplicates, decide which system should own the description — typically the CMS, since it can generate page-specific descriptions — and remove the hardcoded one from the theme.
Make sure your final <meta name="description"> content is meaningful, concise (typically 150–160 characters), and accurately reflects what visitors will find on the page.
The X-UA-Compatible meta tag was originally introduced to control which rendering engine Internet Explorer would use to display a page. Developers could force IE to emulate older versions (e.g., IE=7, IE=9) or use the latest available engine with IE=edge. The value IE=edge,chrome=1 was also commonly used to activate the Google Chrome Frame plugin, which allowed Internet Explorer to use Chrome’s rendering engine instead.
The HTML specification now only permits the value IE=edge for this meta tag. Other values are considered invalid for several reasons:
- Google Chrome Frame is discontinued. The chrome=1 directive targeted a plugin that was retired in February 2014 and is no longer supported by any browser.
- Legacy IE rendering modes are obsolete. Internet Explorer itself has been retired, making emulation modes like IE=EmulateIE7 or IE=9 pointless.
- Standards compliance. The WHATWG HTML living standard explicitly requires the content attribute value to be IE=edge when http-equiv="X-UA-Compatible" is used.
In practice, since all modern browsers use their latest rendering engine by default, this meta tag has little functional impact today. If your site no longer needs to support Internet Explorer at all, you can safely remove the tag entirely. If you choose to keep it — for example, in environments where legacy IE browsers might still access your site — ensure the value is exactly IE=edge.
Examples
Invalid: Using chrome=1 with IE=edge
This was a common pattern when Google Chrome Frame was active, but it now triggers a validation error:
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
Invalid: Using a legacy IE rendering mode
Forcing a specific IE version is no longer valid:
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">
Invalid: Specifying a particular IE version
<meta http-equiv="X-UA-Compatible" content="IE=9">
Valid: Using IE=edge
The only accepted value is IE=edge:
<meta http-equiv="X-UA-Compatible" content="IE=edge">
Valid: Removing the tag entirely
If you don’t need Internet Explorer compatibility, the simplest fix is to remove the meta tag altogether. A minimal valid document without it:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
The <meta charset="utf-8"> declaration is not only valid but recommended by the HTML living standard. So when the validator complains that the charset attribute is “not allowed at this point,” the problem isn’t the <meta> tag itself — it’s what surrounds it. The HTML parser follows strict rules about which elements can appear inside <head>. When it encounters an element that doesn’t belong there (like <img>, <div>, <p>, or other flow/phrasing content), it implicitly closes the <head> and opens the <body>. Any <meta> tags that come after that point are now parsed as being inside <body>, where <meta charset> is not permitted.
This is a problem for several reasons. First, the <meta charset> declaration must appear within the first 1024 bytes of the document so browsers can determine the character encoding early. If the parser moves it out of <head>, browsers may not apply the encoding correctly, potentially leading to garbled text — especially for non-ASCII characters. Second, this often signals a structural error in your HTML that could cause other unexpected rendering issues.
Common causes include:
- An element that only belongs in <body> (like <img>, <div>, <span>, or <p>) placed before <meta charset> in the <head>.
- A stray closing tag (like </head>) appearing too early.
- A <script> tag with content that causes the parser to break out of <head>.
To fix the issue, inspect the elements that appear before <meta charset> in your <head>. Move any elements that don’t belong in <head> into <body>, and place <meta charset="utf-8"> as the very first element inside <head>.
Examples
Incorrect — element before <meta> forces parser out of <head>
An <img> tag inside <head> causes the parser to implicitly close <head> and open <body>. The <meta charset> that follows is now parsed as being in <body>, triggering the error.
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
<img src="photo.jpg" alt="A smiling cat">
<meta charset="utf-8">
</head>
<body>
<p>Some content</p>
</body>
</html>
Correct — <meta charset> first, invalid elements moved to <body>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<img src="photo.jpg" alt="A smiling cat">
<p>Some content</p>
</body>
</html>
Incorrect — stray <div> in <head> breaks context
<!DOCTYPE html>
<html lang="en">
<head>
<div>Oops</div>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello</p>
</body>
</html>
Correct — only valid head elements before <meta charset>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<div>Content goes here</div>
<p>Hello</p>
</body>
</html>
Best practice
As a general rule, always make <meta charset="utf-8"> the very first child of <head>. This ensures the browser detects the encoding as early as possible and avoids the risk of other elements accidentally breaking the parser context before the charset is declared.
The http-equiv attribute on a <meta> element simulates an HTTP response header, allowing you to define document-level metadata that would otherwise require server configuration. Because this metadata applies to the entire document and must be processed before the page content is rendered, the HTML specification requires that <meta http-equiv> elements appear within the <head> element. Placing them in the <body> is invalid and may cause browsers to ignore them entirely, leading to unexpected behavior like incorrect character encoding, broken content security policies, or missing refresh directives.
This error commonly occurs when:
- A <meta http-equiv> tag is accidentally placed inside <body>.
- Content is copy-pasted from one document into the body of another, bringing along <meta> tags.
- A templating system or CMS injects <meta> tags in the wrong location.
Common http-equiv values
The http-equiv attribute supports several standard values:
- content-type — Declares the document’s MIME type and character encoding. In HTML5, the shorthand <meta charset="UTF-8"> is preferred instead.
- refresh — Instructs the browser to reload the page or redirect after a specified number of seconds. Note that automatic refreshing is discouraged for accessibility reasons: it can disorient users, move focus back to the top of the page, and disrupt assistive technology. Avoid it unless absolutely necessary.
- content-security-policy — Defines a Content Security Policy for the document, helping prevent cross-site scripting (XSS) and other code injection attacks.
- default-style — Specifies the preferred stylesheet from a set of alternative stylesheets.
How to fix it
Find every <meta http-equiv> element in your document and ensure it is placed inside the <head> element, before any content in <body>. If the tag is duplicated or unnecessary, remove it.
Examples
❌ Incorrect: http-equiv inside <body>
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<p>Hello, world!</p>
</body>
</html>
The <meta http-equiv> tag is inside <body>, which triggers the validation error.
✅ Correct: http-equiv inside <head>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
✅ Correct: using the HTML5 charset shorthand
In HTML5, you can replace <meta http-equiv="content-type" content="text/html; charset=UTF-8"> with the simpler charset attribute:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
✅ Correct: Content Security Policy in <head>
<head>
<meta charset="UTF-8">
<meta http-equiv="content-security-policy" content="default-src 'self'">
<title>Secure Page</title>
</head>
The content-security-policy value is particularly placement-sensitive — browsers will ignore it if it appears outside <head>, leaving your page without the intended security protections.
This error is misleading at first glance because the <meta> tag in question is often perfectly well-formed. The real problem is usually above the <meta> tag — an element that doesn’t belong in <head> (such as <img>, <div>, <p>, or other flow content) has been placed there. When the HTML parser encounters such an element inside <head>, it implicitly closes the <head> and opens the <body>. From that point on, any subsequent <meta> tags are now technically inside the <body>, where the name attribute on <meta> is not permitted.
In other cases, the error can also occur when a <meta name="..."> tag is explicitly placed inside <body>, or when a typo or malformed tag earlier in the document breaks the expected document structure.
This matters for several reasons. Search engines and social media platforms rely on <meta> tags being in the <head> to extract page descriptions, Open Graph data, and other metadata. If the document structure is broken and <meta> tags end up in the <body>, this metadata may be ignored entirely. Additionally, elements like <img> inside <head> won’t render as expected, and the overall document structure will be invalid, potentially causing unpredictable behavior across browsers.
How to fix it
- Look above the flagged <meta> tag. Find any element in the <head> that doesn’t belong there — common culprits include <img>, <div>, <span>, <p>, <a>, or <section>.
- Move the offending element into the <body> where it belongs.
- If the <meta> tag itself is in the <body>, move it into the <head>.
- Check for malformed tags above the <meta> — an unclosed tag or a typo can break the parser’s understanding of the document structure.
Only certain elements are allowed inside <head>: <title>, <meta>, <link>, <style>, <script>, <noscript>, <base>, and <template>.
Examples
An invalid element in <head> breaks the context
The <img> tag is not allowed inside <head>. The parser implicitly closes <head> when it encounters it, so the <meta> tag that follows ends up in <body>:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
<img src="photo.jpg" alt="A smiling cat">
<meta name="description" content="A page about cats">
</head>
<body>
<p>Welcome!</p>
</body>
</html>
Move the <img> into the <body> to fix the issue:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
<meta name="description" content="A page about cats">
</head>
<body>
<img src="photo.jpg" alt="A smiling cat">
<p>Welcome!</p>
</body>
</html>
A <meta> tag accidentally placed in <body>
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<meta name="author" content="Jane Doe">
<p>Hello world</p>
</body>
</html>
Move the <meta> tag into <head>:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
<meta name="author" content="Jane Doe">
</head>
<body>
<p>Hello world</p>
</body>
</html>
A malformed tag disrupts the <head>
A missing closing > on a <link> tag can confuse the parser, causing subsequent elements to be misinterpreted:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
<link rel="stylesheet" href="style.css"
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>Content</p>
</body>
</html>
Close the <link> tag properly:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
<link rel="stylesheet" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>Content</p>
</body>
</html>
The http-equiv attribute on the <meta> element is designed to simulate certain HTTP response headers when a server isn’t configured to send them directly. However, the HTML specification only permits a limited set of values for this attribute. According to the WHATWG HTML living standard, the valid http-equiv values are:
- content-type — an alternative way to declare character encoding
- default-style — sets the preferred stylesheet
- refresh — redirects or reloads the page after a delay
- x-ua-compatible — specifies document compatibility mode for Internet Explorer
- content-security-policy — declares a content security policy
Using Cache-Control as an http-equiv value is a pattern that originated in early web development, when some browsers attempted to honor cache directives set through <meta> tags. In practice, modern browsers ignore <meta http-equiv="Cache-Control"> entirely. Caching behavior is determined by actual HTTP response headers sent by the server, not by <meta> tags in the document body. This means the tag not only triggers a validation error but also has no practical effect — it gives a false sense of control over caching while doing nothing.
This matters for several reasons. Invalid HTML can cause unexpected behavior in browsers, particularly edge cases with older or less common user agents. It also undermines confidence in your markup — if a validator flags issues, it becomes harder to spot genuinely important errors. Additionally, relying on a non-functional tag for caching can lead to real problems if developers assume caching is being handled when it isn’t.
The correct approach is to configure cache-control headers on your web server or application layer. Every major web server and framework provides a straightforward way to set Cache-Control HTTP headers.
For Apache, you can add this to your .htaccess or server configuration:
Header set Cache-Control "no-cache, no-store, must-revalidate"
For Nginx, use:
add_header Cache-Control "no-cache, no-store, must-revalidate";
In a Node.js/Express application:
res.set('Cache-Control', 'no-cache, no-store, must-revalidate');
Examples
Invalid: Using Cache-Control as an http-equiv value
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
</head>
<body>
<p>This page attempts to control caching via meta tags.</p>
</body>
</html>
In this example, all three <meta> tags are problematic. Cache-Control and Pragma are not valid http-equiv values. While Expires was historically used, it is also not in the current list of conforming values in the WHATWG specification.
Fixed: Removing invalid <meta> tags
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
<!-- Cache-Control should be set via server HTTP headers -->
</head>
<body>
<p>Caching is now properly handled server-side.</p>
</body>
</html>
The invalid <meta> tags are removed entirely. Cache behavior is configured on the server, where it actually takes effect.
Valid: Using a permitted http-equiv value
<!DOCTYPE html>
<html lang="en">
<head>
<title>Redirecting</title>
<meta http-equiv="refresh" content="5;url=https://example.com">
</head>
<body>
<p>You will be redirected in 5 seconds.</p>
</body>
</html>
This example uses refresh, which is a valid http-equiv value. It demonstrates what the attribute is actually designed for — a small set of well-defined, browser-supported directives.
The http-equiv attribute on <meta> elements acts as a pragma directive, simulating the effect of an HTTP response header. The HTML specification defines a strict list of allowed values, including content-type, default-style, refresh, x-ua-compatible, and content-security-policy. Any value not on this list — such as cleartype — is considered invalid and will trigger a validation error.
The <meta http-equiv="cleartype" content="on"> tag was a proprietary Microsoft extension designed to activate ClearType text smoothing in Internet Explorer Mobile 6 and 7 on Windows Phone. ClearType is a sub-pixel rendering technology that improves the readability of text on LCD screens. Since these browsers are long obsolete, this meta tag serves no practical purpose today. No modern browser recognizes or acts on it.
Keeping invalid meta tags in your HTML has several downsides:
- Standards compliance: It produces W3C validation errors, which can mask other, more important issues in your markup.
- Code cleanliness: Dead code clutters your document head and confuses developers who may not know its history.
- No functional benefit: Since no current browser or rendering engine uses this directive, it provides zero value.
The fix is straightforward: remove the <meta http-equiv="cleartype"> tag. If your project requires smooth font rendering on modern browsers, CSS properties like font-smooth (non-standard) or -webkit-font-smoothing and -moz-osx-font-smoothing can be used instead, though these are also non-standard and should be used with care.
Examples
❌ Invalid: Using cleartype as an http-equiv value
<head>
<meta charset="utf-8">
<meta http-equiv="cleartype" content="on">
<title>My Page</title>
</head>
This triggers the validation error because cleartype is not a valid value for http-equiv.
✅ Fixed: Remove the invalid meta tag
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
Simply removing the tag resolves the error with no loss of functionality in modern browsers.
✅ Alternative: Use CSS for font smoothing if needed
If you want to influence text rendering, use CSS instead of a non-standard meta tag:
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
Note that these CSS properties are themselves non-standard and primarily affect macOS and iOS rendering. On Windows, modern browsers already apply ClearType or DirectWrite smoothing automatically without any developer intervention.
The http-equiv attribute on the <meta> element simulates HTTP response headers. However, the HTML living standard only allows a specific set of values for http-equiv, and Content-Script-Type is not among them. The allowed values include content-type, default-style, refresh, x-ua-compatible, and content-security-policy.
In HTML 4.01, <meta http-equiv="Content-Script-Type" content="text/javascript"> was used to tell the browser which scripting language to assume for inline event handlers (like onclick). Since JavaScript is now the only scripting language supported by browsers, this declaration serves no purpose. Every modern browser already assumes JavaScript by default, making this meta tag completely redundant.
Removing this tag has no effect on your page’s behavior. Your scripts will continue to work exactly as before. If you’re maintaining a legacy codebase, you can safely delete this line during any cleanup or modernization effort.
Examples
❌ Invalid: using Content-Script-Type
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<title>My Page</title>
</head>
This triggers the validation error because Content-Script-Type is not a valid http-equiv value in modern HTML.
✅ Fixed: remove the obsolete meta tag
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
Simply remove the <meta http-equiv="Content-Script-Type"> line. No replacement is needed — browsers already default to JavaScript for all script handling.
✅ Valid http-equiv values for reference
Here are some examples of http-equiv values that are valid in modern HTML:
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta http-equiv="refresh" content="30">
<meta http-equiv="content-security-policy" content="default-src 'self'">
<title>My Page</title>
</head>
The http-equiv attribute accepts a specific set of predefined values, and the validator checks both the value itself and its formatting. When the validator reports a bad value of ""Content-Security-Policy"" (note the doubled quotes), it means the actual attribute value being parsed includes literal quotation mark characters as part of the string. The browser sees the first " as opening the attribute, then immediately sees the second " as closing it — resulting in a malformed tag that won’t work as intended.
This matters for several reasons. Content-Security-Policy delivered via a <meta> tag is a critical security mechanism that restricts which resources your page can load. If the tag is malformed, the browser will silently ignore the policy, leaving your site without the CSP protections you intended. There’s no visual indication that the policy failed to apply, making this a particularly dangerous bug.
Common causes of this issue include:
- Copying code from a word processor or CMS that converts straight quotes (") into curly/smart quotes (" and ").
- Double-escaping in templates where a templating engine adds quotes around a value that already has quotes in the markup.
- Manual typos where quotes are accidentally duplicated.
To fix this, open your HTML source in a plain-text editor (not a word processor) and ensure the http-equiv value is wrapped in exactly one pair of standard straight double quotes with no extra quote characters inside.
Examples
Incorrect — doubled quotes around the value
<meta http-equiv=""Content-Security-Policy"" content="default-src 'self';">
The validator interprets this as an http-equiv attribute with an empty value (""), followed by unrecognized content (Content-Security-Policy""), producing the error.
Incorrect — curly/smart quotes
<meta http-equiv="Content-Security-Policy" content="default-src 'self';">
Smart quotes (" and ") are not valid attribute delimiters in HTML. They become part of the attribute value itself, causing the validator to reject it.
Incorrect — HTML entity quotes inside the attribute
<meta http-equiv=""Content-Security-Policy"" content="default-src 'self';">
Using " inside the attribute value embeds literal quote characters into the value string, which makes it invalid.
Correct — single pair of straight double quotes
<meta http-equiv="Content-Security-Policy" content="default-src 'self';">
Correct — full document example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https:; script-src 'self';">
<title>CSP Example</title>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>
The http-equiv value Content-Security-Policy must be spelled exactly as shown — it is case-insensitive per the HTML spec, but using the canonical casing is recommended for clarity. The actual policy directives go in the content attribute, not in http-equiv. If you’re using a templating engine or CMS, check the generated HTML source (via “View Page Source” in your browser) to confirm the output contains clean, straight quotes with no doubling.
Why This Is an Issue
In HTML 4 and XHTML, the Content-Style-Type HTTP header (and its <meta http-equiv> equivalent) told the browser which stylesheet language to use when interpreting inline style attributes and <style> elements. This was theoretically necessary because the specification allowed for alternative stylesheet languages beyond CSS.
In practice, CSS became the only stylesheet language browsers support. The HTML living standard (maintained by WHATWG) recognizes this reality and defines a strict list of valid http-equiv values. Content-Style-Type is not among them. The only valid values include content-type, default-style, refresh, x-ua-compatible, content-security-policy, and a few others defined in the spec.
Because every browser defaults to CSS for all styling, this meta tag serves no functional purpose. Keeping it in your markup only produces a validation error and adds unnecessary bytes to your document.
Similarly, the related Content-Script-Type meta tag (which declared the default scripting language) is also obsolete for the same reasons — JavaScript is the universal default.
How to Fix It
The fix is straightforward: remove the <meta http-equiv="Content-Style-Type" ...> tag from your document’s <head>. No replacement is needed. Browsers will interpret all stylesheets as CSS and all scripts as JavaScript without any explicit declaration.
If you inherited this tag from a legacy template or an older CMS, you can safely delete it with no impact on your site’s appearance or behavior.
Examples
❌ Invalid: Using the obsolete Content-Style-Type pragma
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Style-Type" content="text/css">
<title>My Page</title>
</head>
This triggers the validator error: Bad value “Content-Style-Type” for attribute “http-equiv” on element “meta”.
✅ Valid: Simply remove the obsolete meta tag
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
No replacement is needed. CSS is already the default stylesheet language in all browsers.
❌ Invalid: Both Content-Style-Type and Content-Script-Type (common in legacy templates)
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<title>Legacy Page</title>
</head>
✅ Valid: Remove both obsolete declarations
<head>
<meta charset="utf-8">
<title>Legacy Page</title>
</head>
Both Content-Style-Type and Content-Script-Type are obsolete. Removing them has zero effect on how browsers render your page, and your HTML will pass validation cleanly.
The http-equiv attribute on the <meta> element is designed to simulate certain HTTP response headers directly in HTML. However, the HTML specification only permits a specific set of values: content-type, default-style, refresh, x-ua-compatible, and content-security-policy. Using Expires as a value for http-equiv will trigger a validation error because it falls outside this permitted set.
Historically, some older browsers and HTML versions were more lenient about which values could appear in http-equiv, and developers commonly used <meta http-equiv="Expires" content="0"> or similar patterns to try to prevent page caching. However, this approach was never reliable — browsers and caching proxies handle actual HTTP headers far more consistently than <meta> tag equivalents. Modern HTML formally disallows this value.
Beyond standards compliance, there are practical reasons to avoid this pattern. Many browsers simply ignore unrecognized http-equiv values, meaning the tag does nothing useful. Cache behavior is best controlled at the HTTP level, where servers, CDNs, and proxies all read and respect the headers. Relying on a <meta> tag for caching gives a false sense of control while cluttering your markup with invalid code.
To fix this issue, remove the <meta http-equiv="Expires" ...> tag from your HTML and configure the Expires or Cache-Control HTTP header on your web server.
Examples
Incorrect: Using Expires in http-equiv
This triggers the validation error:
<head>
<meta charset="UTF-8">
<meta http-equiv="Expires" content="0">
<meta http-equiv="Expires" content="Tue, 01 Jan 2025 00:00:00 GMT">
<title>My Page</title>
</head>
Correct: Remove the invalid <meta> tag
Simply remove the offending tag. Only use valid http-equiv values:
<head>
<meta charset="UTF-8">
<title>My Page</title>
</head>
Correct: Valid uses of http-equiv
For reference, here are examples of valid http-equiv values:
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="30">
<meta http-equiv="content-security-policy" content="default-src 'self'">
<meta http-equiv="default-style" content="main-stylesheet">
<title>My Page</title>
</head>
Correct: Set cache expiration via server configuration
The proper way to control caching is through HTTP response headers configured on your server.
Apache (.htaccess or server config):
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/html "access plus 1 day"
</IfModule>
Or using Cache-Control with mod_headers:
<IfModule mod_headers.c>
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Expires "0"
</IfModule>
Nginx:
location ~* \.html$ {
expires 1d;
add_header Cache-Control "public, no-transform";
}
To prevent caching entirely in Nginx:
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
If you don’t have access to server configuration, many server-side languages let you set headers programmatically. For example, in PHP:
<?php
header("Expires: Tue, 01 Jan 2030 00:00:00 GMT");
header("Cache-Control: public, max-age=86400");
?>
By handling cache expiration at the server level, you get reliable behavior across all browsers, proxies, and CDNs — while keeping your HTML clean and standards-compliant.
This error is almost always caused by copying and pasting code from a word processor, CMS rich-text editor, blog post, or PDF. These tools often auto-correct straight quotation marks (") into typographic (curly or “smart”) quotes (" and "). While curly quotes look nicer in prose, they are not valid as attribute delimiters in HTML. The browser and the W3C validator only recognize the standard straight double quote (", U+0022) or straight single quote (', U+0027) as attribute value delimiters.
When the validator encounters markup like <meta property="og:type", the curly quotes are treated as part of the attribute’s value. The validator then sees the value as "og:type" — a string wrapped in literal curly quote characters. Since the property attribute in RDFa (which Open Graph Protocol relies on) expects a term or an absolute URL, and "og:type" is neither, the validator reports the error.
This problem can affect any HTML attribute, but it’s especially common with <meta> tags for Open Graph, Twitter Cards, and other social sharing metadata, since developers frequently copy these snippets from documentation or tutorials.
How to fix it
- Find the curly quotes. Look at the property attribute value in your source code. Curly opening quotes (", U+201C) and closing quotes (", U+201D) may look nearly identical to straight quotes in some fonts, so use your editor’s find-and-replace feature to search for " and ".
- Replace them with straight quotes. Swap every " and " with a standard straight double quote (").
- Disable smart quotes in your editor. If you’re writing HTML in a rich-text editor or word processor, turn off the “smart quotes” or “typographic quotes” feature. Better yet, use a dedicated code editor (like VS Code, Sublime Text, or similar) that won’t auto-replace quotes.
Examples
Incorrect — curly quotes around the attribute value
<meta property="og:type" content="website" />
The curly " and " characters become part of the value itself, producing the validator error: Bad value "og:type" for attribute property.
Correct — straight quotes around the attribute value
<meta property="og:type" content="website" />
Standard straight double quotes correctly delimit the attribute values, and the validator sees og:type as expected.
Correct — single straight quotes are also valid
<meta property='og:type' content='website' />
Straight single quotes (', U+0027) work just as well as straight double quotes for delimiting HTML attribute values. Use whichever style your project prefers, but be consistent.
Full Open Graph example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
<meta property="og:title" content="My Page">
<meta property="og:type" content="website">
<meta property="og:url" content="https://example.com/">
<meta property="og:image" content="https://example.com/image.png">
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
All property and content attributes use straight double quotes, ensuring clean validation and correct parsing by social media crawlers.
The Pragma HTTP header is a holdover from HTTP/1.0, originally used to instruct proxies and browsers not to cache a response. In older HTML specifications, developers sometimes placed <meta http-equiv="Pragma" content="no-cache"> in their documents, hoping browsers would treat it like a real HTTP header. However, the HTML living standard (maintained by WHATWG) restricts the http-equiv attribute to a small set of recognized values: content-type, default-style, refresh, x-ua-compatible, and content-security-policy. The value Pragma is not among them, which is why the W3C validator flags it as invalid.
Beyond the validation error, this approach has always been unreliable. Browsers and caching proxies generally ignore http-equiv meta tags for cache control purposes — they rely on actual HTTP response headers sent by the server. Keeping this invalid tag in your HTML provides a false sense of security while producing no real caching benefit.
Why this is a problem
- Standards compliance: Using an unrecognized http-equiv value produces invalid HTML that fails W3C validation.
- No practical effect: Most browsers and all intermediary proxies (CDNs, reverse proxies) ignore cache directives embedded in <meta> tags. Only real HTTP headers reliably control caching behavior.
- Misleading code: Developers maintaining the codebase may assume caching is properly managed in HTML when it isn’t, leading to unexpected caching issues in production.
How to fix it
- Remove the invalid <meta> tag from your HTML <head>.
- Configure caching via HTTP response headers on your server. Set Cache-Control (and optionally Pragma for HTTP/1.0 compatibility) as actual headers in your server configuration or application code.
For example, in an Apache .htaccess file:
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Or in an Nginx configuration:
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
These server-side headers are the correct and effective way to manage caching.
Examples
Incorrect: using Pragma in http-equiv
This triggers the validation error:
<head>
<meta charset="utf-8">
<meta http-equiv="Pragma" content="no-cache">
<title>My Page</title>
</head>
Incorrect: using Cache-Control in http-equiv
While Cache-Control is also sometimes seen in <meta> tags, it is not a valid http-equiv value in the HTML standard either, and browsers largely ignore it:
<head>
<meta charset="utf-8">
<meta http-equiv="Cache-Control" content="no-cache">
<title>My Page</title>
</head>
Correct: remove the invalid tag and use server headers
Simply remove the caching meta tag. Your HTML stays clean and valid:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Cache control is handled by server-side HTTP headers.</p>
</body>
</html>
Then configure your web server to send the appropriate Cache-Control and Pragma HTTP response headers as shown in the server configuration examples above. This is the only reliable way to control how browsers and proxies cache your pages.
The HTML5 specification mandates UTF-8 as the only permitted character encoding for web documents declared via <meta> tags. Legacy encodings such as windows-1251 (a Cyrillic character encoding), iso-8859-1, shift_jis, and others are no longer valid values in HTML5 <meta> declarations. This restriction exists because UTF-8 is a universal encoding that can represent virtually every character from every writing system, eliminating the interoperability problems that plagued the web when dozens of competing encodings were in use.
When the validator encounters content="text/html; charset=windows-1251" on a <meta> element, it flags it because the charset= portion must be followed by utf-8 — no other value is accepted. This applies whether you use the longer <meta http-equiv="Content-Type"> syntax or the shorter <meta charset> syntax.
Why this matters
- Standards compliance: The WHATWG HTML Living Standard explicitly requires utf-8 as the character encoding when declared in a <meta> tag. Non-conforming encodings will trigger validation errors.
- Internationalization: UTF-8 supports all Unicode characters, making your pages work correctly for users across all languages, including Cyrillic text that windows-1251 was originally designed for.
- Security: Legacy encodings can introduce security vulnerabilities, including certain cross-site scripting (XSS) attack vectors that exploit encoding ambiguity.
- Browser consistency: While browsers may still recognize legacy encodings, relying on them can cause mojibake (garbled text) when there’s a mismatch between the declared and actual encoding.
How to fix it
- Update the <meta> tag to declare utf-8 as the charset.
- Re-save your file in UTF-8 encoding using your text editor or IDE. Most modern editors support this — look for an encoding option in “Save As” or in the status bar.
- Verify your server configuration. If your server sends a Content-Type HTTP header with a different encoding, the server header takes precedence over the <meta> tag. Make sure both agree on UTF-8.
- Convert your content. If your text was originally written in windows-1251, you may need to convert it to UTF-8. Tools like iconv on the command line can help: iconv -f WINDOWS-1251 -t UTF-8 input.html > output.html.
Examples
❌ Incorrect: Using windows-1251 charset
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
✅ Correct: Using utf-8 with http-equiv syntax
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
✅ Correct: Using the shorter <meta charset> syntax (preferred in HTML5)
<meta charset="utf-8">
Full document example
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Пример страницы</title>
</head>
<body>
<p>Текст на русском языке в кодировке UTF-8.</p>
</body>
</html>
The shorter <meta charset="utf-8"> syntax is generally preferred in HTML5 documents because it’s more concise and achieves the same result. Whichever syntax you choose, place the charset declaration within the first 1024 bytes of your document — ideally as the very first element inside <head> — so browsers can detect the encoding as early as possible.
The HTML specification mandates that documents must be encoded in UTF-8. This requirement exists because UTF-8 is the universal character encoding that supports virtually every character from every writing system in the world. Older encodings like windows-1252, iso-8859-1, or shift_jis only support a limited subset of characters and can cause text to display incorrectly — showing garbled characters or question marks — especially for users in different locales or when content includes special symbols, accented letters, or emoji.
When the validator encounters charset=windows-1252 in your <meta> tag, it flags this as an error because the HTML living standard (WHATWG) explicitly states that the character encoding declaration must specify utf-8 as the encoding. This isn’t just a stylistic preference — browsers and other tools rely on this declaration to correctly interpret the bytes in your document. Using a non-UTF-8 encoding can lead to security vulnerabilities (such as encoding-based XSS attacks) and accessibility issues when assistive technologies misinterpret characters.
To fix this issue, take two steps:
- Update the <meta> tag to declare utf-8 as the charset.
- Re-save your file with UTF-8 encoding. Most modern code editors (VS Code, Sublime Text, etc.) let you choose the encoding when saving — look for an option like “Save with Encoding” or check the status bar for the current encoding. If your file was originally in windows-1252, simply changing the <meta> tag without re-encoding the file could cause existing special characters to display incorrectly.
The HTML spec also recommends using the shorter <meta charset="utf-8"> form rather than the longer <meta http-equiv="Content-Type" ...> pragma directive, as it’s simpler and achieves the same result. Either form is valid, but the charset declaration must appear within the first 1024 bytes of the document.
Examples
Incorrect: Using windows-1252 charset
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
This triggers the validator error because the charset is not utf-8.
Correct: Using the short charset declaration (recommended)
<meta charset="utf-8">
Correct: Using the http-equiv pragma directive with utf-8
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Full document example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Note that the <meta charset="utf-8"> tag should be the first element inside <head>, before any other elements (including <title>), so the browser knows the encoding before it starts parsing the rest of the document.
When you set user-scalable=no in your viewport meta tag, the browser completely disables pinch-to-zoom and other scaling gestures on mobile devices. Similarly, setting maximum-scale=1 (or any low value) caps how far a user can zoom in, effectively locking them out of enlarging content. While developers sometimes use these values to create an “app-like” experience or prevent layout issues during zoom, they directly violate accessibility best practices.
Why this is a problem
Accessibility
The Web Content Accessibility Guidelines (WCAG) Success Criterion 1.4.4 (Resize Text) requires that text can be resized up to 200% without loss of content or functionality. Preventing zoom makes it impossible for users with low vision, cognitive disabilities, or motor impairments to interact comfortably with your page. Many users depend on pinch-to-zoom as their primary way to read content on mobile devices.
Standards compliance
The W3C HTML Validator flags this as a warning because it conflicts with established accessibility standards. While it won’t cause your page to fail validation outright, it signals a practice that harms usability. Modern browsers and operating systems have also started to override restrictive viewport settings in some cases — for example, iOS Safari ignores user-scalable=no by default — which means the restriction may not even work as intended while still triggering warnings.
User experience
Even for users without disabilities, preventing zoom can be frustrating. Small text, dense layouts, or content that doesn’t quite fit a screen size can all benefit from the user being able to zoom in. Restricting this capability removes a fundamental browser feature that users expect.
How to fix it
- Remove user-scalable=no from your viewport meta tag. If present, either delete it or set it to yes.
- Remove or increase maximum-scale. If you need to set it, use a value of 5 or higher. Ideally, remove it entirely and let the browser handle zoom limits.
- Remove minimum-scale if it’s set to 1, as this can also restrict zoom behavior on some browsers when combined with other values.
- Test your layout at various zoom levels to ensure content reflows properly and remains usable.
Examples
❌ Viewport that prevents zooming
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
This completely disables user zoom on supporting browsers.
❌ Viewport with restrictive maximum-scale
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0">
This caps zoom at 100%, effectively preventing any meaningful zoom.
❌ Both restrictions combined
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
This is the most restrictive combination and is commonly seen in mobile-first frameworks and templates.
✅ Accessible viewport (recommended)
<meta name="viewport" content="width=device-width, initial-scale=1">
This sets a responsive viewport without restricting zoom at all. The browser’s default zoom behavior is preserved, and users can scale freely.
✅ Accessible viewport with a generous maximum-scale
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5">
If you have a specific reason to set maximum-scale, use a value of 5 or higher. This still allows substantial zoom while giving you some control over extreme zoom levels.
✅ Full document example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Accessible Page</title>
</head>
<body>
<h1>Welcome</h1>
<p>This page allows users to zoom freely.</p>
</body>
</html>
If your layout breaks when users zoom in, the solution is to fix the CSS — using relative units like em, rem, or percentages, and responsive design techniques — rather than disabling zoom. A well-built responsive layout should handle zoom gracefully without needing to restrict it.
The <meta> element provides metadata about the HTML document — information that isn’t displayed on the page but is used by browsers, search engines, and other web services. According to the HTML specification, a <meta> tag without any of the recognized attributes is meaningless. The validator flags this because a bare <meta> element (or one with only unrecognized attributes) provides no useful metadata and likely indicates an error or incomplete tag.
This issue commonly occurs when a <meta> tag is left empty by accident, when an attribute name is misspelled (e.g., naem instead of name), or when a required attribute is accidentally deleted during editing.
Most <meta> use cases fall into a few patterns, each requiring specific attribute combinations:
- charset — Used alone to declare the document’s character encoding.
- name + content — Used together to define named metadata like descriptions, viewport settings, or author information.
- http-equiv + content — Used together to simulate an HTTP response header.
- property + content — Used together for Open Graph and similar RDFa-based metadata.
- itemprop + content — Used together for microdata annotations.
Note that content alone is not sufficient — it must be paired with name, http-equiv, property, or itemprop to have meaning.
Examples
Incorrect: bare <meta> tag with no attributes
This triggers the validation error because the <meta> element has no recognized attributes:
<meta>
Incorrect: misspelled attribute
A typo in the attribute name means the validator doesn’t recognize it:
<meta nane="description" content="An example page.">
Incorrect: content without a pairing attribute
The content attribute alone is not enough — it needs name, http-equiv, property, or itemprop:
<meta content="some value">
Correct: character encoding with charset
<meta charset="UTF-8">
Correct: named metadata with name and content
<meta name="description" content="A brief description of the webpage.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="author" content="Jane Doe">
Correct: HTTP-equivalent with http-equiv and content
<meta http-equiv="X-UA-Compatible" content="IE=edge">
Correct: Open Graph metadata with property and content
<meta property="og:title" content="My Page Title">
<meta property="og:description" content="A summary of the page content.">
Correct: microdata with itemprop and content
<meta itemprop="name" content="Product Name">
Full document example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="A brief description of the webpage.">
<meta property="og:title" content="My Page Title">
<title>Example Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
How to fix
- Find the flagged <meta> tag in your HTML source at the line number the validator reports.
- Check for typos in attribute names — make sure name, charset, http-equiv, property, or itemprop is spelled correctly.
- Add the missing attribute. Determine what the <meta> tag is supposed to do and add the appropriate attribute(s). If you can’t determine its purpose, it may be safe to remove it entirely.
- Ensure proper pairing. If you’re using content, make sure it’s paired with name, http-equiv, property, or itemprop. The charset attribute is the only one that works on its own without content.
The <meta> element is used to provide metadata about an HTML document. According to the HTML specification, a <meta> element must serve a specific purpose, and that purpose is determined by its attributes. A bare <meta> tag or one with only a charset attribute in the wrong context will trigger this validation error.
There are several valid patterns for <meta> elements:
- name + content: Standard metadata pairs (e.g., description, viewport, author).
- http-equiv + content: Pragma directives that affect how the browser processes the page.
- charset: Declares the document’s character encoding (only valid once, in the <head>).
- itemprop + content: Microdata metadata, which can appear in both <head> and <body>.
- property + content: Used for Open Graph and RDFa metadata.
When a <meta> tag doesn’t match any of these valid patterns, the validator raises this error. The most common causes are:
- Forgetting the content attribute when using name or property.
- Using non-standard attributes without the required ones (e.g., only specifying a custom attribute).
- Placing a charset meta in the <body>, where it’s not valid.
- Typos in attribute names like contents instead of content.
This matters for standards compliance and can also affect SEO and social sharing. Search engines and social media crawlers rely on properly formed <meta> tags to extract page information. Malformed tags may be silently ignored, meaning your metadata won’t take effect.
Examples
Incorrect: <meta> with name but no content
<head>
<meta charset="utf-8">
<title>My Page</title>
<meta name="description">
</head>
The <meta name="description"> tag is missing its content attribute, so the validator reports the error.
Correct: <meta> with both name and content
<head>
<meta charset="utf-8">
<title>My Page</title>
<meta name="description" content="A brief description of the page.">
</head>
Incorrect: <meta> with property but no content
<head>
<meta charset="utf-8">
<title>My Page</title>
<meta property="og:title">
</head>
Correct: Open Graph <meta> with property and content
<head>
<meta charset="utf-8">
<title>My Page</title>
<meta property="og:title" content="My Page">
</head>
Incorrect: <meta> with only a non-standard attribute
<head>
<meta charset="utf-8">
<title>My Page</title>
<meta name="theme-color" value="#ff0000">
</head>
Here, value is not a valid attribute for <meta>. The correct attribute is content.
Correct: Using content instead of value
<head>
<meta charset="utf-8">
<title>My Page</title>
<meta name="theme-color" content="#ff0000">
</head>
Incorrect: Bare <meta> tag with no meaningful attributes
<head>
<meta charset="utf-8">
<title>My Page</title>
<meta>
</head>
A <meta> element with no attributes serves no purpose and should be removed entirely.
Correct: Using itemprop in the <body>
The itemprop attribute allows <meta> to be used within the <body> as part of microdata:
<body>
<div itemscope itemtype="https://schema.org/Product">
<span itemprop="name">Example Product</span>
<meta itemprop="sku" content="12345">
</div>
</body>
The <meta> element is used to provide machine-readable metadata about an HTML document, such as its description, character encoding, viewport settings, or social media information. The HTML specification defines several valid forms for <meta>, and most of them require a content attribute to supply the metadata’s value.
This error typically appears when a <meta> tag includes a name or http-equiv attribute but is missing the corresponding content attribute. It can also appear when a <meta> tag has no recognizable attributes at all, or when the property attribute (used by Open Graph / RDFa metadata) is present without content.
A <meta> element must use one of these valid attribute patterns:
- name + content — Named metadata (e.g., description, author, viewport)
- http-equiv + content — Pragma directives (e.g., refresh, content-type)
- charset — Character encoding declaration (no content needed)
- property + content — RDFa/Open Graph metadata (e.g., og:title)
- itemprop + content — Microdata metadata
Without the proper combination, browsers and search engines cannot correctly interpret the metadata, which can hurt SEO, accessibility, and proper page rendering. For example, a <meta name="description"> tag without content provides no description to search engines, and a <meta name="viewport"> without content won’t configure the viewport on mobile devices.
Examples
❌ Missing content attribute
<head>
<meta charset="utf-8">
<title>My Page</title>
<meta name="description">
<meta name="viewport">
</head>
Both <meta> tags with name are missing their required content attribute.
❌ Empty or bare <meta> tag
<head>
<meta charset="utf-8">
<title>My Page</title>
<meta>
</head>
A <meta> element with no attributes at all is invalid.
❌ Open Graph tag missing content
<head>
<meta charset="utf-8">
<title>My Page</title>
<meta property="og:title">
</head>
✅ Correct usage with name and content
<head>
<meta charset="utf-8">
<title>My Page</title>
<meta name="description" content="A brief description of the page">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
✅ Correct usage with http-equiv and content
<meta http-equiv="refresh" content="30">
✅ Correct usage with Open Graph property and content
<meta property="og:title" content="My Page Title">
<meta property="og:description" content="A description for social sharing">
✅ Correct charset declaration (no content needed)
<meta charset="utf-8">
The charset form is the one exception where content is not required, because the character encoding is specified directly in the charset attribute value.
How to fix
- Find the flagged <meta> tag in your HTML source at the line number reported by the validator.
- Determine what type of metadata it represents. Does it have a name, http-equiv, or property attribute?
- Add the missing content attribute with an appropriate value. If you intended the metadata to be empty, use content="", though it’s generally better to either provide a meaningful value or remove the tag entirely.
- If the <meta> tag has no attributes at all, decide what metadata you intended to provide and add the correct attribute combination, or remove the element.
The <meta> element is most commonly used inside the <head> section to define metadata like character encoding, viewport settings, or descriptions. Inside <head>, attributes like charset, http-equiv, and name are perfectly valid. However, the HTML specification also allows <meta> to appear inside the <body> — but only under specific conditions.
When a <meta> element appears in the <body>, it must have either an itemprop attribute (for microdata) or a property attribute (for RDFa). It must also have a content attribute. Additionally, it cannot use http-equiv, charset, or name attributes in this context. These rules exist because the only valid reason to place a <meta> tag in the <body> is to embed machine-readable metadata as part of a structured data annotation — not to define document-level metadata.
Why this matters
- Standards compliance: The HTML living standard explicitly restricts which attributes <meta> can use depending on its placement. Violating this produces invalid HTML.
- Browser behavior: Browsers may ignore or misinterpret <meta> elements that appear in the <body> without proper attributes. For example, a <meta http-equiv="content-type"> tag inside the <body> will have no effect on character encoding, since that must be determined before the body is parsed.
- SEO and structured data: Search engines rely on correctly structured microdata and RDFa. A <meta> element in the body without itemprop or property won’t contribute to any structured data and serves no useful purpose.
Common causes
- Misplaced <meta> tags: A <meta> element meant for the <head> (such as <meta http-equiv="..."> or <meta name="description">) has accidentally been placed inside the <body>. This can happen due to an unclosed <head> tag, a CMS inserting tags in the wrong location, or simply copying markup into the wrong section.
- Missing itemprop or property: A <meta> element inside the <body> is being used for structured data but is missing the required itemprop or property attribute.
Examples
Incorrect: <meta> with http-equiv inside the <body>
This <meta> tag belongs in the <head>, not the <body>:
<body>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<form>
<input type="text" name="q">
</form>
</body>
Fixed: Move the <meta> to the <head>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>My Page</title>
</head>
<body>
<form>
<input type="text" name="q">
</form>
</body>
Incorrect: <meta> in the <body> without itemprop or property
<div itemscope itemtype="https://schema.org/Offer">
<span itemprop="price">9.99</span>
<meta content="USD">
</div>
The <meta> element is missing the itemprop attribute, so the validator reports the error.
Fixed: Add the itemprop attribute
<div itemscope itemtype="https://schema.org/Offer">
<span itemprop="price">9.99</span>
<meta itemprop="priceCurrency" content="USD">
</div>
Correct: Using property for RDFa
The property attribute is also valid for <meta> elements in the <body> when using RDFa:
<div vocab="https://schema.org/" typeof="Event">
<span property="name">Concert</span>
<meta property="startDate" content="2025-08-15T19:00">
</div>
Incorrect: <meta name="..."> inside the <body>
The name attribute is only valid on <meta> elements inside the <head>:
<body>
<meta name="author" content="Jane Doe">
<p>Welcome to my site.</p>
</body>
Fixed: Move it to the <head>
<head>
<title>My Site</title>
<meta name="author" content="Jane Doe">
</head>
<body>
<p>Welcome to my site.</p>
</body>
The HTML living standard mandates UTF-8 as the only permitted character encoding for HTML documents. Legacy encodings like windows-1252, iso-8859-1, shift_jis, and others were common in older web pages, but they support only a limited subset of characters. UTF-8, on the other hand, can represent every character in the Unicode standard, making it universally compatible across languages and scripts.
This issue typically arises from one or more of these causes:
- Missing or incorrect <meta charset> declaration — Your document either lacks a charset declaration or explicitly declares a legacy encoding like <meta charset="windows-1252">.
- File not saved as UTF-8 — Even with the correct <meta> tag, if your text editor saves the file in a different encoding, characters may become garbled (mojibake).
- Server sends a conflicting Content-Type header — The HTTP Content-Type header can override the in-document charset declaration. If your server sends Content-Type: text/html; charset=windows-1252, the browser will use that encoding regardless of what the <meta> tag says.
Why This Matters
- Standards compliance: The WHATWG HTML living standard explicitly states that documents must be encoded in UTF-8. Using a legacy encoding makes your document non-conforming.
- Internationalization: Legacy encodings like windows-1252 only support a limited set of Western European characters. If your content ever includes characters outside that range—emoji, CJK characters, Cyrillic, Arabic, or even certain punctuation—they won’t render correctly.
- Security: Mixed or ambiguous encodings can lead to security vulnerabilities, including certain types of cross-site scripting (XSS) attacks that exploit encoding mismatches.
- Consistency: When the declared encoding doesn’t match the actual file encoding, browsers may misinterpret characters, leading to garbled text that’s difficult to debug.
How to Fix It
Step 1: Declare UTF-8 in your HTML
Add a <meta charset="utf-8"> tag as the first element inside <head>. It must appear within the first 1024 bytes of the document so browsers can detect it early.
Step 2: Save the file as UTF-8
In most modern text editors and IDEs, you can set the file encoding:
- VS Code: Click the encoding label in the bottom status bar and select “Save with Encoding” → “UTF-8”.
- Sublime Text: Go to File → Save with Encoding → UTF-8.
- Notepad++: Go to Encoding → Convert to UTF-8.
If your file already contains characters encoded in windows-1252, simply changing the declaration without re-encoding the file will cause those characters to display incorrectly. You need to convert the file’s actual encoding.
Step 3: Check your server configuration
If your server sends a charset parameter in the Content-Type HTTP header, make sure it specifies UTF-8. For example, in Apache you can add this to your .htaccess file:
AddDefaultCharset UTF-8
In Nginx, you can set it in your server block:
charset utf-8;
Examples
Incorrect: Legacy encoding declared
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="windows-1252">
<title>My Page</title>
</head>
<body>
<p>Hello world</p>
</body>
</html>
This triggers the error because windows-1252 is a legacy encoding.
Incorrect: Using the long-form http-equiv with a legacy encoding
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
This older syntax also triggers the error when it specifies a non-UTF-8 encoding.
Correct: UTF-8 declared properly
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello world</p>
</body>
</html>
The <meta charset="utf-8"> tag appears as the first child of <head>, and the file itself should be saved with UTF-8 encoding.
Correct: Using http-equiv with UTF-8
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
While the shorter <meta charset="utf-8"> form is preferred, this longer syntax is also valid as long as it specifies UTF-8.
According to the HTML specification, <meta> elements are metadata content and must appear within the <head> element. When a <meta> tag appears between </head> and <body>, browsers have to error-correct by either ignoring the element or silently relocating it into the head. This can lead to unpredictable behavior — for instance, a <meta charset="utf-8"> tag in the wrong position might not be processed in time, causing character encoding issues. Similarly, a misplaced <meta name="viewport"> could fail to apply on some browsers, breaking your responsive layout.
There are several common causes for this error:
- A <meta> tag accidentally placed after </head> — perhaps added hastily or through a copy-paste error.
- A duplicate <head> section — if a second <head> block appears in the document, the browser closes the first one implicitly, leaving orphaned <meta> elements in limbo.
- An unclosed element inside <head> — a tag like an unclosed <link> or <script> can confuse the parser, causing it to implicitly close </head> earlier than expected, which pushes subsequent <meta> tags outside the head.
- Template or CMS injection — content management systems or templating engines sometimes inject <meta> tags at incorrect positions in the document.
To fix the issue, inspect your HTML source and ensure every <meta> element is inside a single, properly structured <head> section. Also verify that no elements within <head> are unclosed or malformed, as this can cause the parser to end the head section prematurely.
Examples
Incorrect — <meta> between </head> and <body>
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
<meta charset="utf-8">
</head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<body>
<p>Hello, world!</p>
</body>
</html>
The <meta name="viewport"> tag is outside <head>, triggering the validation error.
Incorrect — duplicate <head> sections
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
<meta charset="utf-8">
</head>
<head>
<meta name="description" content="A sample page">
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
The second <head> block is invalid. The browser ignores it, leaving the <meta name="description"> element stranded between </head> and <body>.
Incorrect — unclosed element forces early head closure
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
<div>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
The <div> is not valid inside <head>, so the parser implicitly closes the head section when it encounters it. The subsequent <meta> tag ends up outside <head>.
Correct — all <meta> elements inside <head>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="A sample page">
<title>My Page</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
All <meta> elements are properly contained within a single <head> section. Note that <meta charset="utf-8"> should ideally be the very first element in <head> so the browser knows the encoding before processing any other content.
¿Listo para validar tus sitios?
Comienza tu prueba gratuita hoy.