Skip to content

CSSHTML#

The boxes and glue csshtml package is made to combine CSS style instructions and HTML text and return a tree data structures which makes it easy to find the style information.

The main CSS struct looks like this:

type CSS struct {
    Pages      map[string]Page
    FileFinder func(string) (string, error)
    FontFaces  []FontFace
}

See the package documentation for details.

Attribute resolving#

cs := csshtml.NewCSSParser()
cs.AddCSSText(`
    p {
        font-weight: bold;
    }
`)

gqd, err := cs.ProcessHTMLChunk(`<p foo="bar" style="border: 1pt solid black;">hello world</p>`)
if err != nil {
    return err
}
gqd.Find("p").Each(func(i int, sel *goquery.Selection) {
    n := sel.Get(0) // a golang.org/x/net/html Node
    for _, attr := range n.Attr {
        fmt.Println(attr.Key, attr.Val)
    }
    resolved, newAttrs := csshtml.ResolveAttributes(n.Attr)
    fmt.Println("-----------")
    fmt.Println(resolved)
    fmt.Println("-----------")
    fmt.Println(newAttrs)
})

returns

foo bar
style border: 1pt solid black;
!font-weight bold
!border 1pt solid black
-----------
map[
    border-bottom-color:black
    border-bottom-style:solid
    border-bottom-width:1pt
    border-left-color:black
    border-left-style:solid
    border-left-width:1pt
    border-right-color:black
    border-right-style:solid
    border-right-width:1pt
    border-top-color:black
    border-top-style:solid
    border-top-width:1pt
    font-weight:bold
]
-----------
[{ foo bar}
 { style border: 1pt solid black;}
 { !font-weight bold}
 { *font-weight bold}
 { *border 1pt solid black}
 { *border-top-style solid}
 { *border-top-width 1pt}
 { *border-top-color black}
 { *border-right-style solid}
 { *border-right-width 1pt}
 { *border-right-color black}
 { *border-bottom-style solid}
 { *border-bottom-width 1pt}
 { *border-bottom-color black}
 { *border-left-style solid}
 { *border-left-width 1pt}
 { *border-left-color black}
]

Explanation: The original attributes in the HTML tree (foo and style) stay unchanged in the tree. Style instructions (from CSS text or from the style attribute) are added to the node prefixed with a exclamation mark, otherwise unchanged.

Calling csshtml.ResolveAttributes() on these attributes returns two values: a map (string -> string) of the resolved attributes and a slice of resolved attributes. Resolving means in this case turning an instruction such as margin: 1em 2em into margin-top: 1em, margin-right: 2em, margin-bottom: 1em and margin-left: 2em. The second argument contains a slice of attributes with prefixed names: original attributes have no prefix, unresolved style attributes have an ! prefix and resolved styles a *.

Using fonts#

cs := csshtml.NewCSSParser()
cs.AddCSSText(`
@font-face {
    font-family: "MetaPro";
    src: url("../fonts/ff-metapro-book.otf");
    font-weight: bold;
}

@font-face {
    font-family: "MetaPro";
    src: url("../fonts/ff-metapro-normal.otf");
}

`)
for _, ff := range cs.FontFaces {
    fmt.Println(ff.Family, ff.Source[0].URI, ff.Weight)
}
MetaPro ../fonts/ff-metapro-book.otf 700
MetaPro ../fonts/ff-metapro-normal.otf 400