Help language development. Donate to The Perl Foundation

CSS::Properties zef:dwarring last updated on 2022-09-29

fec375cf7556011131c0df98b99761cf3f15aa0a/

[Raku CSS Project] / [CSS-Properties Module]

The CSS::Properties module is a set of related classes for parsing, manipulation and generation of CSS property sets, including inheritance, and defaults.

Synopsis

use CSS::Units :pt;
use CSS::Properties;

my CSS::Properties() $css = "color:red !important; padding: 1pt";
say $css.important("color"); # True
$css.border-color = 'red';

$css.margin = [5pt, 2pt, 5pt, 2pt];
$css.margin = 5pt;  # set margin on all 4 sides

# set text alignment
$css.text-align = 'right';

say ~$css; # border-color:red; color:red!important; margin:5pt; padding:1pt; text-align:right;

Classes in this module

See Also

Conformance Levels

Processing defaults to CSS level 3 (class CSS::Module::CSS3). This can be configured via the :module option:

use CSS::Properties;
use CSS::Module;
use CSS::Module::CSS1;
use CSS::Module::CSS21;
use CSS::Module::CSS3;
use CSS::Module::SVG;

my $style = 'color:red; azimuth:left;';

my CSS::Module $module = CSS::Module::CSS1.module;
my CSS::Properties $css1 .= new: :$style, :$module;
## warnings: dropping unknown property: azimuth

$module = CSS::Module::CSS21.module;
my CSS::Properties $css21 .= new: :$style, :$module;
## (no warnings)

my CSS::Properties $css3 .= new: :$style; # CSS3 is the default
# -- or --
$module = CSS::Module::CSS3.module;
$css3 .= new: :$style, :$module;

$module = CSS::Module::SVG.module;
$style ~= "paint-order:markers;";  # add a SVG specific property
my CSS::Properties $css-svg .= new: :$style, :$module;

CSS::Module::SVG is an extension to CSS::Module::CSS3 that includes additional SVG specific properties.

'@font-face' Properties

The CSS::Font::Descriptor module is a class for managing @font-face declarations. The css method can be used to get the raw properties.

@font-face {
    font-family: myFirstFont;
    src: url(sansation_light.woff);
}
use CSS::Properties;
use CSS::Font::Descriptor;

my $style = "font-family: myFirstFont; src: url(sansation_light.woff)";
my CSS::Font::Descriptor $fd .= new: :$style;
my CSS::Properties $font-face-css = $fd.css;

Default values

Most properties have a default value. If a property is reset to its default value it will be omitted from stringification:

my $css = (require CSS::Properties).new;
say $css.background-image; # none
$css.background-image = 'url(camellia.png)';
say ~$css; # "background-image: url(camellia.png);"
$css.background-image = $css.info("background-image").default;
say $css.background-image; # none
say ~$css; # ""

Deleting properties

Properties can be deleted via the delete method, or by assigning the property to Nil:

my CSS::Properties $css .= new: :style("background-position:top left; border-top-color:red; border-bottom-color: green; color: blue");
# delete background position
$css.background-position = Nil;
# delete all border colors
$css.delete: "border-color";

Inheritance

A child class can inherit from one or more parent classes. This follows CSS standards:

To inherit a css object or style string:

use CSS::Properties;

my $parent-style = "margin-top:5pt; margin-left: 15pt; color:rgb(0,0,255) !important";
my $style = "margin-top:25pt; margin-right: initial; margin-left: inherit; color:purple";
my CSS::Properties $css .= new: :$style, :inherit($parent-style);

say $css.color;                     # #7F007Frgb (purple)
say $css.handling("margin-left");   # inherit
say $css.margin-left;               # 15pt

Optimization and Serialization

