SEO

October 17, 2011

CSS Commenting! Are you kidding me? i thought you were just talking to yourselvecss...

Comparing style sheet languages

The table below compares how various style sheet languages express common (are they?) tasks. Text in red indicates that I'm not quite sure if the code is correct. Help with proofreading the examples, as well a filling in the open cells, is appreciated.

Challenge CSS FOSI DSSSL XSL P93 (which is the internal style language of Amaya/Thotlib, anno 1993) PSL
Set the font size of all "H1" elements to 20pt
H1 { font-size: 20pt }
<e-i-c gi="H1"> <charlist> <font inherit="1" size="20pt"> </charlist> </e-i-c>

Note: The "font" category sets all font characteristics (like the shorthand properties in CSS). The "inherit" attribute determines if the other font charateristics (weight etc.) should come from the default "docdesc" enviroment or from the parent element.

(element H1 (make paragraph font-size: 20pt))
<xsl:template match="H1"> <fo:block font-size="20pt"> <xsl:apply-templates/> </fo:block> </xsl:template>
H1: Size: 20 pt;
Set H1's font size to the double of the parent
H1 { font-size: 2em }
<e-i-c gi="H1"> <charlist> <font size="2em"> </charlist> </e-i-c>
(element H1 (make paragraph font-size: (* 2 (inherited-font-size))))
<xsl:template match="H1"> <fo:block font-size="2em"> <xsl:apply-templates/> </fo:block> </xsl:template>
H1: Size: Enclosing * 200 %;
Set H1's font size to be 4pt bigger than the parent not possible
(element H1 (make paragraph font-size: (+ 4pt (inherited-font-size))))
<xsl:template match="H1"> <fo:block font-size="from-parent() + 4pt"> <xsl:apply-templates/> </fo:block> </xsl:template>
H1: Size: Enclosing + 4 pt;
Set H1's font size to the double of the root element's font size not possible not possible

This solution is close to the challenge:

(define base-size 12pt)  (element H1 (make paragraph font-size: (* 2 base-size)))
(define-unit em 12pt) (element BODY (make paragraph font-size: 1em)) (element H1 (make paragraph font-size: 2em)) -->
not possible
Selectors Selectors Selectors Selectors Selectors Selectors Selectors
Select all LI elements that are children of OL
OL > LI { ... }
<e-i-c gi="LI" context="OL"> <charlist> ... </charlist> </e-i-c>
(element (ol li) ...)
<xsl:template match="ol/li"> ... </xsl:template>
LI: begin if immediately within OL ... end;
Select all LI element with an OL ancestor
OL LI { ... }
<e-i-c gi="LI" context="* OL"> <charlist> ... </charlist> </e-i-c>
(element LI (if (not (node-list-empty? (ancestor "OL"))) ... ))
<xsl:template match="ol//li"> ... </xsl:template>
LI: begin if within OL ... end;
Select any P element that is the first child element of its parent
P:first-child { ... }
Not possible (although there are DTD-based tricks to make it happen).
(element P (if (absolute-first-sibling? (current-node)) ... ...))
<xsl:template match="*[position()=1 and self::p]"> ... </xsl:template>
P: if first ...

Note that this condition can only be used for certain properties.

Select any P element that is the first P child element of its parent not possible in CSS2, but is proposed for CSS3:
P:first-of-type { ... }
<e-i-c gi="P" occur="first"> <charlist> ... </charlist> </e-i-c>
(element P (if (first-sibling? (current-node)) ... ...))
<xsl:template match="P[1]"> ... </xsl:template>
not possible
Set properties/characteristics on all elements with a WARNING attibute
.WARNING { ... }
Set properties/characteristics on all NOTE elements with a WARNING attibute
NOTE[WARNING] { ... }
<e-i-c gi="NOTE"> <att> <specval attname="WARNING" attval="#ANY"> <charsubset> ... </charsubset> </att> </e-i-c>
(element NOTE (if (not (node-list-empty? (attribute "WARNING"))) ... ...))
NOTE: if WARNING ...
In a table, select all odd-numbered rows. not possible in CSS2, but the Selector module (currently in CR) proposes:
tr:nth-child(odd)  { ... }

or

tr:nth-child(2n+1) { ... }
not possible
(element TR (if (= (modulo (child-number) 2) 0) ...   ;even-row ...)) ;odd-row
<xsl:template match="tr[position() mod 2 = 1]"> ... </xsl:template>
tr: if odd(rowcounter) ...

"rowcounter" should be declared in the COUNTERS section of the style sheet as:

COUNTERS rowcounter: rank of tr;

Like the "first" condition, this condition only applies to certain properties.

Select all elements
* { ... }
Properties Properties Properties Properties Properties Properties Properties
[challenge]
Formatting model boxes inside boxes area model (seqence of block-level areas with inline areas inside) area model (seqence of block-level areas (called "display" areas) with inline areas inside) boxes inside boxes (although XSL calls it an "hierarchical area model") boxes inside boxes
Absolute or relative properties? All properties, except 'text-indent', are absolute. Examples: margin-left, padding-top, border-bottom Mixed model: horizontal margins are absolute (leftind, rightind), while vertical margins are relative (presp, postsp). Also, margins on the page are absolute (topmarg, botmarg, leftmarg, rightmarg) Most properties are relative: space-before, space-after, start-margin, end-margin. On the simple-page-sequence flow object, there are some absolute properties, e.g.: left-margin, right-margin, top-margin, bottom-margin, left-footer, center-footer, right-footer Mixed model All properties, except 'indent', are abssolute. The positioning of boxes and margins are done through these properties: VertRef, HorizRef, VertPos, HorizPos
Values/units Values/units Values/units Values/units Values/units Values/units Values/units
List all length units
pc picas  pt points  in inches  mm millimeters  cm centimeters  em em space px pixels ex  %
pi picas  pt points  in inches  mm millimeters  cm centimeters  em em space

The base unit for DSSSL is the meter, m. Pre-defined derived units are:

(define-unit cm 0.01m) (define-unit mm 0.001m) (define-unit in 0.0254m) (define-unit pt 0.0003527778m) (define-unit pica 0.004233333m)

DSSSL does not support relative lengths as units - the inherited values can be used in most cases for that behavior.

P has been extended to support the same units as CSS: cm, mm, pt, pc, in, px, em, ex, %
Value propagation Value propagation Value propagation Value propagation Value propagation Value propagation Value propagation
[challenge]
Formatting model Formatting model Formatting model Formatting model Formatting model Formatting model Formatting model
Give the printed a page a 1.5 inch margin on each edge.
@page { margin: 1.5in; }
<pagedesc> <pagespec> <topmarg nomdepth="1.5in"> <botmarg nomdepth="1.4in"> <leftmarg width="1.5in"> <rightmarg width="1.5in"> </pagespec> </pagedesc>

[is the pgid attribute on pagespec required?]

MyPage: begin MarginTop: 1.5 in; MarginBottom: 1.5 in; MarginLeft: 1.5 in; MarginRight: 1.5 in; end;

P has a broad notion of a box. Not only every element in the source document has a box, but you can define additional boxes in a style sheet and you have creation "properties" that generate those boxes. Pages are just such generated boxes. You define them with the same properties as any other box. The only specific thing for a page box is that its parent box is the physical support (sheet of paper, window, etc.)

Indent the first line of PARA elements 2em relative to the other text in the paragraph
PARA { text-indent: 2em }
<e-i-c gi="PARA"> <charlist> <indent inherit="1" firstln="*+2em"> </charlist> </e-i-c>

Note: the asterisk refers to the resolved indetation of the paragraph.

(element PARA (make paragraph first-line-start-indent: (* 2 (actual-font-size))))

