SEO check

HTML Frameset: What It Is and Why It Fails an SEO Check

Frames split a page into separate documents that browsers and crawlers handle poorly. Learn how to spot them and swap in modern HTML and CSS.

Free to use 7 min read Updated Oct 2026

What is an HTML frameset and why does it fail an SEO check?

Quick answer: An HTML frameset replaces the body of a page with a grid of frames, and each frame loads a separate HTML document. The HTML standard marks the feature obsolete, so our report fails any page whose rendered DOM still contains a frame or frameset element. Plain iframe elements are never counted.

  • Pass: zero frame or frameset elements in the rendered page.
  • Fail: one or more of them in the rendered page.
  • Fix: rebuild the layout with CSS Grid or Flexbox and move repeated parts into shared templates.

Check my website

The scan is free and needs no sign up.

What is the HTML frameset tag and how does it work?

A frameset document has a head like any other page, but a frameset element sits where the body would normally be and cuts the window into a grid of cells. Each cell is a frame tag whose src attribute loads a separate HTML file, so one visible page is really several documents.

Give a frame a name attribute and a link can use its target attribute to load pages into that cell, which is how the classic fixed menu worked. The frameborder attribute, noresize and scrolling controlled borders, dragging and scrollbars. The noframes tag held fallback markup for browsers without frame support, and was never meant to carry your real page content.

HTML
<frameset cols="25%,75%">
  <frame src="menu.html" name="menu">
  <frame src="article.html" name="main">
  <noframes><body><p>This site needs frames.</p></body></noframes>
</frameset>

The format comes from HTML 4.01 and its Frameset DTD (XHTML 1.0 had a Frameset variant too), announced by a doctype of its own:

HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">

A current page uses the short <!DOCTYPE html>, which our HTML doctype check explains. The W3C's HTML 4.01 frames specification is the primary source for the attributes above.

rows, cols and relative lengths

The cols attribute makes vertical columns and rows makes horizontal bands. A value of 25%,75% gives each cell a share of the window. A value of 200,* fixes the first column at 200 pixels and hands everything left to the second. Relative lengths such as 1*,2* split the space in proportion, so the second cell is twice the first.

Is the HTML frameset tag still valid in HTML5?

Standards wording: No. The HTML Living Standard, maintained by the WHATWG, lists frame, frameset and noframes among its obsolete HTML elements and tells authors never to use them. Validators report such pages as non-conforming HTML.

The same section names the replacements: an iframe element together with CSS, or server side includes that merge the repeated parts of a site into complete pages. The HTML obsolete features list is short enough to scan.

People often search for "frameset not supported in HTML5". The accurate version is that frames are obsolete in HTML5, and references such as MDN describe them as deprecated in HTML5, not that browsers refuse them. Browsers still draw old framesets for compatibility, but the W3C validator flags the page as non-conforming. Tags such as font, center and marquee fall under a separate test, see our deprecated HTML tags check if your report lists those.

Why do HTML frames hurt SEO and usability?

The root problem is one URL for many documents. The address bar keeps showing the frameset address while the visitor reads a page stored at a different URL, so bookmarking framed pages, sharing and copying the link all point at the wrapper instead of the page they care about.

Frames are not an automatic penalty, because Googlebot can often fetch and render them and framed content can end up indexed. You get weak structure and lost context.

What search engines see

The crawlable wrapper is a thin frameset page: a few frame tags and maybe a noframes line. Googlebot finds each frame source as its own URL, so links to the content pages count for those pages, not for the wrapper address people share. The URL Inspection tool in Google Search Console shows what Google rendered, and our post on how Google crawls pages gives the wider background.

What visitors experience

A searcher who clicks a result may land on article.html. The text is there, but the navigation frame is missing, so the visitor has no menu and no route into the site. Most leave. Our guide to SEO friendly URLs covers what each page should expose on its own address.

