In the early days of the web, HTML was a very simple markup language, primarily designed for structuring academic documents. As the web grew, creators and businesses wanted more sophisticated layouts, but the tools to create them were limited. HTML frames were introduced as a solution to this problem. The core idea of frames is to divide a single web page into multiple, independent sections. Each section, or “frame,” is capable of displaying a different HTML document. This allows developers to show different web pages simultaneously within a single browser window, creating a more complex and seemingly interactive user experience.
A Practical Example of Frames
To understand this concept more clearly, let us use the source article’s example of a bookstore website. In the mid-1990s, using frames was a very popular way to build such a site. You could use a frameset to create a persistent layout. The browser window might be divided into three distinct parts. One frame at the top would be a “Top Frame.” This section would be static and always display the bookstore’s logo and the main navigation menu, such as “Home,” “About,” and “Contact.” This frame would never change, no matter where the user navigated on the site.
Another frame would be on the left-hand side. This “Left Frame” would act as a sidebar, showing a list of book categories like “Fiction,” “Non-Fiction,” and “Children’s Books.” When a user clicked on one of these categories, the link would target the main content area. This “Main Frame,” which would take up the largest part of the screen, is where the content would change. It would initially display a welcome message, but when a user clicked “Fiction,” this frame would load and display the list of fiction books.
This layout felt advanced at the time. A user could browse dozens of pages, and only the main content area would refresh. The logo and navigation would remain perfectly still. You could even add a fourth “Bottom Frame” that would permanently display copyright information, contact details, or other footer-style content. Each of these frames loaded a separate HTML file, but they were all coordinated within one main “frameset” document to create a single, cohesive webpage, allowing users to navigate through different sections seamlessly.
The Two Types of Frames
When discussing “frames” in HTML, it is critical to understand that the term historically refers to two different technologies. The first, and the one we have just described, is the <frameset>. This is a (now obsolete) collection of tags, primarily <frameset> and <frame>, that are used to define the entire layout of the browser window. A special frameset HTML document does not use a <body> tag. Instead, it uses a <frameset> tag to partition the window into rows and columns, with each partition loading a separate HTML document.
The second, and much more modern, technology is the <iframe> or “inline frame.” An iframe is not meant to define the entire layout of a webpage. Instead, it is a regular HTML element, much like an <img> or <p> tag, that you place inside your normal <body> content. An iframe’s purpose is to embed an entirely separate, external webpage within a specific area of your current page. While framesets are no longer used in modern web design, iframes are used every day for things like embedding videos, maps, and advertisements.
The Original Philosophy Behind Framesets
The introduction of framesets, primarily by Netscape in 1996, was revolutionary because it changed the fundamental “page-to-page” navigation model of the web. Before frames, clicking a link meant the entire browser window would go blank and then reload a completely new page. This was a jarring user experience. Framesets allowed web designers to create an “application-like” interface. By keeping the navigation and branding persistent, only the necessary content would update. This made websites feel faster, more stable, and more like a desktop software program.
This approach was a clever solution to the limitations of HTML at the time. There was no practical CSS for layout. Developers were stuck using HTML <table> tags to try and arrange content, which was a clumsy and semantically incorrect method. Frames provided a powerful and (at the time) clean way to achieve a multi-column, persistent layout. This is why they were so rapidly adopted and became a hallmark of web design in the late 1990s. The entire concept was built around the idea of a “master page” that controlled and organized other, smaller, content-focused pages.
Understanding the Frameset Layout
A frameset HTML document has a unique structure. A regular, standard HTML document includes a <head> section for metadata and a <body> section for the visible content. A frameset document, however, includes a <head> section but replaces the <body> section entirely. In its place, it uses a <frameset> section. This fundamental difference is because the frameset document itself displays no content. Its only job is to be a container, to define the layout and organization of the other frames that will be displayed in the main browser window.
The <frameset> section defines how the window is split, either into horizontal rows or vertical columns. These splits can then be nested. For example, you could split the window into two horizontal rows. Then, you could replace the second row with another frameset, which itself is split into two vertical columns. This nesting capability allowed for highly complex and granular layouts. The <frame> tag was then used to specify which HTML document to load into each of these newly created partitions, turning a blank browser into a complex, multi-paned dashboard.
The Role of the <noframes> Tag
The creators of the frameset technology understood that this was a new and not universally supported feature. What would happen if a user visited a frameset-based site with an old browser that did not understand the <frameset> tag? The user would see a completely blank white page, as the browser would ignore the unknown <frameset> tag and find no <body> tag to render. To solve this, the <noframes> element was introduced. Developers would place a <noframes> tag inside the <frameset> section.
Inside the <noframes> tag, they would typically include a basic <body> section. This body content would provide an alternative for browsers that did not support frames or for users who had explicitly disabled frames. This content usually said something like, “This site uses frames, which your browser does not support,” and would then provide a list of simple links to the individual pages. This tag was also critical for early search engines, which, like a simple browser, could not understand or navigate the frameset structure. The <noframes> content was often the only part of the site a search engine could index.
The Problems Frames Aimed to Solve
The core problem was state. Every time a user clicked a link, the entire “state” of the page was lost and a new one was loaded. Imagine a music player website. Without frames, if a user was playing a song and clicked a link to read an artist’s biography, the music would stop as the new page loaded. Frames offered a solution. The music player could live in a small, persistent frame. The user could then browse the rest of the site in the main content frame, and the music player frame would be unaffected, continuing to play the song.
Another problem was code duplication and maintenance. Before frames, if you wanted a navigation menu on every page of your 100-page website, you had to physically copy and paste the same menu HTML code into all 100 HTML files. If you needed to change one link in that menu, you had to manually edit all 100 files. Frames solved this. You would create the menu just once in its own menu.html file. The frameset would then load this single file into the navigation frame. To update the menu, you only had to edit that one file, and the change would instantly appear on the entire site.
Early Implementations of Frames
The practical implementation of framesets required developers to think about their website as a collection of separate, smaller documents rather than a series of large, monolithic pages. A typical site might consist of index.html (the master frameset document), header.html (for the top frame), menu.html (for the left frame), and main.html (as the default content). The index.html file itself would be very small, containing just the <head> and the <frameset> definitions. It was the blueprint for assembling the other pieces.
Developers would then use the name attribute on each <frame> tag to identify them. For example, the main content frame would be given a name like “content_frame”. Then, in the menu.html file, all the hyperlinks would use the target attribute. A link would look like <a href=”fiction.html” target=”content_frame”>Fiction</a>. This target attribute told the browser to load the fiction.html document not in the current (menu) frame, but in the frame named “content_frame”. This “targeting” was the key mechanism that made the whole system work.
The Difference Between <frameset> and <iframe>
It is important to end this introductory part by reinforcing the distinction between the two frame types. The <frameset> is a page layout technology. It is all-encompassing, taking over the entire browser window and dictating its structure. It is now considered obsolete, meaning modern web browsers still support it for legacy reasons, but it is not part of the current HTML5 standard and should not be used for new projects. All of the problems it solved, such as code reuse and layout, are now handled far more effectively by modern technologies like CSS (Flexbox, Grid) and server-side includes or JavaScript frameworks.
The <iframe>, on the other hand, is an embedding technology. It is a standard, fully supported HTML5 element. Its purpose is not to create your site’s layout but to “punch a hole” in your existing page to display a piece of external content. This is incredibly useful for modern, component-based web design. When you embed a YouTube video, a Google Map, a social media post, or a third-party advertisement, you are almost always using an iframe. It safely isolates this external content from your own page. The rest of this series will explore both technologies in detail.
Understanding the Frameset Document
A frameset HTML document is a special type of file that serves as the master blueprint for a framed website. Its structure is fundamentally different from a standard HTML page. A regular HTML document has a <head> and a <body>. The <body> tag contains all the visible content. A frameset document, however, must not contain a <body> tag. Instead, it contains a <frameset> tag. If you include a <body> tag, the browser will ignore the <frameset>. This is because the frameset document itself is not meant to be visible; it is only a container that defines the sections of the window.
The DOCTYPE declaration for a frameset document was also different. To be valid, a page using framesets had to declare this in its HTML. Developers had to use a specific DTD (Document Type Definition) that told validating parsers and browsers that this document would be using frames. For example, the HTML 4.01 DTD for this was “HTML 4.01 Frameset.” This distinction was important for browsers to correctly interpret the page’s unique structure and to render the frames as intended, rather than trying to find a <body> that did not exist.
The <frameset> Tag Attributes
The <frameset> tag is the primary container that defines the rows and columns. It has several key attributes to control the layout. The two most important are rows and cols. You can only use one of these attributes on a single <frameset> tag. If you want to divide the page both horizontally and vertically, you must use nested <frameset> tags. For example, your main <frameset> could define the rows, and then the second row could be replaced by another <frameset> tag that defines the cols for that section.
Other attributes control the appearance of the frames. The border attribute specifies the thickness of the border between all frames, in pixels. The frameborder attribute, confusingly, is a simple on/off switch, where 1 (default) means “show borders” and 0 means “hide borders.” The framespacing attribute was a Microsoft-specific addition that added extra space between frames, also in pixels. These attributes allowed developers to either visually separate the frames or blend them together to create a more seamless-looking layout.
Defining Layout with the ‘rows’ Attribute
The rows attribute is used to divide the browser window into horizontal frames. The value of this attribute is a comma-separated list that defines the size of each row. You can define these sizes in three different ways. The first and most common way is using percentages. For example, rows=”20%,60%,20%” would create three horizontal frames, where the top and bottom frames each take up 20% of the window’s height, and the middle frame takes up 60%.
The second method is using a fixed number of pixels. For instance, rows=”100, *” would create two rows. The top row is a fixed 100 pixels high, perfect for a banner. The * is a wildcard character that means “use all the remaining space.” This is the third method, relative sizing. You can use multiple wildcards. For example, rows=”100, 2*, *” would create three rows. The top is 100 pixels, and the remaining space is divided into two, with the middle row being twice as tall as the bottom row.
Defining Layout with the ‘cols’ Attribute
The cols attribute works exactly like the rows attribute, but it divides the window into vertical frames (columns) instead. The value is a comma-separated list defining the width of each column. Just like rows, you can use percentages, fixed pixels, or relative wildcard values. A common layout for a website might be cols=”200, *”. This would create two vertical frames. The left frame would be a fixed 200 pixels wide, ideal for a navigation menu. The right frame would take the * wildcard and expand to fill the rest of the browser window’s width.
If you wanted a classic three-column layout, you could use cols=”25%, 50%, 25%”. This would create a main central content area with two smaller sidebars on either side. The flexibility of mixing and matching these value types was the primary strength of the frameset system. A developer could create a pixel-perfect header and navigation bar while allowing the main content area to be flexible and resize with the user’s browser window.
The <frame> Tag and its ‘src’ Attribute
Inside the <frameset> tag, you do not add content. Instead, for each row or column you have defined, you must add a <frame> tag. The number of <frame> tags must match the number of partitions you created. If your <frameset> defines rows=”50%,50%”, you must include two <frame> tags. The <frame> tag is an empty element, like an <img> tag. Its most important attribute is src, which stands for “source.” The src attribute specifies the URL of the HTML document that should be loaded into that specific frame.
For our bookstore example with a top banner and a left menu, the master frameset document might look like this: <frameset rows=”100, *”> <frame src=”top.html”> <frameset cols=”200, *”> <frame src=”menu.html”> <frame src=”main.html”> </frameset> </frameset>. This nested structure first creates a 100px top row and loads top.html into it. Then, it divides the remaining space into two columns and loads menu.html and main.html into them.
Controlling Frames with the ‘name’ Attribute
The src attribute defines the initial content of a frame, but the name attribute is what makes the frameset interactive. The name attribute gives a specific frame a unique identifier. For example, in our bookstore site, the <frame> tag for the main content area would be given a name like <frame src=”main.html” name=”content_area”>. This name acts as a target for hyperlinks. Without it, clicking a link in one frame would only change the content of that same frame, which is not what you want for a menu.
In the menu.html document, the hyperlinks would then use the target attribute. A link would be written as <a href=”fiction.html” target=”content_area”>Fiction</a>. When a user clicks this link, the target attribute tells the browser not to load fiction.html in the current frame (the menu). Instead, it instructs the browser to find the frame named “content_area” and load the new page there. This mechanism was the magic that allowed the navigation to remain static while the main content updated.
Controlling Frame Behavior
The <frame> tag also had attributes to control its behavior and appearance. One of the most common was noresize. By default, users could click and drag the borders between frames to resize them. If you had a 100px top banner, you probably did not want the user to be able to resize it. By adding the noresize attribute (<frame src=”top.html” noresize>), you would lock the frame’s border in place, preventing the user from changing its size.
Another key attribute was scrolling. This attribute controlled whether scrollbars would appear if the content inside the frame was larger than the frame itself. The value could be set to yes, no, or auto. Setting scrolling=”yes” would force scrollbars to always be visible, even if they were not needed. Setting scrolling=”no” would permanently disable scrollbars, which could make content inaccessible if it was too large. The default and most common-sense value was auto, which would make scrollbars appear only if the content overflowed the frame’s dimensions.
Controlling Frame Appearance
In addition to the border and frameborder attributes on the parent <frameset>, the individual <frame> tag also had attributes to control its appearance. The marginwidth and marginheight attributes allowed a developer to add a buffer of space, in pixels, inside the frame. marginwidth controlled the space on the left and right, while marginheight controlled the space on the top and bottom. This was useful for preventing content from touching the very edge of the frame, giving it some “breathing room.”
These attributes, along with the <frameset>’s border attributes, gave developers a good amount of control over the look and feel of the layout. By setting frameborder=”0″ and border=”0″ on the <frameset>, and then carefully managing the margins within each frame, developers could create the illusion of a single, seamless page, even though it was assembled from many different documents. This was a common technique for trying to hide the fact that frames were being used.
The <noframes> Fallback Tag
As mentioned in Part 1, the <noframes> tag was the essential fallback for browsers that did not support frames. Any content placed inside a <noframes>…</noframes> block would be completely ignored by a frames-capable browser. However, a non-frames browser would ignore the <frameset> and <frame> tags and would instead render the content inside the <noframes> tag. This was the only way to provide a usable experience for all users.
Typically, the <noframes> section would contain a full <body> element. Inside this body, the developer would provide a message and, most importantly, a simple list of hyperlinks to the core pages of the site (top.html, menu.html, main.html, etc.). This was also critical for accessibility. Screen readers for visually impaired users had immense difficulty navigating framesets, so the <noframes> content was often the only way they could access the site. It also provided the only content that early search engine crawlers could index.
What Is an ‘iframe’?
The <iframe> tag, which stands for “inline frame,” is the modern and fully supported HTML element for embedding one HTML document inside another. It is crucial to distinguish this from the obsolete <frameset> tag. A <frameset> was a layout mechanism that took over the entire browser window and defined its partitions. An <iframe> is a regular HTML element, just like an image (<img>) or a paragraph (<p>). You place an <iframe> inside the <body> of your webpage, and it “punches a hole” in your page to display another webpage inside it.
This fundamental difference means the <iframe> is not a layout tool. You do not use iframes to create your website’s header, footer, and sidebars. You use modern CSS (like Flexbox or Grid) for that. Instead, you use an iframe for its intended purpose: to embed a piece of external, third-party content into a designated spot within your layout. This is why iframes are not obsolete and are a vital part of the modern web. They provide a necessary and secure way to include content that you do not control.
Basic iframe Implementation
Implementing an iframe is very simple. It is a single tag with a few key attributes. The most important attribute is src, just like the <frame> or <img> tag. The src attribute specifies the URL of the document you want to embed. For example, <iframe src=”external.html”></iframe>. This will embed the document external.html into your page at the location where you placed the tag. By default, the iframe may appear as a small box, so you must add width and height attributes to give it a proper size.
For example, <iframe src=”advertisement.html” width=”300″ height=”250″></iframe> would create a 300-pixel by 250-pixel rectangle on your page, which is a standard ad size, and load the advertisement.html document inside it. The content between the opening <iframe> and closing </iframe> tags acts as fallback content. If a user’s browser is extremely old and does not support iframes, it will display this content instead. For example: <iframe src=”map.html”>Your browser does not support iframes. Please <a href=”map.html”>visit this link</a> to see the map.</iframe>.
Controlling iframe Appearance
Like a <frame>, an iframe has attributes to control its appearance. The width and height attributes are the most common, setting the dimensions of the inline frame in pixels. You can also use percentages, for example, width=”100%”, to make the iframe responsive to the width of its container. The frameborder attribute also exists, with 1 (default) showing a border and 0 hiding it. However, in modern HTML5, the frameborder attribute is obsolete. The correct, modern way to control the border is by using CSS.
For example, a modern iframe should be styled like this: <iframe src=”video.html” style=”border: none;”></iframe>. This CSS border: none; property is the recommended way to remove the default border. You can use CSS to control every aspect of the iframe’s box model, including its margin, padding, and border-radius, just like any other element on your page. This makes it far more flexible and better integrated with modern design practices than the old <frameset> attributes.
Controlling iframe Behavior
The iframe tag also has attributes to control its behavior. The scrolling attribute, just like with <frame>, controls the scrollbars. The values are yes, no, and auto (the default). Setting scrolling=”no” is generally bad for accessibility, as it may hide content if the embedded page is larger than the iframe dimensions. The name attribute also exists and functions similarly. It gives the iframe a name so that it can be targeted by hyperlinks (<a target=”iframe_name”>) or form submissions.
A more modern and very important behavioral attribute is loading. This attribute is a huge win for web performance. It can be set to lazy. When you set loading=”lazy”, you are telling the browser not to load the content of the iframe until the user scrolls down the page and the iframe is about to enter the viewport. This is incredibly useful for embedding things like YouTube videos or maps that are at the bottom of a long page. It makes your initial page load much faster because the browser does not waste time and bandwidth loading these heavy, off-screen resources.
The ‘srcdoc’ Attribute
A less common but very interesting iframe attribute is srcdoc. Instead of using the src attribute to point to an external URL, the srcdoc attribute allows you to provide the entire HTML content for the iframe directly within the attribute itself. This is useful for embedding simple, self-contained snippets of HTML that you want to be sandboxed from the rest of your page. For example: <iframe srcdoc=”<p>This is a sandboxed paragraph.</p>”></iframe>. The browser will parse this string of HTML and render it inside the iframe.
This is powerful because the iframe still provides its security isolation. Even though the HTML is coming from your own attribute, it is treated as a separate document. This is useful if you are building a tool like a code editor and want to safely render a preview of user-submitted HTML without it affecting your main application. However, if you provide both a src and a srcdoc attribute, the srcdoc attribute will take precedence. The src attribute will only be used as a fallback for old browsers that do not support srcdoc.
The ‘allow’ Attribute
In the modern web, privacy and security are paramount. Many powerful browser features, like accessing the camera, microphone, or user’s location, are now restricted. An iframe adds another layer of security. By default, a document inside an iframe is not allowed to access these powerful features. The allow attribute is how the parent page can grant specific permissions to the embedded content. The value of this attribute is a string that specifies which features are permitted.
For example, if you embed a video chat application, it will need access to the user’s camera and microphone. You would have to explicitly grant this permission: <iframe src=”chat.html” allow=”camera; microphone”></iframe>. Other common values include geolocation for maps, fullscreen for videos, and payment for payment request APIs. This attribute gives the parent page fine-grained control over what the embedded content can and cannot do, which is essential for security.
The ‘allowfullscreen’ Attribute
A common use case for iframes is embedding videos from services like YouTube or Vimeo. Users expect to be able to click a “fullscreen” button on these videos. However, for security reasons, an iframe is not allowed to make its content go fullscreen by default. You must explicitly grant this permission using the allowfullscreen attribute. This is a simple boolean attribute, meaning you just add the word to the tag: <iframe src=”video.html” allowfullscreen></iframe>.
This attribute, often used in conjunction with allow=”fullscreen”, signals to the browser that the content within the iframe is trusted to enter fullscreen mode. Without this, the fullscreen button on an embedded YouTube video simply would not work, leading to a poor user experience. This is a perfect example of the modern web’s “secure by default” policy, where potentially powerful features must be explicitly enabled by the developer.
The ‘referrerpolicy’ Attribute
When a user clicks a link inside an iframe to go to another site, the browser sends a Referer header. This header tells the new site where the user came from (i.e., the URL of the page containing the iframe). Sometimes, this can be a privacy concern, as you may not want to leak the URL of your page to the embedded site. The referrerpolicy attribute gives you control over this behavior.
You can set this attribute to various values. For example, referrerpolicy=”no-referrer” will prevent the browser from sending any referrer header at all. referrerpolicy=”origin” will send only your main domain (e.g., yourwebsite.com) but not the full path (e.g., yourwebsite.com/secret-admin-page). This attribute is an advanced but important tool for managing privacy and data leakage when dealing with third-party content.
Modern Applications of iframes
As you can see, the iframe is a complex and powerful element with many modern, security-focused features. It is the backbone of web embedding. Every YouTube video you see embedded in a blog post is in an iframe. Every Google Map on a “Contact Us” page is in an iframe. Every “Like” button or “Tweet” feed from a social media site is in an iframe. The online advertising industry is almost completely dependent on iframes to safely serve ads from third-party networks without letting them access or break the publisher’s main page.
They are also used for integrating third-party widgets and applications. When you use a “Stripe” or “PayPal” button to check out, the credit card form is often rendered in an iframe. This is a crucial security feature. It means your website never touches the user’s credit card number. The number is typed directly into an iframe hosted by the payment processor. Your site and the payment processor’s iframe are completely isolated, which dramatically increases security and reduces your liability.
The End of an Era
By the early 2000s, the web development community had turned decisively against framesets. The very technology that was once seen as a sophisticated solution to layout problems became a symbol of outdated and user-unfriendly design. The disadvantages, which were once considered minor trade-offs, became unbearable as the web matured. Search engines became more important, user experience became a discipline, and a new technology called Cascading Style Sheets (CSS) emerged as a far superior alternative for layout. The <frameset> tag was officially deprecated in HTML5, marking the end of its relevance.
The SEO Catastrophe
The single biggest problem that killed framesets was search engine optimization (SEO). The article mentions “SEO Challenges,” but the reality was far more severe. Search engine crawlers in the 1990s and early 2000s were simple. They followed links and indexed the HTML content of pages. A frameset site was their worst nightmare. The master index.html file contained no real content, only the <frameset> definition. The real content was hidden away in other files like main.html or about.html.
Crawlers would often fail to find or associate these content files with the main site. Even if they did find main.html and indexed it, the search result would link directly to that file. A user clicking that link would see only the main content, completely out of context. The site’s navigation, header, and branding (which were in other frames) would be missing. This created a “broken” and confusing experience, and users would immediately leave. This problem made it nearly impossible for a frameset-based site to rank well in search results.
The Broken Bookmark Problem
The article correctly identifies “Complicated Bookmarks” as a major disadvantage. This was an everyday frustration for users. Imagine you navigated the bookstore website, clicked “Fiction,” then “Science Fiction,” and found a specific book, dune.html, displayed in the main content frame. You would bookmark this page to save it for later. However, the URL in your browser’s address bar never changed. It always displayed bookstore.com/index.html, the URL of the master frameset.
When you later used your bookmark, it would not take you back to the page for Dune. It would simply reload the index.html frameset, which would display the default main.html welcome page. Your specific location within the site was lost. This made it impossible for users to save or share links to specific internal pages, a fundamental function of the web. This problem alone made sites that used framesets feel broken and deeply frustrating to navigate.
The Back Button’s Demise
Just as frames broke bookmarking, they also broke the browser’s back button. The back button is one of the most-used features in any web browser. Users rely on it to navigate sequentially backward through their history. On a frameset site, however, clicking links in the menu only changed the content of the main frame. The browser’s main window, which was still on the index.html frameset page, never actually navigated anywhere. As a result, the user’s history was not updated.
A user could click through ten different categories, but the browser’s “back” button would still be grayed out. Or, if they had visited another site before this one, clicking “back” would not take them to the previous frame content; it would cause them to leave the frameset site entirely. This non-standard and unpredictable behavior was a cardinal sin of usability. It broke one of the web’s most fundamental navigation paradigms, leaving users feeling lost and trapped.
Accessibility and Usability Nightmares
For users with disabilities, particularly those relying on screen readers, framesets were a complete disaster. A screen reader is a software that reads the content of a webpage aloud. When it encountered a frameset, it was confronted with multiple, separate HTML documents loaded at the same time. It had no logical way to understand the relationship between them. It might try to read the navigation frame, then the header frame, then the content frame, resulting in a confusing, jumbled mess of audio.
Users had no way to know which frame they were in or how to navigate between them. The content was completely disconnected. Furthermore, the simple act of resizing text was problematic. A user might increase their browser’s font size, but it would only apply to one frame, or it would break the carefully balanced pixel-based layout, causing frames to overlap or content to become hidden. This made frameset sites inaccessible to a significant portion of the population.
Inconsistent Browser Behavior
As the article notes, “Inconsistent Behavior Across Browsers” was another major issue. While Netscape and Internet Explorer were the main players, they implemented frames slightly differently. Attributes like framespacing (IE) and bordercolor (Netscape) were proprietary. The way borders were rendered, the way resizing was handled, and the way scrollbars appeared could all vary from one browser to the next. This meant developers had to spend a significant amount of time testing and tweaking their layouts to look acceptable on different browsers, adding to development time and cost.
Printing Problems
Printing a webpage that used frames was another source of user frustration. When a user hit the “Print” button, the browser had to guess which frame the user intended to print. Most of the time, the browser would print the currently active frame, which was often the last frame the user had clicked (such as the navigation menu). Users would end up with a printout of the site’s menu instead of the main article they wanted. The only workaround was to right-click inside the specific frame they wanted to print and find a special “Print this frame” option, which was non-obvious to most users.
The Rise of CSS as the Solution
The real nail in the coffin for <frameset> was the rise of Cascading Style Sheets (CSS). CSS provided a new, powerful, and standard way to achieve all the layout benefits of frames without any of the crippling disadvantages. With CSS, you could write your HTML in a single, logical document. This was great for SEO, bookmarking, and accessibility. Then, you could use CSS properties like position: fixed; to create a header or sidebar that would stay “fixed” in place while the rest of the page content scrolled.
This single CSS property achieved the main benefit of frames—the persistent navigation menu—with none of the drawbacks. As CSS evolved, layout modules like Floats, and later Flexbox and Grid, gave developers complete control over their page layouts, making the rigid, all-or-nothing approach of <frameset> totally obsolete. You could build multi-column, responsive, and complex layouts within a single HTML document, which was better for users, better for search engines, and better for developers.
The Security Problem: Clickjacking
While iframes are still used today, they share one of the major security vulnerabilities that plagued the original frameset: “clickjacking.” This is an attack where a malicious actor embeds your website in an invisible iframe on their own, evil site. They then overlay their own transparent page, which might have a button that says “Click Here to Win a Prize,” directly on top of a sensitive button on your invisible, embedded site, such as a “Delete My Account” or “Confirm Purchase” button.
The user thinks they are clicking the “Win a Prize” button, but they are actually, invisibly, clicking the “Delete My Account” button on your site. Because they are logged into your site in another tab, the browser sends their credentials, and the action is successful. This is a very dangerous attack. This vulnerability, which is inherent to the concept of embedding, is one of the main reasons developers must be extremely careful when working with frames, even modern iframes. We will discuss the solutions to this in a later part.
Why iframes Survived
The <frameset> died because it was a bad layout tool, and CSS provided a better one. The <iframe> survived and is an active part of the HTML5 standard because it is not a layout tool. It is an “embedding” tool. Its primary feature is not its visual presentation, but its ability to create a secure, isolated sandbox for content from a different domain. In the modern, component-based web, where pages are assembled from many different third-party sources, this isolation is not a bug; it is the most important feature. Modern use cases for iframes are all about safely and securely embedding content that you do not own or trust.
Embedding Media: The Most Common Use
The single most common and recognizable use of an iframe is embedding videos. When you go to a site like YouTube or Vimeo and click the “Share” button, the code it provides you to “Embed” on your website is an iframe tag. This iframe points to a special player URL at YouTube’s domain. This is done for many reasons. It is simple for the user; they just copy and paste one line of code. It is secure for you; the video player is sandboxed and cannot access your parent page.
It is also beneficial for the video service. They get to serve their own player, with their own branding and advertisements, directly on your site. This same logic applies to embedding audio players from services like SoundCloud or Spotify. The iframe is the universal, secure container for serving media from a third-party service onto your website, giving you rich content without having to host the massive video files yourself.
Embedding Interactive Maps
Another ubiquitous use of iframes is for embedding interactive maps. When a business wants to add a “Contact Us” page, they almost always include a map showing their location. Services like Google Maps or Mapbox provide a simple “Share” or “Embed” option that, just like YouTube, generates an iframe tag. This iframe loads the entire, complex, and interactive map application directly into a box on your page.
This is a perfect use case. Your website does not need to know how to render global map tiles or calculate driving directions. You are simply embedding a small, self-contained application from another domain. The iframe keeps the map’s complex code and functionality completely separate from your site’s code. This prevents conflicts and provides a seamless user experience, allowing users to pan, zoom, and get directions without ever leaving your contact page.
Displaying Social Media Feeds and Posts
iframes are also the technology behind most social media embeds. When you see a “Like” button from Facebook, an embedded “Tweet” from X (formerly Twitter), or a post from Instagram displayed in a news-article, that content is being loaded via an iframe. This is, again, for security and isolation. The embedded Tweet needs to be able to show the “like” and “retweet” counts and let you interact with it. It can only do this by running code from Twitter’s servers.
The iframe allows this code to run in a protected environment where it can talk to Twitter’s servers but cannot see the rest of your webpage. This prevents the social media site from, for example, reading your website’s cookies or interfering with your page’s scripts. It creates a secure bridge that allows for rich, interactive content from social platforms to be safely embedded anywhere on the web.
Serving Third-Party Advertisements
The digital advertising industry is built on iframes. When a website wants to display ads, they will typically partner with an ad network. This network gives them a small snippet of JavaScript, which then dynamically writes an iframe onto the page. This iframe’s src attribute points to the ad network’s server. The ad network then serves the advertiser’s creative (the image or video ad) into that iframe.
This isolation is absolutely critical for security. A publisher (like a news website) does not know or trust the hundreds of advertisers that might be displayed on their site. By forcing all ads to run inside an iframe, the ad’s code is “jailed.” It cannot access the parent page, read the site’s cookies, or interfere with the user’s experience. This “sandbox” (which we will cover in detail) is what makes the third-party ad ecosystem possible without completely compromising web security.
Integrating Payment and Booking Systems
When you check out on many e-commerce websites, the form where you enter your credit card number is often an iframe. This is a crucial security feature known as “tokenization,” often provided by services like Stripe, PayPal, or Braintree. Your browser sees the main shop’s checkout page, but the credit card number field itself is a separate document hosted by the payment processor and embedded in an iframe.
This means the e-commerce site’s code never sees or touches the user’s credit card number. The user types it directly into the payment processor’s secure iframe. The iframe then sends this data to the processor, which sends back a “token” (a secure, one-time-use string) to the parent page. The parent page then uses this token to complete the purchase. This dramatically reduces the site’s liability and protects the user from having their data skimmed by a compromised e-commerce site.
Adding Third-Party Widgets
This same principle of embedding self-contained applications applies to countless other “widgets.” When you see a “live chat” bubble in the corner of a website, that is often an iframe running a third-party chat service. When you use a calendar widget to book an appointment, that widget is likely an iframe. Commenting systems, like Disqus, also use iframes to load the comment thread and submission form.
In all these cases, the iframe is the perfect tool. It allows the website owner to add complex functionality to their site by simply copying and pasting a single line of code. They do not have to build or maintain a complex chat system, calendar, or comment platform. They can embed the specialized service, and the iframe ensures that the widget’s code stays isolated from the main page, preventing technical conflicts and security vulnerabilities.
Displaying In-Page Previews
iframes are also used in web applications to provide previews or to display content in a sandboxed environment. For example, a Content Management System (CMS) might use an iframe to show a “live preview” of the blog post you are currently editing. This allows the preview to be refreshed and to apply styles without affecting the main editing interface.
Another common example is an online code editor like CodePen. When you type HTML, CSS, and JavaScript, the “results” window where you see your creation is an iframe. The application takes your code, combines it, and loads it into the iframe (often using the srcdoc attribute). This is done for security. It prevents your user-written code from “escaping” and breaking the main CodePen application. The iframe acts as a secure testbed for running potentially buggy or malicious user-submitted code.
Enhancing User Experience (When Used Correctly)
The article’s “Advantages” section mentions enhancing user experience by loading content separately. This is true for iframes when used correctly. The ability to embed a video player or a map without forcing the user to leave the page is a massive user experience win. The ability to add a chat widget or a booking calendar is also a huge convenience. These elements make a page more interactive and useful.
However, this is very different from the <frameset> approach. We are not “splitting” the page. We are “augmenting” a single, complete, and fully functional page with external components. The page itself is still bookmarkable, accessible, and indexable by search engines. The iframes are just building blocks within that page. This is the key distinction and the reason why iframes have remained an essential tool for all web developers.
The Security Challenge of iframes
While iframes are a modern tool, they are not without serious risks. Their entire purpose—to embed a document from another domain—is inherently a security challenge. We have already mentioned “clickjacking,” which is one of the most famous iframe-based attacks. A malicious site can load your site in an invisible iframe and trick your users into clicking on things they cannot see. This attack is possible because, by default, any website can embed any other website in an iframe.
To combat this, modern web servers have a defense mechanism. A server can send a special HTTP header called X-Frame-Options. This header tells the browser what framing behavior is allowed. A setting of X-Frame-Options: DENY tells the browser that this page should never be allowed to be displayed in a frame, completely preventing all clickjacking attacks. A setting of X-Frame-Options: SAMEORIGIN is more flexible, allowing the page to be framed, but only by other pages from the same website. This is a critical server-side defense.
The Modern sandbox Attribute
The other major security tool is the sandbox attribute, which is applied directly to the <iframe> tag. This attribute “locks down” the iframe content, making it as secure as possible. When you add the sandbox attribute (with no value), you are enabling the tightest set of restrictions. The content inside the iframe is not allowed to run any JavaScript. It cannot submit forms. It cannot open pop-up windows. It cannot navigate the parent page. It is treated as coming from a unique, null origin, preventing it from accessing any data.
This is a “secure by default” starting point. You can then selectively re-enable specific permissions by adding values to the attribute. For example, sandbox=”allow-scripts” will re-enable JavaScript. sandbox=”allow-forms” will allow the iframe to submit forms. sandbox=”allow-same-origin” tells the browser to treat the content as coming from its real origin, not a null one. A very common and secure setup is sandbox=”allow-scripts allow-same-origin”. This allows the iframe to function but still blocks dangerous permissions like pop-ups.
Cross-Domain iframe Communication
The isolation of an iframe is a security feature, but it can also be a development challenge. What if you need to communicate between your parent page and the document inside the iframe? For security reasons, a script on your page cannot directly access the content of an iframe from a different domain (like a payment processor). This is blocked by the browser’s “same-origin policy.” To solve this, a special, secure API called window.postMessage() was created.
This API allows two different windows (such as a parent page and its iframe) to send messages to each other in a safe way. The parent page can use postMessage() to send a string of data to the iframe. The iframe has an “event listener” that “listens” for these messages. It must then verify that the message came from the expected origin (your domain) before acting on it. This “message passing” system allows for secure, cross-domain communication without breaking the browser’s core security model.
The Performance Impact of iframes
iframes are not “free.” They come with a significant performance cost. An iframe is essentially a full webpage (with its own HTML, CSS, and JavaScript) embedded inside your main page. This means the browser has to do twice the work. The iframe’s content consumes its own memory and CPU resources. More importantly, by default, iframes can block the onload event of the parent page. This means your main page might feel “finished” loading, but the browser’s loading spinner will keep spinning until every iframe on the page (including slow third-party ads) has also finished loading.
This can make your page feel slow and sluggish, which is bad for user experience and can even hurt your SEO, as page speed is a ranking factor. A page with many iframes will almost always load slower than a page without them. This is a trade-off that developers must constantly manage. The convenience of embedding a widget must be weighed against the performance cost it adds to the page.
Optimizing iframe Performance
Fortunately, modern HTML provides a powerful tool to manage this performance cost: the loading attribute. By setting loading=”lazy” on an iframe tag, you are telling the browser to defer loading that iframe. The browser will not download or render the iframe’s content until the user has scrolled down the page and the iframe is about to become visible. This is a game-changer for performance.
You can place a dozen loading=”lazy” iframes for YouTube videos at the bottom of your article, and they will have zero impact on your initial page load time. The browser will only load them when they are actually needed. This is now a standard best practice. Any iframe that is “below the fold” (not immediately visible) should almost always have the loading=”lazy” attribute to ensure your main page loads as quickly as possible.
Alternatives to iframes
While iframes are the right tool for embedding third-party applications, they are often the wrong tool for other jobs. If your goal is simply to include content from another file on your own server, an iframe is a very heavy-handed and inefficient solution. For example, if you want to reuse your website’s header or footer on every page, you should not use frames. Instead, you would use a server-side technology like PHP (include ‘footer.php’;), a static site generator, or a JavaScript framework.
If your goal is to display data from an external source (like a weather forecast or stock prices), an iframe is also not the best choice. The correct modern approach is to use a “Fetch API” (a form of AJAX). Your JavaScript would “fetch” this data from the third-party’s API, which usually returns the data in a lightweight format like JSON. Your script would then parse this data and render it as native HTML on your page. This is far faster and gives you complete control over the styling and layout, unlike an iframe which is a “black box.”
Conclusion
The history of the “frame” in HTML is a perfect illustration of the web’s evolution. The <frameset> was a pioneering but flawed attempt to solve the layout problem in a primitive web. It was born from a need to create application-like experiences but was ultimately abandoned because it broke the web’s fundamental principles of linkability, accessibility, and searchability. Its problems were so severe that it was replaced entirely by the more flexible and standards-compliant CSS.
The <iframe>, however, survived this extinction event. It survived because its purpose was different. It was not a layout tool, but an embedding tool. As the web became more interconnected and component-based, the need for a secure “sandbox” to isolate third-party content became more critical than ever. The iframe, armed with new, modern attributes like sandbox, allow, and loading, has become an essential and secure part of the modern developer’s toolkit, carrying on the “frame” legacy in a way that is compatible with the secure, fast, and open web.