(The above fragment is based on an example from the The DSSSL Cookbook.

<xsl:template match="PARA"> <fo:block text-indent="2em"> <xsl:apply-templates/> </fo:block> </xsl:template>
PARA: indent: 2 em;
Give BLOCKQUOTE elements 1em horizontal indentation relative to the parent's box.
BLOCKQUOTE { margin-left: 1em; margin-right: 1em; }
<e-i-c gi="BLOCKQUOTE"> <charlist> <indent firstln="*" leftind="@+1em" rightind="@+1em"> </charlist> </e-i-c>

Note: the indentation of the first line must be set explicitly to make sure the first line has the same indentation as the rest of the paragraph.

<xsl:template match="BLOCKQUOTE"> <fo:block margin-left="1em" margin-right="1em"> <xsl:apply-templates/> </fo:block> </xsl:template>
BLOCKQUOTE: begin MarginLeft: 1 em; MarginRight: 1 em; end;
Give BLOCKQUOTE elements 1em horizontal indentation relative to the layout area (i.e., the area into which the content is poured) without taking the elements out of the flow. Not possible. It could be done if the element is taken out of the flow:
BLOCKQUOTE { position: fixed; left: 50%; margin-left: -1em; }
<e-i-c gi="BLOCKQUOTE"> <charlist> <indent firstln="*" leftind="1em" rightind="1em"> </charlist> </e-i-c>
(element BLOCKQUOTE (make paragraph start-indent: (* 1 (actual-font-size)) end-indent: (* 1 (actual-font-size)) ))
<xsl:template match="BLOCKQUOTE"> <fo:block start-indent="1em" end-indent="1em"> <xsl:apply-templates/> </fo:block> </xsl:template>
BLOCKQUOTE: HorizPos: Left = Root.Left + 1 em;

If the document is paginated, Root represents the page box, if there is no page, Root is the box associated with the root element of your document.

Place the left content edge of a BLOCKQUOTE element 1em to the left of the middle of the layout area (i.e., the area into which the content is poured). not possible
BLOCKQUOTE:  HorizPos: Left = Enclosing.VMiddle - 1 em;

VMiddle is the vertical middle axis.

specify that content should flow into two columns not possible, but suggested for CSS3 Here's a starting point:
<pagedesc>  <pagespec pgid="idinfospec"> <topmarg nomdepth="36pt"> <botmarg nomdepth="36pt"> <leftmarg width="72pt"> <rtmarg width="36pt"> <header nomdepth="36pt"> <vquad verquad="top"> <sectext> <subchars></subchars> </sektext> <header></header> <footer nomdepth="36pt"> <vquad verquad="top"> <sectext> <subchars></subchars> </sectext> </footer> <flowtext width="504pt" nomdepth="684pt" numcols="1" spabove="18pt"  spabelow="6pt">  <column width="5O4pt" mindepth="648pt" nomdepth="684pt"  maxdepth="684pt">  </flowtext>  </pagespec> </pagedesc>
[table challenge]
[floating element challenge]
Linking Linking Linking Linking Linking Linking Linking
Import a style sheet from another location, then override some of the settings
@import url(http://www.example.com/style); H1 { font-size: 2em }
Not possible. Not possible.
Generated text Generated text Generated text Generated text Generated text Generated text Generated text
Given this markup
<NOTE>Platform shoes are back!</NOTE>
It will be displayed like this:
Warning: Platform shoes are back!
NOTE:before {  font-weight: bold; content: "Warning"; }
(element note (make paragraph font-size: 12pt (make sequence font-weight: 'bold (literal "Warning:")) (process-children)))
Add the text "Chapter x:" before all H1 elements where "x" is replaced by an incrementing chapter number
H1:before { content: "Chapter " counter(chaptercounter) ": "; counter-increment: chaptercounter; }
<e-i-c gi="H1"> <charlist> {other H1 characteristics} <enumerat increm="1" enumid="chaptercounter"> <usetext placemnt="before" source="\Chapter \,chaptercounter,\: \"> </usetext> </charlist> </e-i-c>
(define (preced-count node gilist) (node-list-length (node-list-filter (lambda (n1) (member (gi n1) gilist) ) (preced node) ) ) )   (define countable-elements '("H1"))  (define (number-clause node top-level) (case (gi node) (("ROOT-NODE-GI") (list) ) (else (if top-level (list (+ (preced-count node countable-elements) 1)) (cons (+ (preced-count node countable-elements) 1) (number-clause (parent node) top-level) ) ) ) ) )  (define (number-heading node top-level) (literal (format-number-list (reverse (number-clause node top-level)) "1" ".")))  (element H1 (make sequence (number-heading (parent (current-node)) #t) (literal " ") (process-children) ) )

(The above fragment is based on an example from the The DSSSL Cookbook. I'm quite sure the last bit is incomplete...)

<xsl:template match="H1"> <fo:block> <xsl:text>Chapter </xsl:text> <xsl:number level="any" count="H1"/> <xsl:text>: </xsl:text> <xsl:apply-templates/> </fo:block> <xsl:template>

You have to do that at 3 different places in a P style sheet. In the COUNTERS section you define a counter:

COUNTERS ChapterNumber: set 0 on BODY add 1 on H1;

in the BOXES section you define the box that will be generated for each H1 element. This box uses the counter in its content:

BOXES ChapNumBox: begin content: (text 'Chapter ' value(ChapterNumber, Arabic) text':'); size: creator =; ... more properties end;

then you associate a "create" property to H1 elements:

H1: begin createbefore (ChapNumBox); size: 200 %; ... end;
Given this markup:
<p>... some notion<fn>The word is used here in the sense of the German philosopher B. Ratwurst, not that of the French anthropologist M.A. Gret-de-Canard</fn> which obviously... </p>

Make the content of the "fn" element appear in a footnote. Add a superscripted number in front of the footnote. Mark the original position of the "fn" element with the same superscripted number (a so-called «callout»). Make the footnote counter reset on every page. Mark the top of the footnote area with a horizontal rule.

Not possible, but here is a proposed solution for CSS3:
fn { display: footnote; footnote-style-type: decimal; footnote-style-position: outside; footnote-style-reset: page;  }  @footnote { border-top: thin solid black; }  ::trace, ::marker {  vertical-align: superscript; font-size: 6pt; }
or
fn { display: footnote; }  @footnote { border-top: thin solid black; list-style-type: decimal; list-style-position: outside; list-style-reset: page;  }  ::trace, ::marker {  vertical-align: superscript; font-size: 6pt; }
<rsrcdesc> <counter style="arabic" enumid="fnc"> </rsrcdesc>  <ftndesc> <e-i-c gi="fn">  <!-- typeset callout in flowtext --> <charlist inherit="1"> <enumerat increm="1" enumid="fnc"> <usetext source="fnc">  <subchars>  <font inherit="1" size="6pt" offset="4pt"> </subchars> </charlist> </e-i-c> <ftnatts> <!-- typeset superscript and footnote text in footnote area --> <charlist> <font size="8pt"> <presp nominal="3pt">  <textbrk startln="1">  <usetext source="fnc" placemnt="before"> <subchars> <font size="6pt" offset="4pt"> </subchars> </usetext> </ftnatts> </ftndesc>

How do we make sure the counter is reset on every page? How can the counter be placed "outside"? How can we add the horizontal rule?

<xsl:template match="p"> <fo:block> <xsl:apply-templates> <xsl:with-param name="fn_number"> <xsl:number/> </xsl:with-param> </xsl:apply-templates> </fo:block> </xsl:template>  <xsl:template match="fn"> <xsl:param name="fn_number" select="'1'"/> <fo:footnote> <fo:inline font-size="smaller" baseline-shift="super"><xsl:value-of select="$fn_number"/></fo:inline> <fo:footnote-body> <fo:inline baseline-shift="super"> <xsl:attribute name="font-size"><xsl:value-of select="$fn_size_xsl_variable"/></xsl:attribute> <xsl:value-of select="$fn_number"/> </fo:inline> <xsl:apply-templates/> </fo:footnote-body> </fo:footnote> </xsl:template>

Also, one must generate a static-content:

<fo:static-content flow-name="xsl-footnote-separator"> <!-- 1.0pt solid rule, likely black to start --> <fo:leader leader-pattern="rule" leader-length.maximum="100%"/> </fo:static-content>

This will get used automatically.

Note that a size has been defined in a stylesheet global variable, called "fn_size_xsl_variable", for the footnote number size in the actual footnote.

not possible
[header/footer challenge] Not possible.

The challenges are meant to reflect needs of authors, but are also designed to show off crucial differeneces and similarities in the various style sheet languages. Bert Bos has suggested some of the challenges, feel free to suggest more. For an alternative list of challenges, see Jon Bosak's list from 1997.

Thanks to Paul Grosso for contributing style sheet fragments and explanations for FOSI and XSL.

Thanks to Christopher R. Maden for contributing style sheet fragments and explanations for DSSSL.

Thanks to Arved Sandstrom for contributing XSL fragments.

Thanks to Vincent Quint for contributing the "P" examples. He has also written an short description of the P formatting model:

In P, the position of a box is not predefined. You have to set the position of every box with two properties: VertPos and HorizPos. (of course, in a style sheet you can also define default rules that apply to all boxes except those with specific rules). The advantage is that you don't need to have different kinds of boxes in the model. For instance, P does not know anything about tables, rows and cells. Those boxes are plain P boxes. They just have appropriate position properties in the default HTML style sheet. The P engine does not know either about the layout of mathematics. The MathML P style sheet uses position properties to define the position of each subexpression in a math expression.

Comparing style sheet languages The table below compares how various style sheet languages express common (are they?) tasks. Text in red indicates that I'm not quite sure if the code is correct. Help with proofreading the examples, as well a filling in the open cells, is appreciated. The challenges ...»See Ya