method write(
    Bool :$optimize = True,        # consolidate properties
    Bool :$terse = True,           # single line output
    Bool :$color-names = True,     # use color names, where possible
    Bool :$keep-defaults = False,  # don't omit default values
    |c
) is also<Str gist> {

The .write (alias .Str, or .gist) method can be used to produce CSS. Properties are optimized and normalized:

use CSS::Properties;
my CSS::Properties $css .= new( :style("background-repeat:repeat; border-style: groove; border-width: 2pt 2pt; color: rgb(255,0,0);") );
# - 'border-width' and 'border-style' are consolidated to the 'border' container property
# - rgb(255,0,0) is mapped to 'red'
say $css.write;  # "border:2pt groove; color: red;"

Notice that:

$.write Options include:

See also CSS::Properties::Optimizer.

Property Meta-data

The info method gives property specific meta-data, on all (component or container properties). It returns an object of type CSS::Properties::PropertyInfo:

use CSS::Properties;
use CSS::Properties::PropertyInfo;
my CSS::Properties $css .= new;
my CSS::Properties::PropertyInfo $margin-info = $css.info("margin");
say $margin-info.synopsis; # <margin-width>{1,4}
say $margin-info.edges;    # [margin-top margin-right margin-bottom margin-left]
say $margin-info.inherit;  # True (property is inherited)

Data Introspection

The properties method, gives a list of current properties. Only component properties are returned. E.g. font-family may be returned; but font never is.

use CSS::Properties;

my $style = "margin-top: 10%; margin-right: 5mm; margin-bottom: auto";
my CSS::Properties $css .= new: :$style;

for $css.properties -> $prop {
    my $val = $css."$prop"();
    say "$prop: $val {$val.type}";
}

Gives:

margin-top: 10 percent
margin-bottom: auto keyw
margin-right: 5 mm

Lengths and Units

CSS::Units is a convenience module that provides some simple post-fix length unit definitions.

The :ops export overloads + and - to perform unit calculations. +css and -css are also available as more explicit infix operators:

All infix operators convert to the left-hand operand's units.

use CSS::Units :ops, :pt, :px, :in, :mm;
my CSS::Properties $css .= new: :margin[5pt, 10px, .1in, 2mm];

# display margins in millimeters
say "%.2f mm".sprintf(.scale("mm")) for $css.margin.list;

The measure method can be used to perform contextual measurement of lengths, which are converted to the default units.

The current font-size is used for em, ex and percentage calculations.

There are also viewport-width and viewport-height attributes that need to be set to enable vw and vh units.

use CSS::Units :ops, :pt, :px, :in, :mm, :em, :vw, :vh, :percent;
use CSS::Properties;
my CSS::Properties $css .= new: :viewport-width(200);

say $css.units;         # pt
say $css.measure: 10px; # 7.5pt
say $css.measure: 1in;  # 72pt

say $css.font-size;     # 12pt
say $css.measure: 2em;  # 24pt
say $css.measure: 50%;  # 6pt
say $css.measure: .1vw; # 20pt

The measure method can also be used on specific properties. In the case of box measurements (borders, margins and padding) a reference-width also needs to be set for percentage calculations.

use CSS::Units :px, :percent;
use CSS::Properties;
my CSS::Properties $css .= new: :margin[10%, 10px], :reference-width(120);

say $css.measure: :margin-top;       # 12pt
say $css.measure: :margin-left;      # 7.5pt
say $css.measure: :margin-left(20%); # 24pt
say $css.measure: :font-size;        # 12pt
say $css.measure: :font-size(50%);   # 6pt

The units attribute defaults to pt can be changed to any absolute length units:

use CSS::Units :px, :mm;
use CSS::Properties;
my CSS::Properties $css .= new: :margin[10mm, 10px], :units<mm>;
say $css.units;                      # mm
say $css.measure: :margin-top;       # 10mm
say $css.measure: :margin-left;      # 2.646mm

Appendix : CSS3 Properties

Name Default Inherit Type Synopsis
azimuth center Yes \ \ [[ left-side \ far-left \ left \ center-left \ center \ center-right \ right \ far-right \ right-side ] \ \ behind ] \ leftwards \ rightwards
background hash ['background-color' \ \ 'background-image' \ \ 'background-repeat' \ \ 'background-attachment' \ \ 'background-position']
background-attachment scroll scroll \ fixed
background-color transparent \ \ transparent
background-image none \ \ none
background-position 0% 0% [ [ \ \ \ \ left \ center \ right ] [ \ \ \ \ top \ center \ bottom ]? ] \ [ [ left \ center \ right ] \ \ [ top \ center \ bottom ] ]
background-repeat repeat repeat \ repeat-x \ repeat-y \ no-repeat
border hash,box [ 'border-width' \ \ 'border-style' \ \ 'border-color' ]
border-bottom hash [ 'border-bottom-width' \ \ 'border-bottom-style' \ \ 'border-bottom-color' ]
border-bottom-color the value of the 'color' property \ \ transparent
border-bottom-style none \
border-bottom-width medium \
border-collapse separate Yes collapse \ separate
border-color box [ \ \ transparent ]{1,4}
border-left hash [ 'border-left-width' \ \ 'border-left-style' \ \ 'border-left-color' ]
border-left-color the value of the 'color' property \ \ transparent
border-left-style none \
border-left-width medium \
border-right hash [ 'border-right-width' \ \ 'border-right-style' \ \ 'border-right-color' ]
border-right-color the value of the 'color' property \ \ transparent
border-right-style none \
border-right-width medium \
border-spacing 0 Yes \ \?
border-style box \{1,4}
border-top hash [ 'border-top-width' \ \ 'border-top-style' \ \ 'border-top-color' ]
border-top-color the value of the 'color' property \ \ transparent
border-top-style none \
border-top-width medium \
border-width box \{1,4}
bottom auto \ \ \ \ auto
caption-side top Yes top \ bottom
clear none none \ left \ right \ both
clip auto \ \ auto
color depends on user agent Yes \
content normal normal \ none \ [ \ \ \ \ \ \ \ \ attr(\) \ open-quote \ close-quote \ no-open-quote \ no-close-quote ]+
counter-increment none none \ [ \ \? ]+
counter-reset none none \ [ \ \? ]+
cue hash [ 'cue-before' \ \ 'cue-after' ]
cue-after none \ \ none
cue-before none \ \ none
cursor auto Yes [ [\ ,]* [ auto \ crosshair \ default \ pointer \ move \ e-resize \ ne-resize \ nw-resize \ n-resize \ se-resize \ sw-resize \ s-resize \ w-resize \ text \ wait \ help \ progress ] ]
direction ltr Yes ltr \ rtl
display inline inline \ block \ list-item \ inline-block \ table \ inline-table \ table-row-group \ table-header-group \ table-footer-group \ table-row \ table-column-group \ table-column \ table-cell \ table-caption \ none
elevation level Yes \ \ below \ level \ above \ higher \ lower
empty-cells show Yes show \ hide
float none left \ right \ none
font Yes hash [ [ \<‘font-style’> \ \ \ \ \ \<‘font-weight’> \ \ \<‘font-stretch’> ]? \<‘font-size’> [ / \<‘line-height’> ]? \<‘font-family’> ] \ caption \ icon \ menu \ message-box \ small-caption \ status-bar
font-family depends on user agent Yes [ \ \ \ ]#
font-feature-settings normal Yes normal \ \#
font-kerning auto Yes auto \ normal \ none
font-language-override normal Yes normal \ \
font-size medium Yes \ \ \ \ \ \ \
font-size-adjust none Yes none \ auto \ \
font-stretch normal Yes normal \ ultra-condensed \ extra-condensed \ condensed \ semi-condensed \ semi-expanded \ expanded \ extra-expanded \ ultra-expanded
font-style normal Yes normal \ italic \ oblique
font-synthesis weight style Yes none \ [ weight \ \ style ]
font-variant normal Yes normal \ none \ [ \ \ \ \ \ \ \ \ \ \ \ \ stylistic(\) \ \ historical-forms \ \ styleset(\ #) \ \ character-variant(\ #) \ \ swash(\) \ \ ornaments(\) \ \ annotation(\) \ \ [ small-caps \ all-small-caps \ petite-caps \ all-petite-caps \ unicase \ titling-caps ] \ \ \ \ \ \ \ \ \ \ \ ordinal \ \ slashed-zero \ \ \ \ \ \ \ \ ruby ]
font-variant-alternates normal Yes normal \ [ stylistic(\) \ \ historical-forms \ \ styleset(\#) \ \ character-variant(\#) \ \ swash(\) \ \ ornaments(\) \ \ annotation(\) ]
font-variant-caps normal Yes normal \ small-caps \ all-small-caps \ petite-caps \ all-petite-caps \ unicase \ titling-caps
font-variant-east-asian normal Yes normal \ [ \ \ \ \ \ \ ruby ]
font-variant-ligatures normal Yes normal \ none \ [ \ \ \ \ \ \ \ \ \ \ ]
font-variant-numeric normal Yes normal \ [ \ \ \ \ \ \ \ \ \ ordinal \ \ slashed-zero ]
font-variant-position normal Yes normal \ sub \ super
font-weight normal Yes normal \ bold \ bolder \ lighter \ 100 \ 200 \ 300 \ 400 \ 500 \ 600 \ 700 \ 800 \ 900
height auto \ \ \ \ auto
left auto \ \ \ \ auto
letter-spacing normal Yes normal \ \
line-height normal Yes normal \ \ \ \ \ \
list-style Yes hash [ 'list-style-type' \ \ 'list-style-position' \ \ 'list-style-image' ]
list-style-image none Yes \ \ none
list-style-position outside Yes inside \ outside
list-style-type disc Yes disc \ circle \ square \ decimal \ decimal-leading-zero \ lower-roman \ upper-roman \ lower-greek \ lower-latin \ upper-latin \ armenian \ georgian \ lower-alpha \ upper-alpha \ none
margin box \{1,4}
margin-bottom 0 \
margin-left 0 \
margin-right 0 \
margin-top 0 \
max-height none \ \ \ \ none
max-width none \ \ \ \ none
min-height 0 \ \ \
min-width 0 \ \ \
opacity 1.0 \
orphans 2 Yes \
outline hash [ 'outline-color' \ \ 'outline-style' \ \ 'outline-width' ]
outline-color invert \ \ invert
outline-style none [ none \ hidden \ dotted \ dashed \ solid \ double \ groove \ ridge \ inset \ outset ]
outline-width medium thin \ medium \ thick \ \
overflow visible visible \ hidden \ scroll \ auto
padding box \{1,4}
padding-bottom 0 \
padding-left 0 \
padding-right 0 \
padding-top 0 \
page-break-after auto auto \ always \ avoid \ left \ right
page-break-before auto auto \ always \ avoid \ left \ right
page-break-inside auto avoid \ auto
pause [ [\ \ \]{1,2} ]
pause-after 0 \ \ \
pause-before 0 \ \ \
pitch medium Yes \ \ x-low \ low \ medium \ high \ x-high
pitch-range 50 Yes \
play-during auto \ [ mix \ \ repeat ]? \ auto \ none
position static static \ relative \ absolute \ fixed
quotes depends on user agent Yes [\ \]+ \ none
richness 50 Yes \
right auto \ \ \ \ auto
size auto \{1,2} \ auto \ [ \ \ \ [ portrait \ landscape] ]
speak normal Yes normal \ none \ spell-out
speak-header once Yes once \ always
speak-numeral continuous Yes digits \ continuous
speak-punctuation none Yes code \ none
speech-rate medium Yes \ \ x-slow \ slow \ medium \ fast \ x-fast \ faster \ slower
stress 50 Yes \
table-layout auto auto \ fixed
text-align a nameless value that acts as 'left' if 'direction' is 'ltr', 'right' if 'direction' is 'rtl' Yes left \ right \ center \ justify
text-decoration none none \ [ underline \ \ overline \ \ line-through \ \ blink ]
text-indent 0 Yes \ \ \
text-transform none Yes capitalize \ uppercase \ lowercase \ none
top auto \ \ \ \ auto
unicode-bidi normal normal \ embed \ bidi-override
vertical-align baseline baseline \ sub \ super \ top \ text-top \ middle \ bottom \ text-bottom \ \ \ \
visibility visible Yes visible \ hidden \ collapse
voice-family depends on user agent Yes [\ \ \ ]#
volume medium Yes \ \ \ \ silent \ x-soft \ soft \ medium \ loud \ x-loud
white-space normal Yes normal \ pre \ nowrap \ pre-wrap \ pre-line
widows 2 Yes \
width auto \ \ \ \ auto
word-spacing normal Yes normal \ \
z-index auto auto \ \

The above markdown table was produced with the following code snippet

use v6;
say <Name Default Inherit Type Synopsis>.join(' | ');
say ('---' xx 5).join(' | ');

my $css = (require CSS::Properties).new;

for $css.properties(:all).sort -> $name {
    with $css.info($name) {
        my @type;
        @type.push: 'hash' if .children;
        @type.push: 'box' if .box;
        my $synopsis-escaped = .synopsis.subst(/<?before <[ < | > # ]>>/, '\\', :g); 

        say ($name,
             .default // '',
             .inherit ?? 'Yes' !! '',
             @type.join(','),
             $synopsis-escaped,
            ).join(' | ');
    }
}