The Back button behaves oddly too: a visitor clicks Back inside a content frame, only that pane rewinds, and they decide the site is stuck. Printing can produce the wrong pane, and on small screens each frame scrolls on its own. WCAG technique H64 recommends a title attribute on every frame and iframe so a screen reader can announce it.

How does the SEO Site Checker frameset test work?

Our engine opens your URL in headless Chromium, waits for the load event and parses the rendered DOM with BeautifulSoup. Frames that scripts insert before the load event finishes are counted. It is a single row in the Advance section.

The exact rule: the check counts every frame and frameset element in the rendered Document Object Model. Zero is a pass, one or more is a fail, and there is no warning level.

Pass and fail rules

The number shown is a count of elements, not of framed pages. A classic frameset with two frames reports 3, and a nested frameset layout with two framesets and three frames reports 5. Escaped code samples and comments are ignored.

When the page passes, you see a green Congratulations message. A fail shows "This webpage uses frames." with a red How to Fix button, and it counts as one failed check in the summary and the score percentage.

  • Pass: no frame or frameset element in the rendered DOM.
  • Fail: at least one such element in the rendered DOM.
  • Not tested: iframe elements (never counted, even inside a frameset page), other URLs on your site, frames added after the load event, whether engines index framed content, and HTML validity in general.

Scenarios we ran through the check

We ran the same logic against local test pages. One result looks odd: a frameset written inside a body element passes, because the browser parser discards it first, so the rendered DOM wins over the source text.

ScenarioResultElements counted
Classic page with a frameset and two framesFail3
Nested layout, two framesets and three framesFail5
Normal page with an iframe onlyPass0
Frameset written inside a body elementPass0
Frame element added by JavaScriptFail1
Frameset built by script through the DOMFail3
Escaped code sample or commentPass0

The test reads only the URL you submitted, so run key templates separately.

Run the free report

How can I tell if my page uses a frameset?

Four quick checks work, and the third catches frames added by scripts.

  1. Run the report. Open the Advance section and read the Framesets row.
  2. View page source. Look for a frameset element where the body should be, or use the one line command below for static HTML.
  3. Search the live DOM. In the DevTools Elements panel, press Ctrl+F and search for frameset and for "<frame " to catch markup added after load.
  4. Open a deep content URL on its own. If the site menu is missing, the site depends on a surrounding frame.
Text
curl -sL https://example.com/ | grep -iE '<frame(set)?[[:space:]>]'

That command reads only static HTML and misses a tag split across lines, so a clean result does not rule out frames that scripts add. A match inside a comment or script string is a false alarm; the DevTools search settles it.

How to replace a frameset with HTML and CSS

  1. List every frame and its job. Note which is a menu, header, footer, content area or outside embed.
  2. Move shared pieces into a template. Static sites can use server side includes, a PHP include or a build step; CMS sites use the theme layout.
  3. Build one normal document. For menu plus content, use a CSS Grid or Flexbox layout with a sticky menu, and set overflow: auto on the content area only if it must scroll alone.
  4. Turn frame links into plain links. Every link with a target attribute (such as target="main") should become a plain link to a complete page with its own title, meta description and H1.
  5. Plan your URLs. Keep the frameset file's URL for the new page and keep the addresses of real content pages. Menu, header and footer fragments move into the template and their old files get a 301 or removal.
  6. Use iframe sparingly. For another site or a widget, use an iframe with a descriptive title attribute, never for your own navigation.

Two column layout with CSS Grid

This is the after picture for the menu plus content example: a two column grid with a sticky nav on wide screens. The media query stacks everything on narrow ones and releases the sticky, full height menu, or it would fill a phone screen and cover the content.

HTML
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
  .layout { display: grid; grid-template-columns: 240px 1fr; }
  .menu { position: sticky; top: 0; align-self: start; height: 100vh; overflow: auto; }
  @media (max-width: 700px) { .layout { display: block; } .menu { position: static; height: auto; } }
</style>
<div class="layout"><nav class="menu">...</nav><main>...</main></div>

Preview the layout in the free online HTML viewer before you publish it.

Share the menu with a server side include

Once the menu has its own file, every page pulls it in with one line:

HTML
<!--#include virtual="/includes/menu.html" -->

Apache needs mod_include enabled, Options +Includes for the directory and an output filter such as AddOutputFilter INCLUDES .html if you want to keep your .html addresses. Renaming pages to .shtml or .php changes every address, so each old one needs a 301; a build step that writes plain .html files avoids that. Nginx needs ssi on; in the matching location block.

Keep URLs and redirects tidy

The frameset file is usually your home page or a section index, so replace it at its existing address. Content pages keep their addresses, and any that must move get a single 301 hop to the page that now holds the content. Menu, header and footer fragments belong in the template, so 301 their old files or remove them, since left live they become thin, indexable stubs. Then build a fresh file with the XML sitemap generator, so it lists real page addresses, not the old wrapper.

Frameset problems on WordPress, Wix, Shopify and masked domains

A common outside cause is masked domain forwarding, also called URL masking or frame forwarding. Some registrars show your site inside a frame so the address bar stays on the forwarding domain. Depending on the provider, the wrapper is a frameset, which fails this check, or an iframe, which is not flagged but has the same drawbacks. Switch to a 301 redirect or point DNS at your host.

Google's Search Central crawling and indexing FAQ says forwarding through frames generally makes crawling, indexing and ranking under your own domain impossible. If your own server sends X-Frame-Options: DENY or SAMEORIGIN, or a frame-ancestors rule that excludes the registrar, browsers refuse to show it inside the wrapper and the masked address loads blank.

Wix, Shopify and current WordPress themes do not output framesets by default, so expect an old template, a legacy plugin or an outside wrapper.

  • WordPress. View the source to confirm the frameset is really in the HTML, then search the files, for example grep -ril "<frameset" wp-content. Failing that, switch to a default theme and deactivate plugins one at a time to see which one prints it. Likely culprits are a template printing a whole document without a normal body, a plugin serving a standalone frameset page, or plugin JavaScript creating frames.
  • Shopify. Open Online Store, then Themes, then Edit code, and search theme.liquid and the other templates for frameset.
  • Wix. Check the Custom Code area in your site settings and any Embed HTML elements.

Frameset vs iframe vs CSS layout: which one is acceptable?

The MDN frameset reference marks the element deprecated and says that to embed one HTML page inside another, you should use iframe.

OptionStatusBest useFlagged by our report
Frameset and frameObsoleteNothing new, migrate awayYes
iframeValid HTMLMaps, videos and outside content, with a title attributeNo
CSS Grid or FlexboxPreferredResponsive layout that is fully crawlableNo
Templates or server side includesPreferredRepeated header, menu and footerNo

Search engines generally associate iframe content with the framed URL, not the host page, so an iframe suits maps and videos, not your own articles or menu.

Common mistakes when removing frames

  • Wrapping the old site in one big iframe. It passes this check but keeps every old problem.
  • Leaving noframes as the only readable text. If a noframes block holds the only readable copy of your content, crawlers get a stub, so move that text into the real page body.
  • Rebuilding with nested tables. That swaps one old habit for another and trips a different check: our nested tables check.
  • Forgetting titles and descriptions. Former bare content documents now need their own title, meta description and H1.
  • Keeping masked forwarding on. The registrar can wrap your fixed site in a frame again.

Frameset free page checklist

  • A real body. The page has a body and no frame or frameset element.
  • Shared parts from a template. Menu, header and footer come from an include or theme, not a frame.
  • One identity per page. Each page has its own URL, title, meta description and H1.
  • Careful iframes. Any iframe holds outside content and has a title.
  • Final URLs everywhere. Sitemap and internal links use the final addresses. For the wider audit, use our technical SEO checklist.

How to Fix

The short version, the same steps you see when you click How to Fix in your report.

Why this fails: the page you tested contains a frame or frameset element, which splits the window into separate documents. The HTML standard marks these obsolete, and they mean one URL for several documents. An iframe is not what failed.

