RFC 1942
HTML Tables
RFC 1942: HTML Tables ๐
- Author: D. Raggett, W3C ๐
- Category: Experimental ๐งช
- Date: May 1996 ๐
Part 1 of 7 ๐ฆ
Status of this Memo โจ
okay bestie, this memo defines an Experimental Protocol for the Internet community ๐งช. It is NOT an Internet standard of any kind, so don't treat it like one ๐. The authors are literally asking for discussion and suggestions for improvement, so feedback is welcome ๐. Distribution of this memo is unlimited ๐.
Abstract ๐
HTML is a simple markup language for making hypertext documents that are portable from one platform to another ๐ง. HTML documents are SGML documents with generic semantics, which means they're flexible enough to represent information from a wide range of applications ๐ธ.
This spec extends HTML to support a wide variety of tables ๐. The model is designed to play nicely with associated style sheets, but it doesn't need them ๐. It also supports rendering to braille or speech, and exchanging tabular data with databases and spreadsheets ๐ฅ. The HTML table model borrows some ideas from the CALS table model, like grouping table rows into thead, tbody and tfoot sections, plus specifying cell alignment compactly for sets of cells based on the context โจ.
Table of Contents ๐๏ธ
Recent Changes ................................................. 1
Brief Introduction ............................................. 2
Design Rationale ............................................... 5
Walkthrough of the Table DTD ................................... 8
Recommended Layout Algorithms ................................. 23
HTML Table DTD ................................................ 26
References .................................................... 29
Security Considerations ....................................... 30
Author's Address .............................................. 30
Recent Changes ๐
okay so this spec extends HTML to support tables ๐ . The table model grew out of early work on HTML+ and the first draft of HTML3 ๐ฑ. Information providers asked for more control over how tabular info gets presented, so the earlier model got some upgrades ๐ฆ:
- alignment on designated characters such as "." and ":" e.g. aligning a column of numbers on the decimal point ๐ข
- more flexibility in specifying table frames and rules ๐ผ๏ธ
- incremental display for large tables as data is received โญ
- the ability to support scrollable tables with fixed headers, plus better support for breaking tables across pages for printing ๐จ๏ธ
- optional column based defaults for alignment properties ๐
Another big goal was backwards compatibility with the widely deployed Netscape implementation of tables ๐ซถ. A smaller goal was making it simpler to import tables that follow the SGML CALS model ๐ง. The latest draft makes the ALIGN attribute compatible with the latest Netscape and Microsoft browsers ๐. There are also some clarifications about the role of the DIR attribute, and the recommended behaviour when absolute and relative column widths are mixed ๐.
A new element, COLGROUP, lets you group sets of columns with different width and alignment properties, specified by one or more COL elements ๐ง. Its semantics got clarified over previous drafts, and RULES=BASIC was replaced by RULES=GROUPS ๐.
The FRAME and RULES attributes were changed so they don't cause SGML name clashes with each other or with ALIGN and VALIGN ๐ . This was also motivated by wanting to avoid future problems if FRAME and RULES get extended to other table elements ๐ฎ.
A Brief Introduction to HTML Tables ๐
Tables start with an optional caption, followed by one or more rows ๐. Each row is made of one or more cells, which are either header cells or data cells ๐. Cells can be merged across rows and columns, and they can include attributes that help with rendering to speech and braille, or with exporting table data into databases ๐. The model gives you limited control over appearance, like horizontal and vertical alignment of cell contents, border styles, and cell margins ๐ฆ. You can also group rows and columns together to affect this even more โจ. Tables can hold a wild range of content, including headers, lists, paragraphs, forms, figures, preformatted text, and even nested tables ๐คฏ.
Example ๐ง
Here's a tiny table with merged cells ๐ธ:
<TABLE BORDER>
<CAPTION>A test table with merged cells</CAPTION>
<TR><TH ROWSPAN=2><TH COLSPAN=2>Average
<TH ROWSPAN=2>other<BR>category<TH>Misc
<TR><TH>height<TH>weight
<TR><TH ALIGN=LEFT>males<TD>1.9<TD>0.003
<TR><TH ALIGN=LEFT ROWSPAN=2>females<TD>1.7<TD>0.002
</TABLE>
On a dumb terminal, it would look something like this ๐:
A test table with merged cells
/--------------------------------------------------\
| | Average | other | Misc |
| |-------------------| category |--------|
| | height | weight | | |
|-----------------------------------------|--------|
| males | 1.9 | 0.003 | | |
|-----------------------------------------|--------|
| females | 1.7 | 0.002 | | |
\--------------------------------------------------/
Next up is a richer example with grouped rows and columns ๐. It's adapted from "Developing International Software" by Nadine Kano ๐. Here's what the table looks like on paper first ๐จ๏ธ:
CODE-PAGE SUPPORT IN MICROSOFT WINDOWS
========================================================================
Code-Page| Name |ACP OEMCP| Windows Windows Windows
ID | | | NT 3.1 NT 3.51 95
------------------------------------------------------------------------
1200 |Unicode (BMP of ISO 10646) | | X X *
1250 |Windows 3.1 East. Europe | X | X X X
1251 |Windows 3.1 Cyrillic | X | X X X
1252 |Windows 3.1 US (ANSI) | X | X X X
1253 |Windows 3.1 Greek | X | X X X
1254 |Windows 3.1 Turkish | X | X X X
1255 |Hebrew | X | X
1256 |Arabic | X | X
1257 |Baltic | X | X
1361 |Korean (Johab) | X | ** X
------------------------------------------------------------------------
437 |MS-DOS United States | X | X X X
708 |Arabic (ASMO 708) | X | X
709 |Arabic (ASMO 449+, BCON V4)| X | X
710 |Arabic (Transparent Arabic)| X | X
720 |Arabic (Transparent ASMO) | X | X
========================================================================
The markup for this uses COLGROUP elements to group columns and set default column alignment ๐ง. TBODY elements group the rows ๐ซถ. The FRAME and RULES attributes pick which borders get rendered ๐ผ๏ธ:
<table border=2 frame=hsides rules=groups>
<caption>CODE-PAGE SUPPORT IN MICROSOFT WINDOWS</caption>
<colgroup align=center>
<colgroup align=left>
<colgroup align=center span=2>
<colgroup align=center span=3>
<thead valign=top>
<tr>
<th>Code-Page<br>ID
<th>Name
<th>ACP
<th>OEMCP
<th>Windows<br>NT 3.1
<th>Windows<br>NT 3.51
<th>Windows<br>95
<tbody>
<tr><td>1200<td>Unicode (BMP of ISO 10646)<td><td><td>X<td>X<TD>*
<tr><td>1250<td>Windows 3.1 Eastern European<td>X<td><td>X<td>X<TD>X
<tr><td>1251<td>Windows 3.1 Cyrillic<td>X<td><td>X<td>X<TD>X
<tr><td>1252<td>Windows 3.1 US (ANSI)<td>X<td><td>X<td>X<TD>X
<tr><td>1253<td>Windows 3.1 Greek<td>X<td><td>X<td>X<TD>X
<tr><td>1254<td>Windows 3.1 Turkish<td>X<td><td>X<td>X<TD>X
<tr><td>1255<td>Hebrew<td>X<td><td><td><td>X
<tr><td>1256<td>Arabic<td>X<td><td><td><td>X
<tr><td>1257<td>Baltic<td>X<td><td><td><td>X
<tr><td>1361<td>Korean (Johab)<td>X<td><td><td>**<td>X
<tbody>
<tr><td>437<td>MS-DOS United States<td><td>X<td>X<td>X<TD>X
<tr><td>708<td>Arabic (ASMO 708)<td><td>X<td><td><td>X
<tr><td>709<td>Arabic (ASMO 449+, BCON V4)<td><td>X<td><td><td>X
<tr><td>710<td>Arabic (Transparent Arabic)<td><td>X<td><td><td>X
<tr><td>720<td>Arabic (Transparent ASMO)<td><td>X<td><td><td>X
</table>
the table model is SO well thought out, bestie ๐๐ญ
Design Rationale ๐
okay so the HTML table model came from studying existing SGML table models, how word processing packages handle tables, and a whole bunch of tabular layouts in magazines, books, and other paper docs ๐โจ The goal was simple: simple tables should be easy to write, and extra complexity should only show up when you actually need it ๐ This means you can make HTML table markup with everyday text editors, so starting out is way less scary ๐ซถ Honestly this has been a huge reason HTML has been so successful, no cap ๐
People are increasingly using filters from other document formats, or direct WYSIWYG editors, to make HTML ๐ It's important that the table model fits nicely with those workflows. This affects how the markup represents cells that span multiple rows or columns, and how alignment and other presentation properties get attached to groups of cells ๐
Here's a big one: the fonts and window sizes that browsers use are not under the author's control ๐ญ So relying on column widths in absolute units like picas or pixels is risky ๐ Instead, tables can be sized dynamically to match the current window size and fonts ๐ฆ Authors can give guidance on the relative widths of columns, but user agents should to ensure that columns are wide enough to render the width of the largest single element in the cell's content ๐ If the author's specification has to be overridden, it's preferred that the relative widths of individual columns don't change drastically โจ
For big tables or slow connections, it's really nice to start showing the table before all the data has arrived ๐ Most user agents have a default window width of about 80 characters, and lots of HTML page graphics are designed with those defaults in mind ๐ Authors can drop a hint to user agents to turn on incremental display of table contents ๐ง This feature requires the author to specify the number of columns, and it includes a way to control table width and the widths of different columns, either in relative or absolute terms ๐ธ
For incremental display, the browser needs the number of columns and their widths ๐ By default the table's width is the current window size (width="100%"), and you can change that by adding a WIDTH attribute to the TABLE start tag ๐ By default every column is the same width, but you can set column widths with one or more COL elements before the table data starts ๐ฆ
The last piece is the number of columns. Some people suggested waiting until the first row has arrived, but that could take forever if the cells have tons of content ๐ญ Overall it makes more sense, when you want incremental display, to have authors explicitly state the number of columns in the TABLE start tag ๐
Authors still need a way to tell the browser whether to use incremental display or to auto-size the table to fit the cell contents ๐ For the two pass auto sizing mode, the number of columns gets figured out in the first pass, but for incremental mode the number of columns has to be stated up front ๐ซถ So it seems to that COLS=_nn_ would be better for this job than a LAYOUT attribute like LAYOUT=FIXED or LAYOUT=AUTO ๐
People generally find it useful to look at documents from two angles: structural idioms like headers, paragraphs, lists, tables, and figures, and rendering idioms like margins, leading, and font names and sizes ๐ Past experience tells us to keep structural information separate from rendering information ๐ง Mixing them together raises the cost of maintaining documents and lowers portability between applications and media ๐
For tables, text alignment inside cells and the borders between cells are, from a purist's point of view, rendering information ๐ค In practice, though, it's useful to group them with the structural information, because these features move really well from one application to the next โจ The HTML table model leaves most rendering information to associated style sheets ๐จ The model is designed to take advantage of style sheets, but it doesn't require them ๐ธ
This specification gives you a superset of the simpler model from earlier HTML+ work ๐ฆ Tables are treated as an optional caption plus a sequence of rows, and each row is a sequence of table cells ๐ The model also tells header cells apart from data cells, and lets cells span multiple rows and columns ๐
Following the CALS table model, this specification lets table rows be grouped into head, body, and foot sections ๐ง This simplifies the representation of rendering information, and it can be used to repeat head and foot rows when a table breaks across page boundaries, or to give you fixed headers above a scrollable body panel ๐ In the markup, the foot section goes before the body sections ๐ This is an optimization shared with CALS for handling really long tables, because it lets the foot get rendered without waiting for the entire table to be processed ๐ฅ
For the visually impaired, HTML offers a chance to fix the damage caused by the rise of windows-based graphical user interfaces ๐ฅบ The HTML table model includes attributes for labeling each cell, which supports high-quality text to speech conversion ๐ The same attributes can also support automated import and export of table data to databases or spreadsheets ๐
Current desktop publishing packages have super rich control over how tables are rendered, and reproducing that in HTML would be impractical unless HTML turned into a bulky rich text format like RTF or MIF ๐ต This specification does, however, let authors choose from a set of commonly used classes of border styles ๐ The FRAME attribute controls the appearence of the border frame around the table, while the RULES attribute decides which rulings appear inside the table ๐ผ๏ธ
While this specification was being developed, a bunch of ideas were explored for specifying ruling patterns for tables ๐งฉ One problem was the kinds of statements that could be made. Including support for edge subtraction as well as edge addition led to really complicated algorithms ๐ For example, when the team explored letting the full set of table elements include the FRAME and RULES attributes, it led to an algorithm with some 24 steps just to decide whether a particular edge of a cell should be ruled or not ๐ฉ Even with all that complexity, it still didn't give enough rendering control to meet every need for tables ๐ So the current specification deliberately sticks to a simple, intuitive model that's enough for most purposes โจ More experimental work is needed before a more complex approach gets standardized ๐งช
A walk through the table DTD ๐ง
The table document type definition (DTD) is where the formal definition of allowed HTML table syntax lives ๐ What follows is an annotated listing of the DTD ๐ The complete listing is at the end of this document ๐
Heads up: the TABLE element is a block-like element, not a character-level element ๐จ That means it's a peer of other HTML block-like elements, like paragraphs, lists, and headers ๐งฑ
Common Attributes ๐
These attributes show up in several elements, so they're defined here to save space ๐ซถ In general, all attribute names and values in this specification are case insensitive, unless noted otherwise ๐ค The ID, CLASS and attributes are required for use with style sheets, while LANG and DIR are needed for internationalization ๐
<!ENTITY % attrs
"id ID #IMPLIED -- element identifier --
class NAMES #IMPLIED -- for subclassing elements --
lang NAME #IMPLIED -- as per RFC 1766 --
dir (ltr|rtl) #IMPLIED -- I18N text direction --">
ID ๐ชช
Used to define a document-wide identifier ๐ This can name positions within a document so they can be the destination of a hypertext link ๐ Style sheets can also use it to render one element in a unique style ๐จ An ID attribute value is an SGML NAME token ๐งฉ NAME tokens are formed by an initial letter followed by letters, digits, "-" and "." characters ๐ก The letters are restricted to A-Z and a-z ๐
CLASS ๐ท๏ธ
A space separated list of SGML NAME tokens ๐ซง CLASS names say that the element belongs to the corresponding named classes ๐๏ธ It lets authors tell apart the different roles played by the same tag ๐ญ Style sheets can use the classes to provide different renderings depending on those roles ๐
LANG ๐ฃ๏ธ
A LANG attribute identifies the natural language used by the content of the associated element. The syntax and registry of language values are defined by RFC 1766 ๐ Summed up: the language is a primary tag, followed by zero or more subtags separated by "-" โ๏ธ White space isn't allowed, and all tags are case insensitive ๐ โโ๏ธ The name space of tags is administered by IANA ๐๏ธ The two letter primary tag is an ISO 639 language abbreviation, and the initial subtag is a two letter ISO 3166 country code ๐บ๏ธ Example values for LANG include:
en, en-US, en-uk, i-cherokee, x-pig-latin.
DIR โก๏ธโฌ ๏ธ
Human writing systems are grouped into scripts, and scripts determine, among other things, which direction the characters are written ๐ Elements of the Latin script are nominally left to right, while elements of the Arabic script are nominally right to left ๐ These characters have what's called strong directionality ๐ช Other characters can be directionally neutral (spaces) or weak (punctuation) ๐ซง
The DIR attribute specifies an encapsulation boundary that governs how neutral and weakly directional characters are interpreted ๐ง It does not override the directionality of strongly directional characters ๐ The DIR attribute value is either LTR for left to right, or RTL for right to left, e.g. DIR=RTL ๐
When applied to TABLE, it indicates the geometric layout of rows (i.e. row 1 is on the right if DIR=RTL, but on the left if DIR=LTR) ๐ It also indicates a default base directionality for any text in the table's content, if no other DIR attribute applies to that text ๐
Horizontal and Vertical Alignment Attributes โจ
okay so you can set how cell contents line up on a cell by cell basis, or let them inherit from the stuff around them, like the row, the column, or the table itself ๐
ALIGN
this one handles the horizontal alignment of cell contents ๐
<!-- horizontal alignment attributes for cell contents -->
<!ENTITY % cell.halign
"align (left|center|right|justify|char) #IMPLIED
char CDATA #IMPLIED -- alignment char, e.g. char=':' --
charoff CDATA #IMPLIED -- offset for alignment char --"
>
the attribute value should be one of LEFT, CENTER, RIGHT, JUSTIFY and CHAR ๐ซถ user agents may treat JUSTIFY as left alignment if they lack support for text justification, so don't panic if it looks left-aligned ๐ญ and ALIGN=CHAR is what you use when you want everything lined up on one particular character ๐ฅ
for cells that span multiple rows or columns, where the alignment is inherited from the row or column, the initial row and column for the cell is what decides which alignment property gets used โจ
also, an alignment attribute on something inside the cell, like a P element, overrides the normal alignment for the cell. main character energy, the inner thing wins ๐
CHAR
this is used to pick the alignment character for use with align=char, e.g. char=":" ๐ง the default character is the decimal point for the current language, as set by the LANG attribute. and the CHAR attribute value is case sensitive, so be careful bestie ๐
CHAROFF
this specifies the offset to the first occurrence of the alignment character on each line. if a line doesn't have the alignment character at all, it should be shifted horizontally so it ends at the alignment position ๐ฆ
the direction of the cell (the resolved DIR, which comes from inheritance) decides whether the offset is measured from the left or the right margin. for Latin scripts it's from the left margin, and for Arabic scripts it's from the right margin ๐
in addition to standard units, you can use the "%" sign to say the value is a percentage offset of the current cell. so CHAROFF="30%" means the alignment character sits 30% of the way through the cell ๐
when you're using the two pass layout algorithm, the default alignment position (if there's no explicit or inherited CHAROFF) can be found by picking the position that would center lines where the width before and after the alignment character is at its max across the column's ALIGN=CHAR lines. for incremental table layout, the suggested default is CHAROFF="50%" ๐
if several cells in different rows of the same column use character alignment, then by default they should all line up, no matter which character each one uses ๐ซถ and the rules for objects that are too large for the column kick in whenever the explicit or implied alignment means the data is wider than the column's assigned width ๐
VALIGN
this defines whether the cell contents are aligned with the top, middle or bottom of the cell. it's the vertical glow-up ๐ฆ
<!-- vertical alignment attributes for cell contents -->
<!ENTITY % cell.valign
"valign (top|middle|bottom|baseline) #IMPLIED"
>
if it's present, the value should be one of: TOP, MIDDLE, BOTTOM or BASELINE โจ all cells in the same row with valign=baseline should be vertically positioned so the first text line in each of them lands on a common baseline. this constraint only applies to the first line though, not the subsequent text lines in those cells ๐ธ
Inheritance Order
alignment properties can be included with most of the table elements: COL, THEAD, TBODY, TFOOT, TR, TH and TD ๐
when rendering cells, horizontal alignment is decided by columns first (over rows), while for vertical alignment the rows matter more than the columns. it's giving priority drama ๐
here's the detailed precedence order for each attribute, where X > Y means X takes precedence over Y ๐
ALIGN, CHAR and CHAROFF:
cells > columns > column groups > rows > row groups > default
VALIGN, LANG, and DIR:
cells > rows > row groups > columns > column groups > table > default
so cells are the TH and TD elements, rows are TR elements, row groups are THEAD, TBODY and TFOOT, columns are COL elements, and column groups are COLGROUP and COL elements ๐ง and yes, there is no inheritance mechanism for the CLASS attribute, so that one stays put ๐
properties defined on cells take precedence over inherited properties, but they get over-ridden by alignment properties on elements inside the cells ๐ if there's no ALIGN attribute anywhere along the inheritance path, the recommended default alignment is ALIGN=LEFT for table data and ALIGN=CENTER for table headers. the recommended default for vertical alignment is VALIGN=MIDDLE โจ these defaults were picked to match the behaviour of the widely deployed Netscape implementation, so they're basically iconic history ๐ฆ
Standard Units for Widths
several attributes specify widths as a number followed by an optional suffix ๐ the suffix tells you the unit: pt is points, pi is picas, in is inches, cm is centimeters, mm is millimeters, em is em units (equal to the height of the default font), and px is screen pixels ๐
the default units are screen pixels, which were chosen for backwards compatibility ๐ซถ
the number can be an integer or a real valued number like "2.5". exponents, as in "1.2e2", are not allowed ๐ and there's no white space allowed between the number and the suffix, so 2 px is a no-go ๐
the set of suffixes is augmented for certain elements, though ๐ "%" is used for the WIDTH attribute on the TABLE element. it means the attribute gives the percentage width of the space between the current left and right margins, e.g. width="50%" โจ and for the COL element, "*" is used with the WIDTH attribute to specify relative column widths, e.g. width="3*", using the same representation as the CALS table model ๐
The TABLE element
the next stop is the TABLE element, and we're starting with its entity definition ๐ง
<!ENTITY % Where "(left|center|right)">
this one's just the set of allowed values for placement, and it's about to get a lot more interesting ๐ธ๐ฅ
<!ELEMENT table - - (caption?, (col*|colgroup*), thead?, tfoot?, tbody+)>
<!ATTLIST table -- table element --
%attrs; -- id, lang, dir and class --
align %Where; #IMPLIED -- table position relative to --
-- window --
width CDATA #IMPLIED -- table width relative to window --
cols NUMBER #IMPLIED -- used for immediate display mode --
border CDATA #IMPLIED -- controls frame width around --
-- table --
frame %Frame; #IMPLIED -- which parts of table frame to --
-- include --
rules %Rules; #IMPLIED -- controls rules between cells --
cellspacing CDATA #IMPLIED -- spacing between cells --
cellpadding CDATA #IMPLIED -- spacing within cells --
>
okay so the TABLE element needs both a start tag and an end tag, no skipping the closing one ๐. The order is the fun part ๐: it can start with an optional CAPTION, then either one or more COL elements or one or more COLGROUP elements, then an optional THEAD, an optional TFOOT, and finally one or more TBODY elements โจ.
ID, CLASS, LANG and DIR
Go back to the common attributes we covered earlier ๐ซถ
ALIGN
ALIGN is all about where the table sits between your left and right margins ๐ฆ. ALIGN=CENTER puts it smack in the middle ๐. ALIGN=LEFT parks it on the left margin, and ALIGN=RIGHT parks it on the right margin. User agents may flow text around the right-hand side of the table for ALIGN=LEFT, or the left-hand side for ALIGN=RIGHT ๐ธ.
Note you can use<BR CLEAR=LEFT>after the table element if you want to avoid text flowing along side the table when you have specified ALIGN=LEFT, or<BR CLEAR=RIGHT>for a right aligned table. To prevent a right aligned table flowing around something else, use<BR CLEAR=RIGHT>before the table etc. Greater control over textflow is possible using style sheets ๐ .
WIDTH
WIDTH sets the width you want for the table ๐. Besides the standard units, you can use a "%" sign so the width is a percentage of the space between the current left and right margins, like width="50%" ๐. If you leave this attribute out, the layout algorithm we'll get to later decides the table width ๐ง.
It's recommended that the table width grow past whatever WIDTH says when it has to, so the cell contents don't overflow ๐. Those increases should try to avoid big changes to the relative column widths the author set. To avoid needing tons of horizontal scrolling, or when scrolling is impractical or unwanted, it may be fine to split words across lines ๐.
COLS
COLS tells everyone how many columns the table has ๐. If it's there, the user agent may render the table on the fly as data comes in from the network, so you don't have to wait for the whole thing ๐ฅ. If WIDTH is missing, a default of "100%" may be assumed for this purpose โจ. If COLS is absent, the user agent needs a prepass through the table's contents to figure out the number of columns, plus good widths for each column ๐ญ.
BORDER
BORDER sets the width of the border framing the table. Check standard units for the details ๐.
FRAME
FRAME says which sides of the frame get drawn ๐ฆ.
<!ENTITY % Frame
"(void|above|below|hsides|lhs|rhs|vsides|box|border)">
VOID: Don't render any sides of the frame.ABOVE: The top side of the frame.BELOW: The bottom side of the frame.HSIDES: The top and bottom sides of the frame.LHS: The left hand side of the frame.RHS: The right hand side of the frame.VSIDES: The left and right sides of the frame.BOX: All four sides of the frame.BORDER: All four sides of the frame.
The value "Border" is here for backwards compatibility with browsers already out in the wild ๐ฐ๏ธ. If a document includes <TABLE BORDER>, the user agent will see FRAME=BORDER and BORDER=_implied_. If the document includes <TABLE BORDER=_n_>, the user agent should treat that as FRAME=BORDER, except when _n=0_, where FRAME=VOID is the right call ๐.
Note: it would have been nicer to pick FRAME values that match the RULES attribute and the alignment values. For example: none, top, bottom, topbot, left, right, leftright, all. Sadly, SGML requires enumerated attribute values to be unique for each element, no matter the attribute name ๐ฉ. That causes immediate problems for "none", "left", "right" and "all". So the FRAME values were picked to avoid clashing with RULES, ALIGN and VALIGN. That gives a bit of future proofing, since FRAME and RULES are expected to get added to other table elements in later revisions of this spec ๐ฎ. The other option would have been making FRAME a CDATA attribute. The HTML-WG agreed that being able to use SGML validation tools on enumerated values was worth more than having consistent names ๐ซถ.
RULES
RULES says where to draw lines inside the table ๐.
<!ENTITY % Rules "(none | groups | rows | cols | all)">
NONE: Suppresses internal rulings.GROUPS: The THEAD, TFOOT and TBODY elements split the table into row groups, and COLGROUP elements split it into column groups. This puts a horizontal rule between each row group and a vertical rule between each column group. Every table has at least one row and one column group, so you'll always see something ๐.ROWS: Same as RULES=GROUPS, plus horizontal rules between all rows. User agents may choose a heavier rule between groups of rows and columns for emphasis ๐ช.COLS: Same as RULES=GROUPS, plus vertical rules between all columns. User agents may choose a heavier rule between groups of rows and columns for emphasis ๐.ALL: Rules between all rows and all columns. User agents may choose a heavier rule between groups of rows and columns for emphasis โญ.
If a document includes <TABLE BORDER> or <TABLE BORDER=_n_>, the default for the table element is RULES=ALL, except when _n=0_, where RULES=NONE is right ๐.
CELLSPACING
This one is here for backwards compatibility with browsers already out there ๐ฐ๏ธ. It sets the space between the table frame and the first or last cell border for each row or column, and also the space between other cells in the table. Check standard units. Greater control will come with style sheet languages ๐ .
CELLPADDING
Also for backwards compatibility ๐ซถ. It sets the space between a cell's border and its contents, both above/below and left/right. Check standard units. Again, style sheet languages will give you more control ๐ง.
If a fixed width is set for the table or a column, CELLSPACING and CELLPADDING may need more space than was assigned ๐ญ. Current practice is for the latter to win over WIDTH attributes when they clash, although this spec doesn't require that ๐.
Table Captions โจ
<!ELEMENT caption - - (%text;)+>
<!ENTITY % Caption "(top|bottom|left|right)">
<!ATTLIST caption -- table caption --
%attrs; -- id, lang, dir and class --
align %Caption; #IMPLIED -- relative to table --
>
The optional CAPTION element gives the table a caption ๐. Both start and end tags are required ๐.
ID, CLASS, LANG and DIR
Same deal as before: see the common attributes we already covered ๐ซถ.
ALIGN
ALIGN controls where the caption goes relative to the table ๐ฆ. When it's there, ALIGN should have one of these values: TOP, BOTTOM, LEFT and RIGHT. It's recommended that the caption fits within the width or height of the table, as appropriate ๐ธ. The default position of the caption is deliberately left unspecified ๐คทโโ๏ธ.
Note the ALIGN attribute is overused in HTML, but it's kept here for compatibility with browsers that are already deployed ๐ .
The COLGROUP Element ๐
<!ELEMENT colgroup - O (col*)>
<!ATTLIST colgroup
%attrs; -- id, lang, dir and class --
span NUMBER 1 -- default number of columns in --
-- group --
width CDATA #IMPLIED -- default width for enclosed --
-- COLs --
%cell.halign; -- horizontal alignment in --
-- cells --
%cell.valign; -- vertical alignment in cells --
>
COLGROUP is a container for a group of columns, and it lets you set default properties for them ๐ง. If there's no COLGROUP element, every column in the table counts as belonging to one single column group ๐. Each COLGROUP can hold zero or more COL elements. COLGROUP needs a start tag, but the end tag can be left out, which is handy when you're defining a run of COLGROUPs ๐ซถ. Here's an example:
<TABLE FRAME=BOX RULES=COLS>
<COLGROUP>
<COL WIDTH="1*">
<COL WIDTH="2*">
<COLGROUP>
<COL WIDTH="1*">
<COL WIDTH="3*">
<THEAD>
<TR> ...
</TABLE>
COLGROUP elements can use these attributes:
ID, CLASS, LANG and DIR
Back to the common attributes we covered earlier ๐.
SPAN
SPAN is a positive integer that sets a default for how many columns are in this group. It should be ignored if the COLGROUP element has one or more COL elements inside it. It's a handy shortcut for grouping columns without writing out COL elements ๐.
WIDTH
WIDTH sets a default width for each grouped column. Check standard units for the details. The "*" suffix means relative widths too ๐ธ:
width=64 width in screen pixels
width=0.5* a relative width of 0.5
Relative widths act as constraints on how the widths of different columns relate to each other ๐ฆ. If a COLGROUP says its relative width is zero, all of the columns in that group should be set to their minimum widths, unless they're tied to a COL element with its own overriding WIDTH attribute ๐ญ. When widths are given in absolute units, the user agent can use them to constrain the width of the table ๐. The "*" suffix exists to make importing tables from the CALS representation easier ๐ .
ALIGN, CHAR, CHAROFF and VALIGN
These set values for horizontal and vertical alignment inside table cells. Check the inheritance order of alignment properties to see how they stack up ๐โจ.
The COL Element ๐
okay so COL is the element that lets you set column-based defaults for table properties ๐ It's EMPTY, which means no content, and you should never give it an end tag (bestie, don't do it ๐). You can stack several COL elements in a row, and their attributes override the ones on the parent COLGROUP. Iconic behaviour โจ
<!ELEMENT col - O EMPTY>
<!ATTLIST col -- column groups and --
-- properties --
%attrs; -- id, lang, dir and class --
span NUMBER 1 -- number of columns spanned --
-- by group --
width CDATA #IMPLIED -- column width specification --
%cell.halign; -- horizontal alignment in --
-- cells --
%cell.valign; -- vertical alignment in cells --
>
ID, CLASS, LANG and DIR ๐
See the earlier description of the common attributes. Nothing new here, just the usual squad ๐ซถ
SPAN ๐
SPAN is a positive integer that says how many columns this element applies to, and it defaults to one. If you don't use SPAN at all, the first COL hits the first column, the second COL hits the second column, and so on. Now watch this: if the second COL has SPAN=2, it covers the second AND third columns ๐ญ Then the next COL picks up at the fourth column, and the story keeps going from there.
SPAN=0 is the special one ๐ It means the COL spans every column from the current one all the way to the last column. And here's the tea: a COL SPAN does NOT make a group. It's just a sneaky way to share attribute definitions around ๐
WIDTH ๐
WIDTH sets the width of the columns (see the standard units section). If one element covers several columns, WIDTH is the width for EACH individual column, not the width of the whole span. Important, don't mix that up ๐
The * suffix means relative widths, like this:
width=64 width in screen pixels
width=0.5* a relative width of 0.5
Relative widths act as constraints on each other. If a COL gives a relative width of zero, that column should always be set to its minimum width ๐ When widths are in absolute units, the user agent can use them to constrain the width of the whole table. And the * suffix exists mainly to make it easier to import tables from the CALS representation, so it's giving practicality ๐ง
ALIGN, CHAR, CHAROFF and VALIGN ๐
These set values for horizontal and vertical alignment inside table cells. Check out the inheritance order of alignment properties for the full lore.
Table Head, Foot and Body Elements ๐ง
Okay the DTD for these three is giving structure ๐
<!ELEMENT thead - O tr+>
<!ELEMENT tfoot - O tr+>
<!ELEMENT tbody O O tr+>
<!ATTLIST (thead|tbody|tfoot) -- table section --
%attrs; -- id, lang, dir and class --
%cell.halign; -- horizontal alignment in --
-- cells --
%cell.valign; -- vertical alignment in cells --
>
So tables can be split into head and body sections. THEAD and TFOOT are optional, but you always need one or more TBODY elements, no exceptions โจ If your table is only a TBODY, you can skip its start and end tags, since the parser can figure them out. If you have a THEAD, its start tag is required, but the end tag can be left off as long as a TFOOT or TBODY start tag comes right after. Same deal for TFOOT ๐ซถ
Note: This definition keeps compatibility with tables made for the older model, and it also lets you drop the end tags for THEAD, TFOOT and TBODY. Literally so convenient ๐
These three elements are basically a control panel for rendering ๐๏ธ If there are tons of rows in the body, user agents might use a scrolling region for the table body sections. When you're printing to a paged device, tables often have to break across pages, and that's where THEAD, TFOOT and TBODY shine. They let the user agent repeat the table foot at the bottom of the current page, then repeat the table head at the top of the new page, and then keep going with the body ๐ฆ
TFOOT goes before TBODY in the markup, and that's on purpose ๐ฅ It means browsers can render the foot before they've received all of the table data. This is super useful for really long tables with scrolling body sections, or for paged output where the table gets broken over lots of pages.
Each THEAD, TFOOT and TBODY element must contain one or more TR elements ๐ธ
ID, CLASS, LANG and DIR ๐
See the earlier description of the common attributes.
ALIGN, CHAR, CHAROFF and VALIGN ๐
These specify values for horizontal and vertical alignment inside table cells. See the inheritance order of alignment properties.
Table Row (TR) elements ๐ฆฉ
Here's the DTD for TR, and it's giving very clear vibes:
<!ELEMENT tr - O (th|td)+>
<!ATTLIST tr -- table row --
%attrs; -- id, lang, dir and class --
%cell.halign; -- horizontal alignment in --
-- cells --
%cell.valign; -- vertical alignment in cells --
>
TR (table row) is basically a container that holds one row of table cells ๐ฆ The end tag is optional, so you can leave it off if you want to live dangerously ๐
ID, CLASS, LANG and DIR ๐
See the earlier description of the common attributes.
ALIGN, CHAR, CHAROFF and VALIGN ๐
These specify values for horizontal and vertical alignment inside table cells. See the inheritance order of alignment properties.
Table Cells: TH and TD ๐ฐ
The DTD for cells is the main event ๐
<!ELEMENT (th|td) - O %body.content>
<!ATTLIST (th|td) -- header or data cell --
%attrs; -- id, lang, dir and class --
axis CDATA #IMPLIED -- defaults to cell content --
axes CDATA #IMPLIED -- list of axis names --
nowrap (nowrap) #IMPLIED -- suppress word wrap --
rowspan NUMBER 1 -- number of rows spanned by --
-- cell --
colspan NUMBER 1 -- number of cols spanned by --
-- cell --
%cell.halign; -- horizontal alignment in --
-- cells --
%cell.valign; -- vertical alignment in cells --
>
TH is for header cells and TD is for data cells ๐ This lets user agents render them differently even when there are no style sheets, so the headers can stand out and not blend in with the data.
Cells can span multiple rows and columns, and they're allowed to be empty too. A cell that spans rows adds to the column count on each row it covers, but it only shows up in the markup once, in the first row it spans. The row count comes from the number of TR elements. Any extra rows implied by row-spanning cells past that count should be ignored ๐
If the table's column count is bigger than the number of cells in a row (after counting cells from spanned rows), the missing cells are treated as sitting on the right hand side of the table and rendered as empty cells. But if the language context says the writing order is right to left, the missing cells should go on the left hand side instead ๐
Tables can also have overlapping cells, which is a whole mood ๐ญ Here's an example:
<table border>
<tr><td rowspan=2>1<td>2<td>3
<tr><td rowspan=2>4
<tr><td colspan=2>5<td>6
</table>
And it might look something like this:
/-----------\
| 1 | 2 | 3 |
| |-------|
| | 4 | |
|---|...|---|
| 5 : | 6 |
\-----------/
In this example, the cells labelled 4 and 5 overlap. When that happens, how it's rendered is implementation dependent ๐
The AXIS and AXES attributes give you a way to define concise labels for cells. When rendering to speech, these can supply abbreviated names for the headers that go with each cell. They're also handy if you want to process the table contents later and load them into a database, since then they become the database field names. The table's class attribute should be used to let the software recognise which tables can be treated that way ๐ง
ID, CLASS, LANG and DIR ๐
See the earlier description of the common attributes.
AXIS ๐ท๏ธ
AXIS defines an abbreviated name for a header cell, for example one that can be used when rendering to speech. It defaults to the cell's content.
AXES ๐บ๏ธ
AXES is a comma separated list of axis names which together identify the row and column headers that pertain to this cell. It's used for example when rendering to speech, to figure out where the cell sits in the table. If it's missing, the user agent can try to follow up columns and left along rows (right for some languages) to find the matching header cells.
NOWRAP, e.g. <TD NOWRAP> ๐
If this attribute is present, automatic wrapping of text lines gets turned off for this cell. Be careful with it, because if you use it uncautiously it can make cells excessively wide ๐ฌ It's only defined for backwards compatibility with user agents that are already out there. You get more control with the associated style sheet languages (for example, for overflow handling).
ROWSPAN, e.g. <TD ROWSPAN=2> ๐
ROWSPAN is a positive integer that defines how many rows this cell spans. The default ROWSPAN is 1. ROWSPAN=0 is special and means the cell spans all rows from the current row up to the last row of the table ๐
COLSPAN, e.g. <TD COLSPAN=2> ๐
COLSPAN is a positive integer that defines how many columns this cell spans. The default COLSPAN is 1. COLSPAN=0 is special too, and means the cell spans all columns from the current column up to the last column of the table ๐
ALIGN, CHAR, CHAROFF and VALIGN ๐
These specify values for horizontal and vertical alignment inside table cells. See the inheritance order of alignment properties.
Note: It is recommended that implementors provide support for the Netscape 1.1 WIDTH attribute for TH and TD, although this isn't part of the current specification. Document authors are advised to use the width attribute for the COL element instead. Bestie, use COL for widths, not the old one ๐ซถ
Recommended Layout Algorithms ๐งฎ
Here's the layout tea โ If the COLS attribute on the TABLE element specifies the number of columns, then the table may be rendered using a fixed layout. Otherwise, the autolayout algorithm described below should be used ๐
Fixed Layout Algorithm
okay so the fixed layout algorithm is for when you already know how many columns the table has ๐ The default move is to make every column the same width, but authors can override that with relative or absolute widths using the COLGROUP or COL elements ๐ The default table width is the space between the current left and right margins, unless the WIDTH attribute on the TABLE element overrides it or the absolute column widths set it ๐ When you're mixing absolute and relative widths, you first hand out space to the absolute columns, and whatever's left gets split between the relative ones โจ
the table syntax by itself can't guarantee that attribute values agree with each other ๐ญ for example, the number of columns in the COLS attribute might not match the number implied by the COL elements, and that might not match the number implied by the table cells either ๐ overflow is another mess, because if the columns are too narrow, cell contents can spill out ๐ user agents are recommended to recover gracefully here, for instance by hyphenating words and falling back to splitting words when there's no known hyphenation point ๐ซถ
if an indivisible element causes cell overflow, the user agent may consider adjusting the column widths and re-rendering the table ๐ฅ in the worst case, clipping may be considered if adjusting widths and/or scrollable cell content isn't feasible ๐ฌ whatever happens, if cell content gets split or clipped, that should be shown to the user in an appropriate way ๐ธ
Autolayout Algorithm
if the COLS attribute is missing from the table start tag, the user agent should use this autolayout algorithm ๐ง it makes two passes over the table data and scales linearly with the table's size, which is honestly so efficient ๐ญ
in the first pass, line wrapping gets turned off, and the user agent tracks the minimum and maximum width of each cell ๐ the maximum width is the widest line, and since wrapping is off, paragraphs count as long lines unless <BR> elements break them up ๐ the minimum width is the widest word or image (and so on), counting leading indents and list bullets too ๐ฆ basically, imagine formatting the cell's content in its own window, and figure out how narrow that window can get before the cell starts overflowing โจ letting user agents split words cuts down on horizontal scrolling and on clipping in the worst case ๐
nested tables inside cell content get the same treatment ๐ช their minimum and maximum widths feed into the minimum and maximum widths of the nested table, and from there into the parent table cell itself ๐ the algorithm stays linear with the total cell content, and it's pretty much independent of how deeply things are nested ๐
to handle character alignment in cell contents, the algorithm keeps three running min/max totals per column: left of the align char, right of the align char, and un-aligned ๐ the minimum width for a column is then max(min_left + min_right, min_non-aligned) ๐ข
the minimum and maximum cell widths get used to work out the matching minimum and maximum column widths, which then give the minimum and maximum width for the whole table ๐ cells can hold nested tables, but that doesn't make the code much harder ๐ซถ the next step is assigning column widths based on the space available, which is the space between the current left and right margins ๐ฉท
for cells spanning multiple columns, one simple approach (used by Arena) is to split the min/max widths evenly across the columns involved ๐ฐ a slightly fancier approach is to use the min/max widths of unspanned cells to weight how the spanned widths get split ๐ง experiments showed that a blend of the two works well for a wide range of tables ๐
the table borders and intercell margins have to be counted when assigning column widths, and there are three cases ๐
- the minimum table width is equal to or wider than the available space. in this case, assign the minimum widths and let the user scroll horizontally. for conversion to braille, the cells have to be replaced by references to notes holding their full content, and by convention those notes come before the table ๐
- the maximum table width fits inside the available space. in this case, set the columns to their maximum widths ๐
- the maximum width of the table is bigger than the available space, but the minimum table width is smaller. in this case, find the difference between the available space and the minimum table width, and call that W. also call D the difference between the maximum and minimum width of the table ๐งฎ
for each column, let d be the difference between its maximum and minimum width. then set the column's width to the minimum width plus d times W over D. this means columns with big gaps between their minimum and maximum widths end up wider than columns with smaller gaps ๐
this assignment step gets repeated for nested tables, using the minimum and maximum widths worked out for all of them in the first pass ๐ช in that case, the width of the parent (enclosing) table cell plays the role of the current window size ๐ผ๏ธ this repeats recursively for every nested table ๐ the topmost table then gets rendered with the assigned widths, and nested tables are rendered as part of the parent table's cell contents ๐ฆ
if the table width is set with the WIDTH attribute, the user agent tries to match the column widths to it ๐ฏ the WIDTH attribute isn't binding if that would leave any column narrower than its minimum (indivisible) width ๐ โโ๏ธ
if relative widths are set with the COL element, the algorithm changes so columns can grow past their minimum width to meet the relative width constraints ๐ COL elements should be treated as hints only, so no column should go below its minimum width ๐ท columns also shouldn't get so wide that the table sticks out well past the window ๐ช if a COL element gives a relative width of zero, that column should always be set to its minimum width ๐ซ
HTML Table DTD
the DTD (document type definition) is the formal definition of which syntax is allowed for HTML tables ๐ here it is, in all its glory ๐
<!-- Content model entities imported from parent DTD:
%body.content; allows table cells to contain headers, paras,
lists, form elements and even arbitrarily nested tables.
%text; is text characters, including character entities and
character emphasis elements, IMG and anchors
-->
<!ENTITY % attrs
"id ID #IMPLIED -- element identifier --
class NAMES #IMPLIED -- for subclassing elements --
lang NAME #IMPLIED -- as per RFC 1766 --
dir (ltr|rtl) #IMPLIED -- I18N text direction --">
<!--
The BORDER attribute sets the thickness of the frame around the
table. The default units are screen pixels.
The FRAME attribute specifies which parts of the frame around
the table should be rendered. The values are not the same as
CALS to avoid a name clash with the VALIGN attribute.
The value "border" is included for backwards compatibility with
<TABLE BORDER> which yields frame=border and border=implied
For <TABLE BORDER=1> you get border=1 and frame=implied. In this
case, its appropriate to treat this as frame=border for backwards
compatibility with deployed browsers.
-->
<!ENTITY % Frame "(void|above|below|hsides|lhs|rhs|vsides|box|border)">
<!--
The RULES attribute defines which rules to draw between cells:
If RULES is absent then assume:
"none" if BORDER is absent or BORDER=0 otherwise "all"
-->
<!ENTITY % Rules "(none | groups | rows | cols | all)">
<!-- horizontal placement of table relative to window -->
<!ENTITY % Where "(left|center|right)">
<!-- horizontal alignment attributes for cell contents -->
<!ENTITY % cell.halign
"align (left|center|right|justify|char) #IMPLIED
char CDATA #IMPLIED -- alignment char, e.g. char=':' --
charoff CDATA #IMPLIED -- offset for alignment char --"
>
<!-- vertical alignment attributes for cell contents -->
<!ENTITY % cell.valign
"valign (top|middle|bottom|baseline) #IMPLIED"
>
<!ELEMENT table - - (caption?, (col*|colgroup*), thead?, tfoot?, t
body+)>
<!ELEMENT caption - - (%text;)+>
<!ELEMENT thead - O (tr+)>
<!ELEMENT tfoot - O (tr+)>
<!ELEMENT tbody O O (tr+)>
<!ELEMENT colgroup - O (col*)>
<!ELEMENT col - O EMPTY>
<!ELEMENT tr - O (th|td)+>
<!ELEMENT (th|td) - O %body.content>
<!ATTLIST table -- table element --
%attrs; -- id, lang, dir and class --
align %Where; #IMPLIED -- table position relative to --
-- window --
width CDATA #IMPLIED -- table width relative to window --
cols NUMBER #IMPLIED -- used for immediate display mode --
border CDATA #IMPLIED -- controls frame width around --
-- table --
frame %Frame; #IMPLIED -- which parts of table frame to --
-- include --
rules %Rules; #IMPLIED -- rulings between rows and cols --
cellspacing CDATA #IMPLIED -- spacing between cells --
cellpadding CDATA #IMPLIED -- spacing within cells --
>
<!-- ALIGN is used here for compatibility with deployed browsers -->
<!ENTITY % Caption "(top|bottom|left|right)">
<!ATTLIST caption -- table caption --
%attrs; -- id, lang, dir and class --
align %Caption; #IMPLIED -- relative to table --
>
<!--
COLGROUP groups a set of COL elements. It allows you to group
several columns together.
-->
<!ATTLIST colgroup
%attrs; -- id, lang, dir and class --
span NUMBER 1 -- default number of columns in --
-- group --
width CDATA #IMPLIED -- default width for enclosed COLs --
%cell.halign; -- horizontal alignment in cells --
%cell.valign; -- vertical alignment in cells --
>
<!--
COL elements define the alignment properties for cells in a given
column or spanned columns. The WIDTH attribute specifies the
width of the columns, e.g.
width=64 width in screen pixels
width=0.5* relative width of 0.5
-->
<!ATTLIST col -- column groups and properties --
%attrs; -- id, lang, dir and class --
span NUMBER 1 -- number of columns spanned by --
-- group --
width CDATA #IMPLIED -- column width specification --
%cell.halign; -- horizontal alignment in cells --
%cell.valign; -- vertical alignment in cells --
>
Okay bestie, the table stuff is where the magic really happens ๐ Here's how the header, footer, and body sections work together ๐ธ
<!--
Use THEAD to duplicate headers when breaking table
across page boundaries, or for static headers when
body sections are rendered in scrolling panel.
Use TFOOT to duplicate footers when breaking table
across page boundaries, or for static footers when
body sections are rendered in scrolling panel.
Use multiple TBODY sections when rules are needed
between groups of table rows.
-->
<!ATTLIST (thead|tbody|tfoot) -- table section --
%attrs; -- id, lang, dir and class --
%cell.halign; -- horizontal alignment in cells --
%cell.valign; -- vertical alignment in cells --
>
<!ATTLIST tr -- table row --
%attrs; -- id, lang, dir and class --
%cell.halign; -- horizontal alignment in cells --
%cell.valign; -- vertical alignment in cells --
>
<!ATTLIST (th|td) -- header or data cell --
%attrs; -- id, lang, dir and class --
axis CDATA #IMPLIED -- defaults to cell content --
axes CDATA #IMPLIED -- list of axis names --
nowrap (nowrap) #IMPLIED -- suppress word wrap --
rowspan NUMBER 1 -- number of rows spanned by cell --
colspan NUMBER 1 -- number of cols spanned by cell --
%cell.halign; -- horizontal alignment in cells --
%cell.valign; -- vertical alignment in cells --
>
So the big idea ๐ง is that THEAD repeats your headers when a table gets split across pages, or keeps them pinned when the body scrolls in its own panel ๐ TFOOT does the same job for footers ๐ฆ And TBODY is how you add rules between groups of rows, so you can section off your table like a pro ๐
Every row lives in a TR ๐ and every cell is either a TH (header) or a TD (data) ๐ Both cells take axis, axes, nowrap, rowspan, and colspan, plus the usual id, lang, dir, and class attributes from %attrs; ๐ The rowspan and colspan values default to 1, which means "just one, thank you" ๐
References
Arena W3C's HTML3 browser, see http://www.w3.org/pub/WWW/Arena/. Arena started life as a proof of concept demo for ideas in the HTML+ specification that came before HTML3 ๐ธ It's now being re-implemented as a reference implementation of HTML3, with support for style sheets and client-side scripting โจ iconic behaviour, honestly ๐ญ
CALS Continuous Acquisition and Life-Cycle Support (formerly Computer-aided Acquisition and Logistics Support) (CALS) is a Department of Defense (DoD) strategy for achieving effective creation, exchange, and use of digital data for weapon systems and equipment ๐ซถ More information is on the US Navy CALS home page at http://navysgml.dt.navy.mil/cals.html ๐ฅ
HTML 2.0 (RFC1866) Hypertext Markup Language Specification Version 2.0 by T. Berners-Lee and D. Connolly, November 1995 ๐ Further information can be found at http://www.w3.org/pub/WWW/MarkUp/ or at ftp://ds.internic.net/rfc/rfc1866.txt ๐
HTML 3.0 Hypertext Markup Language Specification Version 3.0 ๐ง The initial draft specification was published in March 1995 โญ Work on refining HTML3 is proceeding piecemeal, with the new table specification as one of the pieces ๐
For W3C related work on HTML, see http://www.w3.org/pub/WWW/MarkUp/.
RFC 1766 "Tags for the Identification of Languages", by H. Alvestrand, UNINETT, March 1995 ๐ฆ This document can be downloaded from ftp://ds.internic.net/rfc/rfc1766.txt.
Security Considerations
Security issues are not discussed in this memo ๐ Nothing to see here, bestie, this one's all about tables ๐
Author's Address
Dave Raggett W3C
EMail: dsr@w3.org
The World Wide Web Consortium: http://www.w3.org/ ๐
๐ฆ where this page comes from
- ietf: rfc1942 1996-05
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms