W3C: WD-layout-960408

Frame-based layout via Style Sheets

W3C Working Draft 08-Apr-1996

This version:
Latest version:
Bert Bos <bert@w3.org>,
Dave Raggett <dsr@w3.org>,
Håkon Lie <howcome@w3.org>

Status of this document

This is a W3C Working Draft for review by W3C members and other interested parties. It is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to use W3C Working Drafts as reference material or to cite them as other than "work in progress". A list of current W3C working drafts can be found at: http://www.w3.org/pub/WWW/TR

Note: since working drafts are subject to frequent change, you are advised to reference the above URL, rather than the URLs for working drafts themselves.


CSS1 [Ref css] is a simple style sheet language, that can be applied to HTML [Ref html]. It describes the style of a document: which fonts and colors to use, how much whitespace to insert, etc. This specification extends CSS to support the definition of nested frames for controlling how a page (or window) is to be divided up into frames and which part of a document goes into which frame.


Until recently Web browsers have rendered HTML documents as single column scrolling windows. Authors have been given very limited means to control the placement of features in the window. Traditional page-layout authoring tools for desktop publishing allow you to create and move and resize document frames. You can then view and alter properties of these frames, e.g. the background color and the style of borders if any. You may also be able to drag and drop objects onto frames, and to move and resize the objects relative to the frame on which they have been attached.

This specification extends CSS to define frames and to specify which HTML elements are displayed in what frames. Frames can be placed on parent frames. The top level frame is the "page". Here is an example:

    <style type="text/css">
    @page {layout: fixed; width: 500px; height: 500px}
    @frame header {left: 0px; top: 0px; width: 500px; height: 100px}
    @frame toc {left: 0px; top: 100px; width: 500px; height: 400px}
    h1 {flow: header}
    ul {flow: toc}

    <h1>Welcome to my Home Page</h1>

    <li>Favorite Places
    <li>Picture of my family
    <li>My plans for this week

This sets the page size to 500 by 500 pixels, and defines two frames, one below the other. The header element is flowed into the top frame named "header" while the unordered list is flowed into the bottom frame named "toc". The page uses a fixed layout manager. This requires that all the components on the page must have an explicit position and size. The two frames on the page use the default layout manager which lays things out automatically based on the styles and properties of the contents.

Units for Lengths

Length values can be specified as an integer representing the number of screen pixels followed by an optional "px" suffix e.g. "200px", or as a percentage of the available space in the parent frame, e.g. "50%". This doesn't include the space used for padding the parent frame's contents.

You can also use fixed units by including a suffix after a floating point number, e.g. "0.5in". The allowed suffices are: pt for points, pc for picas, in for inches, and cm for centimeters, where 72pt = 6pc = 1in = 2.54cm.

Defining Frames

The command "@page" allows you to define the properties of the outermost frame. The command "@frame <name>" is used to define nested frames. The name parameter defines the name of the frame. The following properties can be used with these commands:

parent: <frame-name>
Attaches the frame to a parent frame. The default parent is "page". This is the predefined name of the default page.
zindex: <number>
This is an integer representing the graphical layer the frame or object is displayed at. Frames with higher values for zindex appear above frames with lower values. If two frames have the same value for zindex, the z-order between the two frames is undefined.
layout: fill | fixed | row | column
This sets the layout policy for the frame. The default is "fill". See below.
content: <URL> | normal
Fills the content of the frame with the given URL. This allows you to put someone else's document inside your frame. A URL supplied with this property overrides the normal content for the frame. The default is "normal".
border-width: <length>
Sets the border width of the frame. The default is no border. It is defined in exactly the same way as in CSS1.
border-style: <style>
Sets the border style for the frame. It is defined in exactly the same way as in CSS1. will this include "inset" and "outset"?
border-color: <URL and/or color>
Sets the border style for the frame. It is defined in exactly the same way as in CSS1.
padding: <values>
This sets the space between the border and the frame's content. It is defined in exactly the same way as in CSS1.
background: transparent | <URL> | [ <color> [ / <color> ]? ]
Sets the background characteristics of the frame. It allows you to define transparent or colored backgrounds, and to specify background image patterns or color fades. It is defined in exactly the same way as in CSS1.

The following define alternative ways for specifying the position and size of a frame. They can also be applied to HTML elements. The positional information is ignored by layout policies like "fill"

left: <length>
Sets the position of the left of a frame or object relative to the parent frame.
top: <length>
Sets the position of the top of a frame or object relative to the parent frame.
right: <length>
Sets the position of the right of a frame or object relative to the parent frame.
bottom: <length>
Sets the position of the bottom of a frame or object relative to the parent frame.
width: <length> | auto
Sets the width of a frame or object.
height: <length> | auto
Sets the height of a frame or object.
geometry: <left> <top> <width> <height>
Sets the position and size of a frame or object.
Is "geometry" too X11 centric, would "bounds" be better?

Note that none of the above properties are inherited from parent frames. In the absence of size properties, some layout policies determine the default size from the contents of a frame or object.

Layout Policies

There are four policies: fill, fixed, row and column. Fill is the traditional layout policy for browsers. Fixed is used when you want absolute control. Row and Column provide the same functionality as Netscape frames and can be nested to provide richer layouts.

layout: fill is the default and lays out the contents of the frame in the traditional manner used by web browsers to layout HTML documents. This policy ignores the positional properties of components. Frames are not allowed as explicit components, although implicit frames are.

layout: fixed places each component at a fixed position relative to the frame. This requires each component to explicitly specify its position and size. Note that positions may be specified using percentage widths or fixed widths.

layout: row organizes the frame as a single row of components one beside another. The height of each component is set to fill the parent frame, while the width: property of components can be used to set their width. The default width for each component is determined from its contents (width: auto). This policy only allows frames as components.

layout: column organizes the frame as a single column of components one above another. The width of each component is set to fill the parent frame, while the height: property of components can be used to set their height. The default height for each component is determined from its contents (height: auto). This policy only allows frames as components.

Nested frames with different policies can be used to define complex layouts, for example a mix of "Row" and "Column" policies can be used to create rich grid-based layouts. Additional layout policies are anticipated in future versions of this specification, e.g. for magazine style layout as found in magazines like Time and Newsweek.

There are two general approaches to laying out documents: top-down, where you specify the frames and then pour the content into them; and bottom-up, where the content determines what frames are needed. The top-down approach is great for layout common to a group of pages, while the bottom-up approach is valuable for coping with positioning headers, figures and varying numbers of columns as the window size is changed. This specification is only the first step along the road to much richer layout capabilities combining top-down and bottom-up approaches.

Associating HTML elements with Frames

You associate an HTML element with a particular frame using the flow: <frame-name> property to name the intended frame, e.g.

        p { flow: main }

This causes the contents of all paragraphs to be flowed into the frame named "main". The property is called "flow" in anticipation of being used to name flows consisting of sequences of frames. By default, elements are flowed onto the page. You can readily override this by defining the flow property for the BODY element. For example:

        <style type="text/css">
        @page {layout: column}
        @frame banner
        @frame body
        h1 {flow: banner}
        body {flow: main}

This defines two frames, and flows the contents of H1 elements into the "banner" frame. Other elements that appear as part of the document BODY inherit the flow property from the BODY element and are flowed into the "body" frame. The page has the "column" layout policy. As a result the two frames extend in width to fill the page, with the "banner" appearing above the "body". The heights of both frames are determined from their contents.

Where did my document go?

Frames are left empty unless they are filled, for instance:

        <title>Why is this empty?</title>
        <style type="text/css">ag
        @page {layout: row}
        @frame toc {width: 20%}
        @frame main {width: 80%}
        <h1>Test document</h1>
        <P>This won't be shown at all!

The above results in two empty frames. The HTML elements aren't shown! This can be fixed by adding the statement "body {flow: main}" which causes the body of the document to be flowed into the frame "main".

An exception to the above rule is when the page layout policy is "fill" as in:

        <title>This is fine</title>
        <style type="text/css">ag
        @page {layout: fill}
        <h1>Test document</h1>
        <P>This shows up fine!

This is the default situation and behaves just as if you had omitted the statement "@page {layout: fill}". This works because the default value for flow is the "page". The page exists whether not it is declared (unlike other frames), and the default for layout policy is "fill".

Setting the target frame for hypertext links

The target: <frame-name> property can be used to set the target frame for displaying the resource referenced by a URL when the user clicks on a hypertext link. The default is "page", i.e. the new document replaces the current page.

When the target property is given on a frame, all the hypertext links in that frame assume that target, unless overridden by more specific rules. You can also set the target property on elements such as lists and of course anchor elements.

        <style type="text/css">
          @page {layout: column}
          @frame banner {height: 20%}
          @frame middle {height: 70%; layout: row}
          @frame sponsors {height: 10%; content: sponsors.html}
          @frame toc {parent: middle; width: 20%}
          @frame main {parent: middle; width: 80%}
          h1 {flow: banner}
          ul.toc {flow: toc; target: main}
          body {flow: main}
        <h1>Welcome to Bayview Athletics</h1>

        <ul class=toc>
          <li>Our facilities
          <li>Sporting events schedule
          <li>How to become a member

This example defines five frames, and illustrates how to exploit nested frames for richer layouts. The page uses the column layout policy to organise its children as a single column. It contains three frames:

The banner stretches right across the top of the page, occupying the top 20% of the page. The bottom 10% of the page is devoted to "messages from our sponsors" using the content property to specify the URL. In between there is a frame named "middle" which acts as a container for two child frames named "toc" and "main".

The layout policy for "middle" is row. As a result the two children are placed side by side, with "toc" occupying the left 20% and "main" the right 80% of the page width.

The unordered list with the class attribute value "toc" is associated with two properties: flow: toc which causes the contents of the list to be flowed into the frame named "toc", and target: main which causes any hypertext links within this list to display into the frame named "main".

Implicit Frames

If you want a child frame to occur as part of a "fill" region you need to use an implicit frame. This is done by setting the layout property for the element, e.g.

        <FORM STYLE="layout: fixed; width: 100px; height: 100px">
           ... elements with explicit position/size

The layout property causes the user agent to create a frame for the contents of this element. In this example, the frame is given the "fixed" layout policy and a size of 100 by 100 screen pixels. The frame can be positioned using the normal CSS attributes, but properties such as top, left, bottom or right will be ignored. Implicit frames avoid the problems involved in figuring out how to flow HTML content around any fixed frames that are explicitly placed in the parent frame.

Note that implicit frames do not support targetting. why not?

Individually Resizable Frames

When the user resizes the browser window the layout policy for each frame is used to layout the contents of that frame. Sometimes authors will want to give users the ability to manually resize individual frames. On most user interfaces, the user will be alerted to this by a change of the pointer icon to a resize icon when it is moved over the frame border. The "resize" property can be used to specify whether a frame is manually resizable or not:

resize: auto
This is the default, and means that the frame can only be resized under automatic control, for instance when the page is resized.
resize: manual
This means that the frame can be resized manually as well as under automatic control.

Coping with Under and Overflow

If the contents of a frame (or page) exceed the size of the frame, then scroll bars (or an equivalent mechanism for moving the contents through the viewable area) should be provided. If the contents don't fill the frame, the remaining space should be filled with the background color or texture associated with the frame.

Scrollbars may interfere with the aesthetics of the layout, and some people will find it preferable to use an alternative mechanism when there is only a small overflow. For example, the pointer icon could be changed to a "grabbing hand" to indicate that the content can be moved by dragging the pointer over the frame. A static visual indication that overflow has occurred is also recommended e.g. a overflow icon in the bottom right corner of the frame.

It is anticipated that future revisions to this specification will provide the means for creating multiple pages as an alternative to scrollbars.

Note: Do we really need a property to disable the use of scrollbars as opposed to alternative mechanisms? For example: "overflow: scroll | hand | button | any" defaulting to "any".


"Cascading style sheets" by Håkon Lie & Bert Bos, February 1996. The latest version of this document can be downloaded from http://www.w3.org/pub/WWW/TR/WD-css1.html
RFC 1866
"Hypertext Markup Language - 2.0" by T. Berners-Lee & D. Connolly, November 1995. This document can be downloaded from ftp://ds.internic.net/rfc/rfc1866.txt or see http://www.w3.org/pub/WWW/MarkUp/html-spec.

W3C: The World Wide Web Consortium: http://www.w3.org/