How to fix it:

  1. List each frame and its job.
  2. Move the menu, header and footer into a shared template.
  3. Build one document with a body and lay it out with CSS Grid or Flexbox.
  4. Change every link that uses a target attribute (such as target="main") into a plain link to a full page with its own title and description.
  5. Replace the frameset page with the new document at the same URL and remove any noframes block. Content pages keep their addresses; old menu and header files get a 301 to the home page or are removed.
HTML
<meta name="viewport" content="width=device-width, initial-scale=1">
<div class="layout">
  <nav class="menu">...</nav>
  <main>...</main>
</div>
<style>
  .layout { display: grid; grid-template-columns: 240px 1fr; }
  @media (max-width: 700px) { .layout { display: block; } }
</style>

To check static HTML, run this and expect nothing (a match inside a comment or script string is a false alarm, and scripts can still add frames, so also search the live page in DevTools):

Text
curl -sL https://example.com/ | grep -iE '<frame(set)?[[:space:]>]'

For outside content, use an iframe with a title:

HTML
<iframe src="https://example.com/widget" title="Store locator map"></iframe>
  • Static HTML: move the shared menu and footer into server side includes, a PHP include or a build step.
  • WordPress: search the theme and plugin folders for frameset, test with a default theme, or deactivate plugins one at a time.
  • Masked domain forwarding: replace the masked forward with a 301 redirect, or point DNS straight at the host.
  • Wix and Shopify: check Custom Code and Embed HTML in Wix, and theme.liquid plus apps in Shopify.

Background reading: what the HTML standard says.

Re-test: view the page source and confirm there is a body and no frame or frameset tag, then run our free report again and look for the green Framesets result.

Re-test my website

Frequently Asked Questions

What is a frameset in HTML?
A frameset is the element that takes the place of the body in an old style page and splits the browser window into frames, each loading its own HTML file. Its rows and cols attributes define the grid. The HTML standard now lists it as obsolete, so new pages should not use it.
What is the difference between frame and frameset in HTML?
The frameset is the container that defines the grid of rows and columns. Each frame inside it is one cell pointing to a separate document through its src attribute, and a frame cannot stand alone in a normal page. Our report counts both elements when it finds them in the rendered DOM.
Are HTML frames obsolete?
Yes. The HTML standard lists frame, frameset and noframes among its obsolete elements, and validators report them as non-conforming. Browsers keep drawing old framesets so legacy sites still work, but new pages should rely on CSS layout and shared templates, with iframe saved for real embeds such as maps or videos.
Do frames hurt SEO?
They are a structural weakness more than a penalty. The frameset page holds almost no text, the real content sits on separate URLs, and a searcher can land on one with no menu around it. Ranking signals may also split between the pieces. One complete document per page removes the issue.
What is the difference between a frameset and an iframe?
A frameset takes over the whole window and replaces the body, while an iframe is one box placed inside an otherwise normal page. Iframe is valid HTML, and our check does not flag it. Use it for outside content such as a map, never for your own navigation.
How do I replace a frameset in HTML5?
Move the repeated menu, header and footer into a template or include, then lay the page out with CSS Grid or Flexbox. Replace the frameset file at its existing URL with the new document, point menu links at complete pages with their own titles, and give moved frame sources a 301. Use iframe only for outside content.
Can Google index content inside frames?
Sometimes, but not reliably. Google can often find the frame source URLs and index them as separate pages, yet nothing keeps those pieces connected to the menu or to each other. Its Search Central crawling FAQ also says forwarding built on frames generally prevents crawling, indexing and ranking under your own domain.
How do I know if my page uses a frameset?
Run the free report and read the Framesets row in the Advance section. You can also view the page source and search for frameset and frame, then search the live page in your browser DevTools Elements panel, which catches frames that scripts add after loading.

See how your site scores right now

Paste your address into the free report, then use the How to Fix button on anything that needs work.

Free to use. Results in under a minute for most sites.