CSS support
htmlbag uses csshtml to match stylesheet rules against the DOM. CSS
applies through three sources, in order of increasing specificity:
<style>blocks in<head>.<link rel="stylesheet" href="…">external files.- Inline
style="…"attributes.
Recognised properties
Box model
width, height, margin, margin-{top,right,bottom,left},
padding, padding-{top,right,bottom,left}, border,
border-{top,right,bottom,left}, border-width, border-style,
border-color, border-radius, box-sizing.
Typography
font-family, font-size, font-weight, font-style,
text-align, text-indent, text-decoration, line-height,
color, letter-spacing, word-spacing,
text-transform, white-space.
Backgrounds
background-color, background-image, background.
Page-level layout
@page rules support size (named like A4 or explicit
<width> <height>) and margin / margin-{top,right,bottom,left}.
Insert positioning
float: top | before | bottom | after — see inserts.
The standard CSS float: left | right (side floats with text wrap) is
not supported.
Display
display: none hides an element entirely.
display: block and display: inline override the element’s default
formatting context. A <span class="title"> with display: block
becomes a block-level container that starts on its own line; a
<div class="badge"> with display: inline flows inline with its
surrounding text. The override is read from the resolved style, so
selector-driven and class-driven rules work the same as inline styles.
Lists and markers
list-style-type (disc, decimal, lower-roman, upper-alpha, …)
controls the visible marker on <ol> / <ul> items.
list-style-position: outside (default) places the marker in the
padding band to the left of the item’s content, so multi-line items
keep their text aligned at a single left edge. list-style-position: inside reflows the marker as part of the item’s first line.
The marker itself can be styled via the ::marker pseudo-element:
li::marker {
color: darkslateblue;
font-weight: bold;
font-family: monospace;
}
li.note::marker {
content: "→ ";
}The content property on ::marker replaces the default
list-style-type glyph for that item. See the marker-pseudo
example.
Generated content and counters
::before and ::after pseudo-elements render generated content via
the content property. Strings, attribute values (attr(name)),
counter functions and the leader(…) token are supported:
h2::before {
content: counter(section) ". ";
}
figcaption::before {
content: "Figure " counter(figure) ": ";
}CSS Counters work as in CSS Lists 3:
| Property | Effect |
|---|---|
counter-reset: name [value] |
(Re)set a named counter on entering this element. |
counter-increment: name [step] |
Bump the counter by step (default 1) when this element matches. |
counter(name) |
The current value of the counter as a string. |
counters(name, sep) |
Joined values up the ancestor stack (for nested numbering like 1.2.3). |
Counters are scoped by the element tree: a counter-reset on a section
boundary clears nested counters, exactly as the spec prescribes.
body { counter-reset: section; }
h2 { counter-reset: subsection; counter-increment: section; }
h3 { counter-increment: subsection; }
h2::before { content: counter(section) " "; }
h3::before { content: counter(section) "." counter(subsection) " "; }See the numbered-sections-counters example for a full document with hierarchical numbering.
boxesandglue extensions
Vendor-prefixed (-bag-…) properties expose Knuth-Plass line-breaker
knobs that have no direct CSS-spec equivalent. They take part in the
normal CSS cascade — set them on body for a document-wide default,
on a class for per-element tuning, override with !important.
| Property | Type | Default | Effect |
|---|---|---|---|
-bag-linebreak-tolerance |
float | 4 |
Knuth-Plass badness ceiling (TeX \tolerance). Higher values let the line breaker accept looser lines. TeX uses 200 for \fussy and 10000 for \sloppy. |
-bag-linebreak-hyphen-penalty |
int | 50 |
Demerits added at a hyphenation breakpoint (TeX \hyphenpenalty). Lower values encourage hyphenation; useful for German compound words where the default prefers a slightly overfull line to a hyphenated loose one. |
/* Document-wide: relaxed line breaker, hyphenate eagerly. */
body {
-bag-linebreak-tolerance: 200;
-bag-linebreak-hyphen-penalty: 5;
}
/* Narrow column: even more permissive. */
.sidenote {
-bag-linebreak-tolerance: 1000;
}Hyphenation patterns themselves are selected by the standard
lang="…" HTML attribute (resolved through CSS Text 3 §6 hyphens),
or — for whole documents — by the front-matter lang: key in the
Markdown frontend. Tags without TeX patterns (Arabic, Hebrew, CJK,
unknown) resolve to a no-op hyphenator and never produce break
points; the tunables above only matter when patterns are present.
Selector support
The full CSS3 selector grammar works: type, class, id, attribute,
descendant, child and sibling combinators, plus structural
pseudo-classes like :first-child, :last-child, :nth-child(n),
:nth-of-type(n), :not(...). A common use case is alternating-row
styling on tables — see the zebra-table
example.
Box model details
padding-left and margin-left on a block container shift child
boxes to the right and reduce their content width accordingly, exactly
as CSS prescribes. So ul { padding-left: 20pt } indents list items,
blockquote { margin-left: 20pt } indents the quote body, and
nested containers stack their shifts.
What’s resolved when
CSS is fully resolved before htmlbag walks the DOM — by the time
CSSBuilder.OutputPages runs, every element carries its computed
properties in HTMLItem.Styles (a map[string]string). This means
selector matches and class-driven rules are picked up; you do not
need to inline styles to make them visible to htmlbag’s detection.