| Title: | Simple CSS Parser and Tools |
|---|---|
| Description: | Simple CSS parser and tools. |
| Authors: | mikefc |
| Maintainer: | mikefc <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.1 |
| Built: | 2026-05-25 06:25:41 UTC |
| Source: | https://github.com/coolbutuseless/cssparser |
Multiply alpha channel by given value
alpha_mul(x, alpha = 1)alpha_mul(x, alpha = 1)
x |
hex colour with alpha with total of 8 hex digits |
alpha |
alpha [0, 1] |
Set alpha channel
alpha_set(x, alpha = 1)alpha_set(x, alpha = 1)
x |
hex colour with alpha with total of 8 hex digits |
alpha |
alpha [0, 1] |
A version of cat which has an indentation depth
cat_indent(depth, ..., sep = "")cat_indent(depth, ..., sep = "")
depth |
the indentation depth |
... |
arguments passed to cat() |
sep |
argument passed to cat() |
xpath) of the final computed style for each elementCreate a named list (indexed by xpath) of the final computed style for each element
css_apply(xml, css = list(), svg = FALSE)css_apply(xml, css = list(), svg = FALSE)
xml |
xml document as returned by |
css |
list of rules parsed from CSS stylesheet. E.g as returned
by |
svg |
include SVG presentation tags in the cascade? default: FALSE |
named list of styles where the name is the xpath to a
node in the document, and the value is a named list of
property/values for this element.
Apply the CSS to the given HTML, storing the result as inline 'style' tags on each element
css_apply_inline(xml, css)css_apply_inline(xml, css)
xml |
html/xml document (as read by |
css |
CSS stylesheet to apply (as read by |
new xml document with final computed CSS written to inline style attribute on each element.
CSS colours can be lots of things:
css_colour_to_hex(x)css_colour_to_hex(x)
x |
CSS colour |
Hex colour with 3, 6 or 8 characters
CSS colour name e.g. 'red'. Not all CSS colours correspond to R colours e.g. 'silver' is not in R
rgb(), hsl(), hcl(), lab() and other colourspace-specific colour constructores. Only rgb and hsl are currently handled
color() for complex colourspace specifidation. Not handled yet
'transparent' and sometimes 'none' to indicate '#00000000'
'currentColor' or 'currentcolor' to indicate the colour for this element should be taken from whatever the current 'color' property is
for SVG, colours colours can be references to 'linearGradient' and 'radialGradient' specifications, or patterns
Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#currentcolor_keyword
hex colour (always with alpha channel)
Create a new CSS length object
css_length(x, unit)css_length(x, unit)
x |
numeric value |
unit |
character string for unit |
This is a naive conversion.
css_length_as_pixels(x, font_size = 12, ...)css_length_as_pixels(x, font_size = 12, ...)
x |
object of type |
font_size |
font size to calculate 'em' with. default: 12 |
... |
other arguments ignored |
For a proper conversion, it would have to take into account the font-size
on the root element (for rem units), and various things to do with
framepoint and viewing size of the element and its parents.
simple numeric value
Merge multiple stylesheets given in priority order
css_merge(...)css_merge(...)
... |
multiple CSS objects. The order in which these arguments are given reflect the priority of the stylesheets from lowest to highest priority. Later stylesheets (i.e. high priority) will override any styles declared earlier (lower priority) |
final cascaded stylesheet
## Not run: css1 <- read_css("chrome_builtin.css") css2 <- read_css("this_page.css") css_merge(css1, css2) ## End(Not run)## Not run: css1 <- read_css("chrome_builtin.css") css2 <- read_css("this_page.css") css_merge(css1, css2) ## End(Not run)
modifyList()
If an individual element in the base list has the 'important' attribute set to TRUE, then it does *not* get overwritten.
css_merge_core(base, new)css_merge_core(base, new)
base |
the original list |
new |
the new list from which to take values and put into base |
Some properties are accumulative, rather than replacement-based. E.g.
SVGs transform attribute combines parent + child transform
matrices. For now, any accumulative properties are concatenated into
a vector of character stirngs to be dealt with by the user after
parsing.
Otherwise, this function behaves very much like utils::modifyList()
updated version of base list
read_css())Pretty Printing of a CSS stylesheet (as produced by read_css())
css_pretty_print(x, depth = 0, rulesep = "\n", ...)css_pretty_print(x, depth = 0, rulesep = "\n", ...)
x |
object representing a CSS stylesheet |
depth |
the recursion depth of this block (used for indentation) |
rulesep |
separator between multiple rules |
... |
other arguments ignored |
https://www.w3schools.com/CSSref/css_units.asp
css_string_as_css_length(x)css_string_as_css_length(x)
x |
a value from CSS. |
css_length object
"1em") into the number of pixels
this represents.This function is a small wrapper around css_string_as_length() and
css_length_as_pixels().
css_string_as_pixels(x, percentage_as_fraction = TRUE, ...)css_string_as_pixels(x, percentage_as_fraction = TRUE, ...)
x |
Character string of a CSS value e.g. "12", "12px", "3em", "47%" |
percentage_as_fraction |
Default: TRUE means that if a value is given as
"50
|
... |
other arguments passed to |
This function does some naive conversions, and assumes the display is 96dpi.
For more control on the final result, the user is encouraged to use
css_string_as_length() and hand-roll their own unit conversion to
their display units. This can be tricky as some units rely on rendering
viewport sizes and font-size on the root node - thus i'll leave that for
the user to handle.
a numeric value for this length in pixels as best we can with limited knowledge
HTML4 user-agent css
html4_user_agent_csshtml4_user_agent_css
An object of class list of length 120.
This tream object (an environment) is used to encapsulate a vector of named tokens, an index of the current position, and some simple tools for advancing the stream, consuming tokens, etc
init_stream(tokens)init_stream(tokens)
tokens |
named |
Test if string is a single string with something in it
is_char1(x)is_char1(x)
x |
string |
TRUE if string is single string with something in it
Break a string into labelled tokens based upon a set of patterns
lex(text, regexes, verbose = FALSE)lex(text, regexes, verbose = FALSE)
text |
a single character string |
regexes |
a named vector of regex strings. Each string represents
a regex to match a token, and the name of the string is the
label for the token. Each regex can contain an explicit
captured group using the standard |
verbose |
print more information about the matching process. default: FALSE |
a named character vector with the names representing the token type with the value being the element extracted by the corresponding regular expression.
## Not run: lex("hello there 123.45", regexes=c(number=re$number, word="(\\w+)", whitespace="(\\s+)")) ## End(Not run)## Not run: lex("hello there 123.45", regexes=c(number=re$number, word="(\\w+)", whitespace="(\\s+)")) ## End(Not run)
This is really generic and lumps everything up to the next semi-colon into a single character string.
parse_at(stream)parse_at(stream)
stream |
stream |
If hex colour doesn't have an alpha channel, add it as 'FF'
If hex colour only has 3 digits, expand it to 6, then add alpha channel
parse_colour_hex(hex_colour)parse_colour_hex(hex_colour)
hex_colour |
e.g. '#000' |
8 char hex colour
## Not run: parse_colour_hex('#123') # -> '#112233FF' ## End(Not run)## Not run: parse_colour_hex('#123') # -> '#112233FF' ## End(Not run)
MDN https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl()
parse_colour_hsl_to_hex(colour_func_text)parse_colour_hsl_to_hex(colour_func_text)
colour_func_text |
string representing an |
hex colour
## Not run: parse_colour_hsl_to_hex('hsl(50, 0.5, 0.5)') ## End(Not run)## Not run: parse_colour_hsl_to_hex('hsl(50, 0.5, 0.5)') ## End(Not run)
MDN https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb()
parse_colour_rgb_to_hex(rgb_text)parse_colour_rgb_to_hex(rgb_text)
rgb_text |
string representing an |
hex colour
## Not run: parse_colour_rgb_to_hex('rgb(255, 0, 0)') ## End(Not run)## Not run: parse_colour_rgb_to_hex('rgb(255, 0, 0)') ## End(Not run)
e.g. "fill: black; color: blue" -> list(fill = 'black', color = 'blue')
parse_declaration(stream)parse_declaration(stream)
stream |
environment containing tokens and the current index. This is an internal only datastructure to assist in parsing |
a named list i.e. the name/value property pair
Nested 'ats' are things like @media where there is a nested
stylesheet as part of this declaration.
parse_nested_at(stream)parse_nested_at(stream)
stream |
stream |
name list of list(rule_name = list(property = value, ...))
A rule here is a selector and a list of property/value pairs
parse_rule(stream)parse_rule(stream)
stream |
stream |
name list of list(rule_name = list(property = value, ...))
A 'rule' is a 'selector' + a list of property/value pairs.
parse_rules_from_stream(stream)parse_rules_from_stream(stream)
stream |
token stream |
name list of list(rule_name = list(property = value, ...))
The selector is everything from the start of the rule to the first open-brace
parse_selectors(stream)parse_selectors(stream)
stream |
environment containing tokens and the current index. This is an internal only datastructure to assist in parsing |
e.g. .circle fill = 'black' -> '.circle'
single character string
s3 method fr printing a stream
## S3 method for class 'stream' print(x, ...)## S3 method for class 'stream' print(x, ...)
x |
stream object |
... |
other arguments passed to print() |
Convert CSS stylesheet from text or a file into a list object
read_css(stylesheet)read_css(stylesheet)
stylesheet |
CSS stylsheet. Either as a character string containing the CSS, or a path to a file containing CSS text |
named list of lists, where the top-level name is the CSS selector, and the value is a list of property/value pairs for this selector (i.s. a CSS declaration block)
Parse CSS declaration block (aka inline style) to a named list of CSS declarations
read_inline_style(inline_style)read_inline_style(inline_style)
inline_style |
set of ";"-delmited declarations i.e. an inline style, or a CSS declaration block: e.g. "stroke:red; fill: black; stroke-width:12" |
named list of declarations (i.e. property/value pairs)
e.g. list(stroke = 'red', fill = 'black', 'stroke-width' = 12)
Depth-first recursion into the HTML document node tree to accumulate/cascade styles
recurse_node_tree(node, xpath_styles, parent_style = list(), svg)recurse_node_tree(node, xpath_styles, parent_style = list(), svg)
node |
current XML node |
xpath_styles |
list containing the accumulated styles for each xpath |
parent_style |
the style from the direct parent |
svg |
include SVG presentation tags in the cascade? default: FALSE |
updated xpath style lookup list
Algorithm defined here: https://drafts.csswg.org/selectors-3/#specificity
selector_specificity(sel)selector_specificity(sel)
sel |
selector |
A selector's specificity is calculated as follows:
count the number of ID selectors in the selector (= a)
count the number of class selectors, attributes selectors, and pseudo-classes in the selector (= b)
count the number of type selectors and pseudo-elements in the selector (= c)
ignore the universal selector
Selectors inside the negation pseudo-class are counted like any other, but the negation itself does not count as a pseudo-class.
Concatenating the three numbers a-b-c (in a number system with a large base) gives the specificity.
Since we only really have base-10 numbers (rather than numbers in arbitrarily large bases), just use 2 digits for each of the counts. Hopefully it is really unlikely that any of the counts exceeds 99!
numeric value
This is not perfect/finished but it is a step in the right direction.
split_font_shorthand(font_text)split_font_shorthand(font_text)
font_text |
the text of the "font" declaration e.g. "italic 1.2em "Fira Sans", serif;" |
For example: this function does not split the "font-variant" shorthand
list of font-related property/value declarations e.g.
list('font-family'='serif', font-size='1.2em', ...)
Flatten a style to an inline string
style_flatten_to_inline(style)style_flatten_to_inline(style)
style |
a named list of property/value pairs |
single string suitable for a style attribute on an element
## Not run: style_flatten_to_line(list(color='black', border='1px')) # -> "color:black; border: 1px;" ## End(Not run)## Not run: style_flatten_to_line(list(color='black', border='1px')) # -> "color:black; border: 1px;" ## End(Not run)
Merge multiple styles for a given element which are given in priority order
style_merge(...)style_merge(...)
... |
multiple style objects (i.e. declaration blocks). The order in which these arguments are given reflect the priority of the styles from lowest to highest priority. Later styles (i.e. high priority) will override any styles declared earlier (lower priority) |
final cascaded result
## Not run: style1 <- list(color = 'blue', `font-weight` = 'bold') style2 <- list(color = 'red', `font-size`="12px") style_merge(style1, style2) ## End(Not run)## Not run: style1 <- list(color = 'blue', `font-weight` = 'bold') style2 <- list(color = 'red', `font-size`="12px") style_merge(style1, style2) ## End(Not run)
Pretty Printing of a single style or declaration block
style_pretty_print(x, depth = 0)style_pretty_print(x, depth = 0)
x |
object representing a list of property/value declarations |
depth |
the recursion depth of this block (used for indentation) |
Trim the end off a string
trim(x, len)trim(x, len)
x |
string |
len |
number of characters to trim |
Since XML documents and nodes are almost always handled 'by-reference' if you want to keep an original untouched when adding nodes etc, you need to make an unlinked copy of it.
xml_duplicate(x)xml_duplicate(x)
x |
xml document |
new, unlinked xml document