Quin, Liam. “CSS Within: An application of the principle of locality of reference
to CSS and XSLT.” Presented at Balisage: The Markup Conference 2021, Washington, DC, August 2 - 6, 2021. In Proceedings of Balisage: The Markup Conference 2021. Balisage Series on Markup Technologies, vol. 26 (2021). https://doi.org/10.4242/BalisageVol26.Quin01.
Balisage: The Markup Conference 2021 August 2 - 6, 2021
Balisage Paper: CSS Within: An application of the principle of locality of reference
to CSS and XSLT
Liam Quin runs an information design and XML consulting company, Delightful Computing, and previously was XML Activity Lead at the World Wide Web Consortium; before that
he was involved in the creation of XML itself and in SGML, most notably at SoftQuad
Inc. in Toronto. His backgrounds are in digital typography and computer science.
An important principle of writing, and of programming in
particular, is that one should be able to understand any
particular passage without having to look elsewhere. Of course,
there may be concepts that one needs, but in literature having
to consult a dictionary several times in every sentence is
tedious; in software engineering, having to read function
definitions before understanding the code that calls them can be
dangerous.
This paper describes experiments with CSS Within (a method of
embedding CSS style rules into XSLT transformations) and
discusses how the proximity of the rules to the corresponding
element generation affects maintenance.
In computer hardware architecture, the principle of Locality of
Reference (attributed to Peter Denning) is that the processor tends
to access the same memory locations, and others nearby, repeatedly
over any given period of time. In an article revisiting the
discovery of this principle, Peter Denning wrote [Denning
2006],
The locality principle flows from human cognitive and
coordinative behavior. The mind focuses on a small part of the
sensory field and can work most quickly on the objects of its
attention. People gather the most useful objects close around
them to minimize the time and work of using them. These
behaviors are transferred into the computational systems we
design.
The locality principle will be useful wherever there is an
advantage in reducing the apparent distance from a process to
the objects it accesses
This paper explores an application of the principle of Locality of
Reference to computer programs and scripts, and in particular to
XSLT templates and functions. It discusses some ways this principle
has been applied with various degrees of success in software
engineering; the paper then describes one particular application,
that of generating both HTML and corresponding CSS in parallel using
XSLT. After describing experience with this parallel generation the
author will be in a position to describe why they consider it to be
a success.
Locality of Reference in Software
An early problem in software, and one that continues to be a
problem today, is the task of ensuring that documentation for a
library is up to date with respect to the code. If you are using a
library of programming functions (for example, the EXPath File
module in XPath and XSLT), you rely on the documentation to tell you
what arguments you must supply to each function, to list the error
conditions, and to explain what the function returns. If the
documentation says, file:open takes a
filename as its argument and returns a sequence of lines as
individual strings but in fact it takes a URI
Reference (informally, a URL) and returns a single, possibly empty,
string, your program may seem to be working correctly until you have
a Microsoft Windows filename with \ in it, or until you supply an
input file containing more than one line of text. The problem, then,
is this: How can such discrepancies between code and documentation
arise? And how can they be avoided?
In the early days of computing, program libraries were documented
in printed books; the first of these was produced in 1951 in
Cambridge Wilkes, Wheeler, Gill, 1951. This first book,
like many after it, was typewritten, not prepared by computer. Later
on, the Unix programmer’s manual was, unusually for the time,
prepared on the same system it described: a PDP-11 computer running
Unix. By the time the Seventh Edition of the manual was produced, it
was a mixture of technical reports andman
pages, with each library function having its own manual
page, produced from a separate file using the
troff typesetting software.
Producing the documentation for a library separately from the code
implementing the library meant there was a duplication of
information: the function signatures, listing the function names,
parameters, and return types, were kept both in the software itself
and in the external documentation. This created the possibility that
the documentation and code could differ.
Literate Programming
In the 1970s and early 1980s the mathematician and computer
scientist Donald Knuth saw this problem and designed a system
in which the program and its documentation, both internal and
external, could be interwoven. In effect
the programmer was expected to write a text-book or extended
essay about a problem being addressed by software, and to
incorporate the text of the program into that work.
It may be useful to bear in mind that a great many people
(although not all) have gone into computer science having barely
ever written an essay, and certainly not enjoying the process.
The author of this paper had to write exactly one essay as a
computer science undergraduate, and it was for an elective
course outside the computer science department. Turning the
problem of writing a code library and some documentation into
the task of writing a book is not universally seen as a
simplification, nor as an inviting change, by such programmers.
Perhaps this is part of why Dr. Knuth’s literate programming has
not caught on en masse.
In the case that the requirements for a program seem stable,
however, and the program will change only slowly over a long
time (decades, perhaps), Knuth’s literate programming is an
unparalleled tour de
force.
A more serious problem with literate programming is that the
methodology assumes a software life-cycle in which programs are
designed and then remain largely static: they do not undergo
significant reorganization. After all, if writing an essay is
unappealing, rewriting the essay must be
even less appealing. Since the program is interleaved with the
documentation, refactoring means reworking the documentation
even before the software design has become stable again. But any
barrier to refactoring, however small, may lead to programs
being rewritten from scratch, with new sets of bugs, rather than
being reorganized.
Embedded Documentation
While Knuth was building complex cathedrals, others were
kneeling in animal-hides and worshipping at hedge-altars. The
author of this paper devised a system in the 1980s for personal
use in the C programming language in which each function was
preceded by a fragment of SGML describing it, itself contained
in a comment so that the library would compile:
The approach of embedding the documentation in the program
seems a much better fit with the relationship between a
programmer and extended written prose than the reverse,
embedding the program in the documentation. More importantly,
where literate programming seemingly throws up barriers to
refactoring and reorganizing code, embedded documentation does
not. It is no surprise that similar systems are now widespread,
from systems like doxygen for C or C++ to
javadoc for Java.
Note that the early documentation method shown here mentions
other functions by name, but there was no automated check that
they had not been renamed.
Consider a programmer who, at some late hour, discovers the
source of a bug. They make a correction to the code; they
recompile, they run tests; they smile; they go to sleep. But in
examining the code they did not need to look outside the
function body they were repairing. As a result, it’s easy for
necessary changes to the documentation to be overlooked. This is
sure to be a factor why in JavaDoc, doxygen and other
documentation systems (as well as the SGML-based system shown
above) the documentation does often stray from the code.
However, this style of documentation considerably reduces the
problems of entirely separate program documentation, such as
Unix manual page, that might go for decades and many major
software revisions of the program described, without being
updated.
Docstrings
The maintainers of the Python language were able to build on
the work of others; both on systems such as
doxygen or javadoc
and on a much simpler system in some versions of the
emacs editor. In this latter system, if
the first item in a function body was a literal string it was
taken to be a short (one-line) description of the purpose of the
function.
Python uses a similar method with its
docstrings: a single string placed
after the start of the function serves as minimal
documentation:
def schema_validate(xml, xsd):
"""Perform W3C XML Schema validation"""
print("Validation failed: duplicate element found.")
Notice how the documentation, although much less complete in
this example, appears after the start of
the function. Since anyone working on a function is very likely
to need to look at the function signature and parameter names,
they are going to be reminded to update the documentation. It is
this reminder that gives a clear example of the principle of
locality of reference: because the documentation is in view of
the programmer changing the code, it is easy to keep up to date.
Such a simple change turns out to make a large difference in
practice Unsub, 2021.
It should be noted that Python docstrings can be many lines
long and for a class are expected to document all public
methods.
Sad and Dismal Failures
Project failures have been attributed to programmers assuming they
understood what a function did when it had perhaps a misleading
name. This should, perhaps, be no surprise, if people become
programmers because they dislike menial repetitive tasks and want
the computers to do them instead.
If the principle of locality of reference says that we tend to
look nearby for things we need, it follows that we should write code
that can be understood as much as possible without having to look
elsewhere. A well-known source of software defect comes from calling
a function incorrectly, for example with an argument expressed in
feet instead of metres. Another example includes languages such as
Pascal and C++ in which function parameters can be passed implicitly
by reference, so that f(x) can result in a change to
the value of a local variable x even where
x is not a pointer or reference.
Early programs had to use short identifiers because of memory
limitations. C programs, for example, could use variables of any
reasonable length but only the first six characters were significant
for global symbols shared between files. This is why Unix used
creat() and mknod() (the loader
prepends an underscore to globals, using all six characters). This
gave rise to a culture of using short variable names and function
names. The author of this paper was astonished to encounter, in the
1980s, a program with function names such as
addToTableOfContents(item, pageNumber) but then saw
the advantage: you could read code that called
addToTableOfContents without having to look at its
definition to guess what it did. The mixed case function name would
be treated as AddToT on systems that still had the
six-character limit, a prefix slightly more likely to be unique than
add_to.
This property of being able to read a fragment of a program and
understand it without needing to read the definitions of all the
functions that it calls is another example of the principle of
locality of reference. That is, where the previous examples have
featured parallel information such as documentation that must be
updated at the same time as code, this example features names that
we must understand, ideally without having to leave the
neighbourhood.
CSS Within
This section introduces a method of using CSS that is informed by
the principle of locality. One use of XSLT is to transform a
document represented in XML into two groups of files: one group, in
HTML, intended as inputs to a Web browser or to a formatter to make
PDF; the other group, consisting of images, CSS and JavaScript, to
be referenced by the HTML files in the first group.
A problem arises that is analogous to that of software
documentation: the CSS and JavaScript must be kept up to date with
any changes in the HTML structure, and changes to the HTML structure
may necessitate in turn changes to the CSS.
It might seem that this should be trivial to manage, but a CSS
file as short as only six or seven thousand lines is already larger
than the Version Six Unix kernel source. Worse, the cascading
nature of CSS means that multiple CSS rules might apply to any given
element, and might appear anywhere in the CSS stylesheet.
CSS Within is an attempt to apply the principle of locality of
reference to the problem of keeping CSS and HTML and XST all
synchronized.
CSS Four Ways
When the author of this paper was first faced with the problem
of generating a static HTML Web site with CSS styling, they
simply made an external CSS file. Unfortunately as the XSLT was
modified independently of the CSS, the CSS gradually grew longer
and is no longer feasible to maintain at all.
The next approach was to generate a CSS file from within a
single XSLT make-css template. This at least meant
that when editing a template, the corresponding CSS selector
could often be found quickly. It was an improvement but not a
solution, though ,as it was easy to forget to update one or
another. Removing an element constructor in CSS might or might
not remove the need for a particular group of CSS style rules –
and those rules might or might not be near one another in the
CSS, again violating our locality of reference principle.
The second approach was to use non-XSLT elements. It turns
out, as many readers will already know, that you can include
elements from non-XSL namespaces at the top level in XSLT
stylesheets. So it was possible to have, for example, a
css:styles element just before each template.
In practice there were some difficulties with doing this. The
first was remembering to look before the start of the template.
Another difficulty (shared with other approaches already
mentioned) was that curly braces in text nodes have become
special in XSLT 3: if the expand-text attribute is set to
yes on the stylesheet element, then you
need to turn it off again for each such CSS element so the curly
braces do not introduce embedded XPath expressions. A third
difficulty was that tie granularity did not
match the problem: CSS styles are applied to individual elements
in their context, but an XSLT template might generate many
different elements.
Applying the principle that we need to have everything
relevant to hand, then, CSS Within was born. Consider the
following fragment taken from inside a template in a production
XSLT stylesheet:
In the listing, the direct element constructor creating the
HTML div element is immediately followed by
a CSS fragment to match it. There could be multiple CSS rule
elements as needed. The generated CSS would look like
this:
div.index {
padding: 1rem;
margin: 0;
max-width: 20rem;
}
ul.breadcrumb {
list-style: none; /* turn off the bullets */
}
In the example, the HTML div element and the HTML
ul element each have their own separate styles,
directly associated with them. This has resolved or at least
greatly reduced the problem of granularity. Since the CSS is now
embedded within the direct element constructor, rather than
separated from it and outside the template, this has also
resolved the difficulty of the person maintaining the XSLT
having two places to update in parallel. Finally, moving the
selector into an attribute means that curly braces are not
needed, and now the CSS syntax can happily co-exist with XSLT
3.
This approach needs more support than simply putting the CSS
before the template. The css:rule elements
are considered by an XSLT processor to be “direct element
constructors”, so they and their contents appear in the output.
To deal with this, the author has used two different approaches.
The first, shown in the appendix to this paper, is to use the
XPath fn:transform() function to apply a
stylesheet and then remove extraneous CSS elements before
creating the final output.
It may seem that the CSS could be bundled up and written to
the CSS file, perhaps with an XSLT 3 accumulator, as the input
is processed, but in fact what is needed is
all of the CSS elements, including ones
not triggered by templates, for example for server-generated
dynamic content or for static HTML pages sharing the same CSS
stylesheet. Therefore, the XSLT separately processes the XSLT
stylesheet as XML, gathers the css:rule elements,
and writes the stylesheet.
The author has also written very simple a Java extension class
for Saxon so that the CSS elements do not generate any content;
this is available (both source and compiled) on the gitlab page
for CSS Within.
Putting the CSS inside XSLT element constructors in templates
has the effect of interleaving the XSLT
source and the CSS source. Evaluating the XSLT entails
separating out the two streams. The CSS is removed when the XSLT
stylesheet is compiled (either by XSLT pre-processing of the
stylesheet itself, or using a Java implementation to do this).
Since the CSS is no longer present when the XSLT is evaluated,
property values cannot refer directly to XSLT variables; a
mechanism to include dynamically-generated content in the CSS
sylesheet is described in the next section.
CSS Within in More Detail
This paper does not attempt a complete definition of CSS
Within, but illustrates enough of it for the purpose of
discussing the application of the principle of locality of
reference to software maintenance. The full documentation is
available on the gitlab page for CSS Within.
css:rule
This element has a match
attribute, and generates a single CSS rule. The
content should be CSS properties.
It’s also possible to reuse fragments of CSS with
a ref attribute to point to a
css:rule element with a
corresponding name attribute.
This helps to address the problem of not knowing
whether it is safe to remove a definition: if the
same CSS rule is used in multiple places, this can
be indicated with a css:rule element
pointing back to (for example) the first
instance.
A stream attribute allows for
generation of multiple CSS outputs; one might have
values of print, screen, and #all.
<!ELEMENT css:rule (#PCDATA)*>
<!ATTLIST css:rule
match CDATA #IMPLIED
stream CDATA #IMPLIED
name ID #IMPLIED
ref ID #IMPLIED
>
css:media
This element models CSS media queries (specific in
the W3C CSS Conditional Text module). It contains
any mix of css:rule and
css:media elements.
The effect of the media query is that if the
viewport (the screen or page) is less than six
hundred pixels wide, a elements inside
the navigation bar are rendered with minimum height
and width of 48 pixels; since a CSS pixel is defined
to be one ninety-sixth of an inch, 48 pixels is half
an inch, plenty large enough for a mobile phone or
tablet user to hit with a thumb.
There are also constructs for at-rules, a CSS header and
footer, and ways to get at the generated stylesheet.
In all cases the curly braces are generated automatically, and
the CSS rules can be placed near the code generating the
elements to which they will apply, or, as in the media query
example, in the parent element's XSLT template.
Writing Out CSS Styles
Regardless of how many times any particular XSLT
template was used in a transformation, the CSS stylesheet
contains each css:rule element exactly once.
The rules appear in the order in which they occur in the
stylesheet.
If you need to put rules in a different order, you can put
them between templates or in a template not otherwise used,
and give them names; then refer to them with name/ref pairs
from empty css:rule elements where they are
needed, to remind your later self, and others, where they
apply.
The stylesheet is constructed as a string; it is possible
to call fn:replace() on it from within XSLT
before writing it out. In addition, you can make a header
that defines CSS custom properties (CSS variables) and refer
to them in the stylesheet.
The implementation of CSS Within currently on gitlab uses
fn:transform() to run a modified version of
the stylesheet with the CSS rules removed, or removes any
errant CSS instructions from the output; it then uses a
namespaced XSLT mode to gather up the CSS rules and write
them out. Some cleverness, described in an appendix to this
paper, would be needed to do this in the case that there are
multiple stylesheet compilation units (possibly including
external precompiled packages) that might be selected at
runtime.
Alternate Designs
It's very tempting to want to make the CSS properties be
XML attributes instead of text content. There are some
problems with this, however.
The attributes must be processed without
evaluating the stylesheet. XSLT developers are
accustomed to thinking of attributes as first-class
objects, passing them around, generating them in
functions, using dynamic attribute sets, using
attribute value templates to interpolate runtime
values, and more. None of these techniques work when
the XSLT stylesheet is treated as a passive XML
document containing CSS fragments.
It often happens that a CSS property must be
repeated in the same rule with different values:
different user agents (browsers) will use whichever
value they consider valid and reject the others. You
cannot have two XML attributes with the same name,
so this rules out using the obvious
attribute-name/value approach.
Some CSS property values do contain curly braces,
but there's no equivalent to expand-text =
"no" for attribute values, so you are
back to difficulties with curly braces, compounded
by the fact that you can't use a runtime
variable.
Although the forgoing reasons are surmountable
with varying degrees of inconvenience, a far greater
problem is the distance between XSLT and CSS
cognitive modes for the human reader. It's much
easier to read a CSS example in CSS syntax and
compare it to online examples, or to copy and paste
to and from a Web browser element inspector. The way
CSS is written is part of the way people think about
CSS, so it's important to support keeping it that
way.
In particular, the CSS cascade works very
differently from XSLT template priorities. In XSLT,
an entire template is selected by the processor
based on priorities. In CSS individual rule/value
pairs are selected, and in some cases merged, based
on a mixture of ordering in the input file and how
specific the selectors on the CSS rule surrounding
them are. It’s easy to forget this and to imagine
that an entire rule (between open and close curly
braces) is to be selected; getting this wrong can
lead to white text on a white background, or other
styling errors.
None the less, the author is considering using an
attribute-based approach to font references, so some
experimentation is happening and CSS Within may evolve
towards supporting a richer markup for individual CSS
property-value pairs in the future, as well as for at-rules
such as @font-face or @page which
at the moment must be supplied separately, for example in a
header included when the CSS is written.
Future Work
CSS Within continues to evolve through experience and
contemplation. A current experiment makes the match
attribute optional on css:rule elements,:
instead, the immediately enclosing direct element
constructor is examined. This makes it easier to rename
elements or classes, and easier to copy style blocks. The
example from earlier in this paper, showing the use of a
media query, might become:
Only the second line of the example is changed; in
practice, however, this change would likely simplify almost
all css:rule elements. The question to be
determined is whether the change increases or reduces
maintainability.
More support for CSS at-rules is planned, for example for
fonts or keyframes; experiments using an attribute on a
css:rule element to point to an at-rule for
a @font-face have not been promising so far, as
the added complexity gave minimal benefit. However, hooking
into infrastructure to test that font files are in place may
give added motivation. In addition, automatically generating
the latest version of the “bullet-proof Web font” syntax
from something simpler would be a benefit. The following
listing gives an example of a CSS font
definition:
@font-face {
font-family: "IM Fell English PRO";
font-slant: normal;
font-weight: regular;
src: url('fonts/imfellenglishpro.eot');
src: url('fonts/imfellenglishpro.eot?#iefix') format('embedded-opentype'),
url('fonts/imfellenglishpro.woff2') format('woff2'),
url('fonts/imfellenglishpro.woff') format('woff'),
url('fonts/imfellenglishpro.ttf') format('truetype');
/* SCG fonts via CSS are deprecated now, see
* https://www.zachleat.com/web/retire-bulletproof-syntax/
* url('fonts/imfellenglishpro.svg#imfellenglishpro') format('svg');
*/
}
Notice especially the tricks such as
?#iefix used if Internet Explorer support
is desired, along with the need to repeat the first
src property-value pair. Complexities such
as this, along with the occasional need for actual syntax
errors to support incorrect implementations, makes a
markup-based representation especially complex. Simple
attribute-value pairs do not work because of the repetition.
However, simply surrounding the rule with element and using
name/ref for validation may be useful in
itself:
<cs:font-face name="imfelleiglishpro">
font-family: "IM Fell English PRO";
font-slant: normal;
font-weight: regular;
src: url('fonts/imfellenglishpro.eot');
src: url('fonts/imfellenglishpro.eot?#iefix') format('embedded-opentype'),
url('fonts/imfellenglishpro.woff2') format('woff2'),
url('fonts/imfellenglishpro.woff') format('woff'),
url('fonts/imfellenglishpro.ttf') format('truetype');
/* SCG fonts via CSS are deprecated now, see
* https://www.zachleat.com/web/retire-bulletproof-syntax/
* url('fonts/imfellenglishpro.svg#imfellenglishpro') format('svg');
*/
</css:font-face>
With this simple change,
the font-face CSS rule could be included only if needed,
and a warning generated on an attempt to use a font-face by
reference that was not defined.
For Web use it’s important to include font definitions as
early in a stylesheet as possible, so that the browser can
start the process of loading the font. CSS is generated by
the CSS Within XSLT stylesheet in the order it occurs in
the input XSLT you are using, so you can have an
otherwise-unmatched template at the start of your
stylesheet, or an xsl:variable definition,
containing rules to go at the start.
There is also ongoing work with extension elements. The
Java class for Saxon that makes css:rule and
css:media return an empty sequence at
runtime could also help to write out stylesheets, but the
author ran into a combination of time constraints and
unclear documentation, so this is not yet an active part of
the CSS Within distribution.
CSS Within can also be used with systems such as the SASS
preprocessor, although some of the SASS benefits, such as
nesting, are irrelevant since CSS Within uses the natural
nesting of direct element constructors.
CSS Within In Practice; An Unwarranted Conclusion
It took the author an hour or two to convert one standalone CSS
file of some 6,500 lines to CSS fragments within an XSLT stylesheet.
However, the time has paid for itself in unexpected ways. Not only
are the styles now always up to date, but the act of
finding the particular style rule has
become trivial, which has saved far more time than
anticipated.
It is difficult to contemplate going back to keeping CSS in a
separate file. The necessity of handling extension elements, or of
post-processing the XSLT result, is unfortunate. Preprocessing the
XSLT to remove CSS elements before evaluation sounds tempting, but
in XSLT 3 stylesheet filenames for inclusion could be supplied as
parameters and package selection can depend on system properties or
even environment variables, so this is not in general
possible.
Some months after implementing CSS Within, the author had occasion
to return to the original project. They found that they were easily
able to modify and refactor the stylesheet as needed, updating the
styles. Previously, returning to the project after some time has
always proved difficult.
Moving a dependent resource into the centre of the code, instead
of cluttering the code, provides an overall clarity and increase in
efficiency. Furthermore, there is a reduced
impediment to refactoring compared to an external stylesheet,
because the effects of making changes are more readily
apparent.
In fairness, one should contrast the possibility,
literate-programming style, of embedding XSLT inside CSS
stylesheets. However, not only would this discourage refactoring, as
already suggested, but it would bring back the difficulties of curly
braces, and would add the same impediment to updating: that it would
be easiest to modify a template without looking at the corresponding
CSS. With CSS Within it is easier to look at both CSS and XSLT than
to look at only one, because the CSS is within the XSLT at the point
where it is needed, and yet kept subsidiary. Making it easier to do
the right thing than the wrong thing leads to an overall improvement
in code as well as in quality of life.
The Principle of Locality of Reference is useful in leading us to
ways of writing code that is more readable, more reliable, and much
easier to maintain.
Appendix A. Implementing “CSS Within” With XSLT
There are three parts to the implementation:
Checking the CSS elements are used correctly, with for
example no css:media elements inside
css:rule elements;
Handling the unwanted constructed CSS nodes when the
stylesheet is executed;
Generating the CSS stylesheet.
In the current implementations, the first item, that of
validation, is handled by XSLT that also removes unwanted nodes.
The second item, that of removing the unwanted nodes, as achieved
as follows: either with a Java extension element that returns the
empty sequence on compilation, so that the nodes are not generated,
or using fn:transform()to call XSLT and then
post-processing the result with an identity transform that removes
all elements in the CSS Within namespace. It is also possible to
pre-process the stylesheet to remove the CSS direct element
constructors (and their contents) and then use fn:transform() on the
result. However, this does not take external packages into
account.
Generating the stylesheet is done currently by processing the
stylesheet with XSLT; the author also had extensions written in Java
to provide a css:get-stream() function so that
the stylesheets could be written from the XSLT stylesheet but this
did not work with separate compilation of packages, nor with
multiple stylesheet files. A newer approach was started: this would
augment a css:gather element in each file or
compilation unit with the generated text of the style sheet, so that
it can be placed in a template that uses xsl:next-match
to process all of the stylesheet files at runtime.
An XSLT variable can be define to hold a CSS header containing an
encoding declaration, initial comments, @font-face,
@page and other at-rules, and this can easily be
prepended to the CSS file when it is created from XSLT. Such a
header can also define custom properties (CSS variables) which can
then be referenced from property values in css:rule
elements. This considerably reduces any need to construct XSS
property values at runtime inside actual templates, which is just as
well since the CSS is gathered before the stylesheets are even
execute!.
Appendix B. A Slightly Longer Example
The following is a complete template from a production
stylesheet.
[Denning, 2005] Denning,
Peter J., The Locality Principle, in
Communications of the ACM, Vol 48, No. 7, July 2005. doi:https://doi.org/10.1145/1070838.1070856.
[Unsub, 2021] Unsubstantiated assertion provided without evidence.
[Wilkes, Wheeler, Gill, 1951] Wilkes, N., Wheeler, D., Gill, S.,
Report on the Preparation of Programmes
for the EDSAC and the Use of the Library of
Subroutines, University Mathematical Laboratory,
Cambridge, 1951.
Wilkes, N., Wheeler, D., Gill, S.,
Report on the Preparation of Programmes
for the EDSAC and the Use of the Library of
Subroutines, University Mathematical Laboratory,
Cambridge, 1951.