Lists are a powerful way to making complex ideas easier to digest, better than caramel. Auditorily I defined them via a thunk earcon, with or without the insertion of tiered numbering. Visually they’re denoted by preceding each list item by a symbol (•) or number.
These numbers are commonly rendered using one of a variety of counting styles, including:
And that’s without getting into non-latinate languages!
@counter-style
To let webdevs configure how counters are rendered, the W3C are standardising the @counter-style
at-rule. I’ve implemented this in Haskell Stylist to make implementing all the standard (and more) counter-styles trivial!
These counter-styles defines:
But most importantly it includes a “counting system” & the Unicode characters/symbols with which it should be used.
These counting systems may be one of:
cyclic
which repeats a given sequence of symbols as the markers.fixed
which iterates over a given sequence before falling back, where the number associated to the first symbol is configurable.symbolic
which doubles (then triples, etc) up the symbols once we’ve iterated through them.alphabetic
which works similarly to numeric
, but tweaked to work better with alphabetical symbols.numeric
which repeatedly divides by some base & outputs corresponding symbols for the remainders.additive
which iterates over symbol/value pairs to greedily output a sequence with the desired sum. Think Roman Numerals where X = 10, V = 5, & I = 1.These collectively can be configured to describe almost all the numbering systems used around the globe.
The Western numbering system (which is derived from India’s via Arabia) isn’t the only numbering system. Most can be handled by the numeric
system, or the flexibility of the additive
system. There’s plenty of alphabets to use with the alphabetic
system, & the other systems have their uses.
The W3C provides a sample stylesheet which I copied & pasted into my codebase. They say they don’t expect “useragents” (their term for webbrowsers) to implement all of these, but I did anyways since it was trivial & to show a commitment to internationalization.
Except there’s a few numbering systems known to the W3C which needed to be implemented specially!
Chinese has 4 numbering systems which, with some nuances, favours denoting the 1s, 10s, 100s, & 1000s places as opposed addings zeroes (零
). These systems differ in which logograms are used & whether shorthands are used for the teens. This was implemented with a little postprocessing after converting the number to decimal digits. Several Chinese numbering systems can be implemented as variants on this generic algorithm.
Ethiopian numerals (historically used across northern Africa) meanwhile, with it’s own nuances, pairs up every 2 digits. Between each pair it intersperses alternating ፻
& ፼
seperators. Within each pair, the tens place uses different characters from the one’s place. For zero & negative numbers, as per W3C’s recommendation, I fallback to the Western numbering system.
I minorly extended the @counter-style
spec with a couple extra system
s for internal use to invoke these algorithms with (partially, in the case of Ethiopian) configurable Unicode symbols. Webdevs are discouraged from taking advantage of this & should instead use the browser-independant:
simp-chinese-informal
,simp-chinese-formal
,trad-chinese-informal
,trad-chinese-formal
,ethiopic-numeric
counter-styles.
I took testcases out of that W3C spec to ensure I got all this correct.
I refactored how I’m exposing pseudoelements, now I’m exposing them to PropertyParser
implementations as opposed to the library’s caller. This necessitated an addition to the “Stylist Traits” hackage, which I introduced to minimize the transitive dependencies in other components of the Argonaut Stack including Stylist compatibility. This will likely be useful again the future!
This change allowed the Data.CSS.Preprocessor.Text
styletree-preprocessor to handle inserting the ::before
, ::after
, & for list items (declared via display: list-item
) ::marker
pseudoelements. The ::marker
pseudoelement holds the list item’s bullet or counter, who’s contents (if absent) is generated from list-style-image
(relies on as-yet unimplemented image content) or list-style-type
.
For list-style-position: outside
I lower the list item to (as-yet unimplemented) flexbox & generate a new styletree element around it’s other children (including ::before
& ::after
) so the marker can lie outside. Whether the marker is at the start or end depends on the marker-side
& direction
CSS properties.
These list items automatically increment a list-item
counter, determining which number is rendered via the specified counter-style.
P.S. I proofread this preprocessor, leading to the discovery of several bugs to squash. Nothing I find worth explaining in detail.
Several CSS shorthands, like list-style
, allows you to specify subproperty values in any order. A utility in Stylist Traits was added to aid implementing these.
It splits out function arguments, before associating each token with the first matching subproperty. Then iterates to the next token/function to match against remaining subproperties. Any leftover subproperties are set to initial
.