This is a W3C NOTE 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 NOTEs as reference material or to cite them as other than "work in progress". A list of current W3C NOTEs can be found at: http://www.w3.org/pub/WWW/TR
Note: since NOTEs are subject to frequent change, you are advised to reference the above URL, rather than the URLs for NOTEs 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} </style> <h1>Welcome to my Home Page</h1> <ul> <li>Favorite Places <li>Picture of my family <li>My plans for this week </ul>
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.
Frames designed for online use won't in general work for generating hardcopy. Many frames rely on scrollbars to allow users to scroll through material too large to fit into a frame. This doesn't translate well to hardcopy. You could choose to print what is currently visible in the frame. More useful though is the ability to segment material across a number of pages. Hardcopy presents new opportunities for presentation. In particular, you can flow text across multiple columns. This in turn makes it practical to place images between columns. The use of a scrolling window model makes text flow between multiple columns painful for online use. This specification includes features intended for hardcopy only. These allow authors to specify a sequence of page layouts for successive pages.
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 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.
There is some interest in allowing a length to be specified as the maximum of a percentage value and a fixed value, e.g. "left: max(20%, 50px)". This syntax would allow other expressions to be added in future.
The declaration "@page" allows you to define the properties of the outermost frame. The declaration "@frame <name>" is used to define nested frames. The name parameter defines the name of the frame. Frame names must start with an alphanumeric character.
The following properties can be used with these declarations:
The following define alternative ways for specifying the position and size of a frame. They can also be applied to HTML elements. These properties are ignored under some layout policies.
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.
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. The values for left, top, right and bottom are ignored within fill layout. 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. Within a fixed layout region, the following CSS properties are ignored: clear, float, margin and white-space. In addition, all HTML elements are treated as block-like, i.e. display: inline is automatically treated as equivalent to display: block.
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, together with the margin: property. 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, together with the margin: property. 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.
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, all 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 main h1 {flow: banner} body {flow: main} </style>
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 "main" frame. The page has the "column" layout policy. As a result the two frames extend in width to fill the page, with "banner" appearing above "main". The page height has been left undefined and set by the current window size. The heights of both frames are then determined from their contents using an algorithm similar to that used to assign column widths for tables.
Frames are left empty unless they are filled, for instance:
<html> <head> <title>Why is this empty?</title> <style type="text/css">ag @page {layout: row} @frame toc {width: 20%} @frame main {width: 80%} </style> <body> <h1>Test document</h1> <P>This won't be shown at all! </html>
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:
<html> <head> <title>This is fine</title> <style type="text/css">ag @page {layout: fill} </style> <body> <h1>Test document</h1> <P>This shows up fine! </html>
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".
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.
Does this permit multiple inheritance? If so, it may be better to say the target property defaults to the value of the flow property.
<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} </style> <h1>Welcome to Bayview Athletics</h1> <ul class=toc> <li><a href=facilities>Our facilities</a> <li><a href=events>Sporting events schedule</a> <li><a href=membership>How to become a member</a> </ul>
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".
Frame names defined with the @frame declaration must start with an alphanumeric character. This allows them to be distinguished from special target names which begin with an underscore character:
HTML documents contain a set of implicit frames. These frames act as containers for the contents of any block element in a document's structure. This is best understood by examining a very simple HTML document:
<TITLE>My Home Page</TITLE> <BODY> <H1>This is my Home Page</H1> <DIV> <P>Hobbies:</P> <UL> <LI>Skiing <LI>Web Surfing </UL> </DIV> </BODY>
The above HTML document can be visualized as the following set of nested frames:
BODY
|
As shown in the above diagram, each block element in HTML can be considered a container for content. HTML currently lays out content into frames whose height grows to match the content. This model lends itself quite well to textual content, but fails to provide enough flexibility for creating complex input forms or layouts that require overlapping elements. By offering the ability to use alternative layout models for any block element, the author can change how these implicit frames are layed out. This proposal calls for adding the ability to define a different layout model for any element within the document.
Initially, implicit frames should be limited to the existing fill model (the default) and the new fixed positioning model. This specification however is not closed to the prospect of eventually defining additional layout models for content within an implicit frame.
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 </FORM>
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.
Here is a more elaborate example.
<HTML> <TITLE>John Doe's Home Page</TITLE> <BODY STYLE="LAYOUT: FIXED; WIDTH:500; HEIGHT:500"> <H1 STYLE="LEFT:0; WIDTH:500; HEIGHT:100; TOP=0"> Welcome to my Home Page </H1> <DIV CLASS=TOC STYLE="LEFT:0; WIDTH:500; HEIGHT:500; TOP:100"> <UL> <LI>Favorite Places <LI>Picture of my family <LI>My plans this week </UL> </DIV> </BODY> </HTML>
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:
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.
Note: Do we need a property to specify the scrolling mechanism? For example: "overflow: autoscroll | scrollbar | hand | button | any" defaulting to "any".
Extensions for use when Printing
The following extensions to CSS are only applicable when rendering to a paged medium such as hardcopy. It allows you to specify the layout for a sequence of pages. This work is still at an early stage and suggestions for improvements are welcome. Here is an example of a page definition for a book-like layout:
@layout {titlepage emptypage (rightpage leftpage)* colophon}
This defines a sequence of pages, five different types in all. The `leftpage' and `rightpage' can be repeated as a pair. After the @layout keyword, there is a list, enclosed in curly braces, of names arbitrarily chosen by the page designer. By default, each of these named pages will occur exactly once in the produced output as separate sheets of paper, or as a stack of windows, for example).
If there is an asterisk behind the name, it means that that page occurs only if there is text to put onto it. If there is more text than will fit, the page is repeated as needed. Pages can be grouped within parentheses, as in the example above, which causes the group to repeat, instead of the individual pages. Each page must be defined with the @page name declaration, e.g.
@page titlepage {layout: fixed}
You can then define frames and specify which page they belong to with the parent: property. Pages with no attached frames or other content are to be left blank. Frames can be grouped into flows, by specifying the flow: name property in the frame declaration. This defaults to the name of the frame. When a frame is filled, the remaining content fills into the next frame with the same flow name. This process continues across pages as needed.
Further work is needed for specifying: