CSS-DOM
view release on metacpan or search on metacpan
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
(?:
(?(?{\$\$prepped[pos()-1]eq 'rgb('})|(?!))
(?: $sign 1(?:,$sign 1){2} | $sign%(?:,$sign%){2} )
|
(?(?{\$\$prepped[pos()-1]eq 'rgba('})|(?!))
(?: $sign 1(?:,$sign 1){2} | $sign%(?:,$sign%){2} ),$sign 1
)
\\)) (?{ $type_is_ CSS_RGBCOLOR })
)" . cap_end . ")"
# <counter> represents the following four:
# counter(<identifier>)
# counter(<identifier>,'list-style-type')
# counters(<identifier>,<string>)
# counters(<identifier>,<string>,'list-style-type')
: $3 eq 'counter' ? do {
our $Self;
my $list_style_type = old_perl
? exists $$Self{"list-style-type"}
? $compiled{$$Self{"list-style-type"}{format}}
||= _compile_format($$Self{"list-style-type"}{format})
: '(?!)'
: '(??{
exists $$Self{"list-style-type"}
? $compiled{$$Self{"list-style-type"}{format}}
: $Fail
})'
;
q*(?x:* . cap_start . q*(f(?{$$prepped[pos()-1]})
(?(?{$^R eq "counter("})
i(?:,* . $list_style_type . q*)?
|
(?(?{$^R eq "counters("})
i,'(?:,* . $list_style_type . q*)?
|
(?!)
)
)
\))*
. "(?{ $type_is_ CSS_COUNTER;"
. ' $valtypes[$#valtypes=pos()-1] = -1})' # -1 is a special
. cap_end . ')' # marker for the end
} # of a counter
: $3 eq 'frequency' ?
'(?:' . cap_start . '((?:d(?(?{
$$tokens[pos()-1]eq"+"||$$tokens[-1+pos]eq"-"&&$$tokens[pos]eq 0
})|(?!)))?[D1](?(?{
my$p=$$prepped[pos()-1];$p eq"hz"||$p eq"khz"||$p eq 0
})|(?!)))' . $type_is_dim_or_number . cap_end . ")"
: $3 eq 'identifier' ?
"(?:" . cap_start . "(i)(?{ $type_is_ CSS_IDENT })" . cap_end . ")"
: $3 eq 'integer' ?
'(?:' . cap_start . '(1(?(?{index$$tokens[pos()-1],".",==-1})|(?!)))'
. "(?{ $type_is_ CSS_NUMBER })" . cap_end . ")"
: $3 eq 'length' ?
"(?:" . cap_start . "($sign\[D1])" . '(?(?{
$$alt_types[pos()-1]eq"l"||$$prepped[pos()-1]eq 0
})|(?!))' . $type_is_dim_or_number . cap_end . ")"
: $3 eq 'number' ?
"(?:" . cap_start . "(1)(?{ $type_is_ CSS_NUMBER })" . cap_end . ")"
: $3 eq 'percentage' ?
"(?:" . cap_start
. "($sign%)(?{ $type_is_ CSS_PERCENTAGE })"
. cap_end . ")"
: $3 eq 'shape' ?
q*(?x:* . cap_start . q*(f
(?(?{$$prepped[pos()-1] eq "rect("})
(?:
(?:
(?:d(?(?{$$alt_types[pos()-1]eq"+"})|(?!)))?[D1](?(?{
$$alt_types[pos()-1]eq"l"||$$prepped[pos()-1] eq 0
})|(?!))
|
i(?(?{$$prepped[pos()-1]eq"auto"})|(?!))
),?
){4}
|
(?!)
)
\))* . "(?{ $type_is_ CSS_RECT })" . cap_end . ")"
: $3 eq 'string' ?
"(?:" . cap_start . "(')(?{ $type_is_ CSS_STRING })" . cap_end . ")"
: $3 eq 'str/words' ?
"(?:" . cap_start
. "('|i+)(?{ $type_is_ CSS_STRING })"
. cap_end . ")"
: $3 eq 'time' ?
"(?:" . cap_start . "($sign\[D1])" . '(?(?{
my$p=$$prepped[pos()-1];$p eq"ms"||$p eq"s"||$p eq 0
})|(?!))' . $type_is_dim_or_number . cap_end . ")"
: $3 eq 'url' ?
"(?:" . cap_start . "(u)(?{ $type_is_ CSS_URI })" . cap_end . ")"
: die "Unrecognised data type in property format: <$3>";
}
elsif($4) { # identifier
$pattern .=
'(?:' . cap_start
. '(i)(?(?{$$prepped[-1+pos]eq"' . $4 . '"})|(?!))'
. "(?{ $type_is_ CSS_IDENT })"
. cap_end . ")";
}
elsif($5) { # number
$pattern .=
'(?:' . cap_start
. '(1)(?(?{$$tokens[-1+pos]eq"' . $5 . '"})|(?!))'
. "(?{ $type_is_ CSS_NUMBER })"
. cap_end . ")";
}
elsif($6) { # '...' reference
$pattern .=
'(?:' # again, we use (?: ... ) in case a question mark is added
. cap_start
. '((??{
exists $$Self{"' . $6 . '"}
? $compiled{$$Self{"' . $6 . '"}{format}}
: $Fail;
}))'
. '(?{
# We have a do-block here because a re-evalâs lexical pad is very
# buggy and must not be used. (See perl bug #65150.)
local$match{"'.$6.'"}=do{
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
~~~
CSS::DOM::Style currently relies on the internal formatting of the hash
refs. I want to allow custom property parser classes to do away with hash
refs
altogether, so I will need extra methods here that Style will use instead.
=back
=end comment
=head1 HOW INDIVIDUAL PROPERTIES ARE SPECIFIED
Before you read this the first time, look at the L</Example> below, and
then come back and use this for reference.
The specification for an individual property is a hash ref. There are
several keys that each hash ref can have:
=over
=item format
This is set to a string that describes the format of the property. The
syntax used is based on the CSS 2.1 spec, but is not exactly the same.
Unlike regular expressions, these formats are applied to properties on a
token-by-token basis, not one character at a time. (This means that
C<100|200> cannot be written as C<[1|2]00>, as that would mean
S<C<1 00 | 2 00>>.)
Whitespace is ignored in the format and in the CSS property except as a
token separator.
There are several metachars (in order of precedence):
[...] grouping (like (?:...) )
(...) capturing group (just like a regexp)
? optional
* zero or more
+ one or more
|| alternates that can come in any order and are optional,
but at least one must be specified (the order will be
retained if possible)
| alternates, exactly one of which is required
In addition, the following datatypes can be specified in angle brackets:
<angle> A number with a 'deg', 'rad' or 'grad' suffix
<attr> attr(...)
<colour> (You can omit the 'u' if you want to.) One of CSS's
predefined colour or system colour names, or a #
followed by 3 or 6 hex digits, or the 'rgb(...)'
format (rgba is supported, too)
<counter> counter(...)
<frequency> A unit of Hz or kHz
<identifier> An identifier token
<integer> An integer (really?!)
<length> Number followed by a length unit (em, ex, px, in, cm,
mm, pt, pc)
<number> A number token
<percentage> Number followed by %
<shape> rect(...)
<string> A string token
<str/words> A sequence of identifiers or a single string (e.g., a
font name)
<time> A unit of seconds or milliseconds
<url> A URL token
The format for a shorthand property can contain the name of a sub-property
in single ASCII quotes.
All other characters are understood verbatim.
It is not necessary to include the word 'inherit' in the format, since
every property supports that.
C<< <counter> >> makes use of the specification for the list-style-type
property. So if you modify the latter, it will affect C<< <counter> >> as
well.
=item default
The default value. This only applies to simple properties.
=item inherit
Whether the property is inherited.
=item special_values
A hash ref of values that are replaced with other values (e.g.,
S<C<< caption => '13px sans-serif' >>>.) The keys
are lowercase identifier names.
This feature only applies to single identifiers. In fact, it exists solely
for the font property's use.
=item list
Set to true if the property is a list of values. The capturing parentheses
in the format determine the individual values of the list.
This applies to simple properties only.
=item properties
For a shorthand property, list the sub-properties here. The keys are the
property names. The values are array refs. The elements within the arrays
are numbers indicating which captures in the format are to be used for the
sub-property's value. They are tried one after the other. Whichever is the
first that matches (null matches not counting) is used.
Sub-properties that are referenced in the C<format> need not be listed
here.
=item serialise
For shorthand properties only. Set this to a subroutine that serialises the
property. It is called with a hashref of sub-properties as its sole
argument. The values of the hash are blank for properties that are set to
their initial values. This sub is only called when all sub-properties are
set.
=back
=head2 Example
=cut
0&&q r
=for ;
our $CSS21 = new CSS::DOM::PropertyParser;
my %properties = (
azimuth => {
format => '<angle> |
[ left-side | far-left | left | center-left |
center | center-right | right | far-right |
right-inside ] || behind
| leftwards | rightwards',
default => '0',
inherit => 1,
},
'background-attachment' => {
format => 'scroll | fixed',
default => 'scroll',
inherit => 0,
},
'background-color' => {
format => '<colour>',
default => 'transparent',
inherit => 0,
},
'background-image' => {
format => '<url> | none',
default => 'none',
inherit => 0,
},
'background-position' => {
format => '[<percentage>|<length>|left|right]
[<percentage>|<length>|top|center|bottom]? |
[top|bottom] [left|center|right]? |
center [<percentage>|<length>|left|right|top|bottom|
center]?',
default => '0% 0%',
inherit => 0,
},
'background-repeat' => {
format => 'repeat | repeat-x | repeat-y | no-repeat',
default => 'repeat',
inherit => 0,
},
background => {
format => "'background-color' || 'background-image' ||
'background-repeat' || 'background-attachment' ||
'background-position'",
serialise => sub {
my $p = shift;
my $ret = '';
for(qw/ background-color background-image background-repeat
background-attachment background-position /) {
length $p->{$_} and $ret .= "$p->{$_} ";
}
chop $ret;
length $ret ? $ret : 'none'
},
},
'border-collapse' => {
format => 'collapse | separate',
inherit => 1,
default => 'separate',
},
'border-color' => {
format => '(<colour>)[(<colour>)[(<colour>)(<colour>)?]?]?',
properties => {
'border-top-color' => [1],
'border-right-color' => [2,1],
'border-bottom-color' => [3,1],
'border-left-color' => [4,2,1],
},
serialise => sub {
my $p = shift;
my @vals = map $p->{"border-$_-color"},
qw/top right bottom left/;
$vals[3] eq $vals[1] and pop @vals,
$vals[2] eq $vals[0] and pop @vals,
$vals[1] eq $vals[0] and pop @vals;
return join " ", @vals;
},
},
'border-spacing' => {
format => '<length> <length>?',
default => '0',
inherit => 1,
},
'border-style' => {
format => "(none|hidden|dotted|dashed|solid|double|groove|ridge|
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
},
'border-width' => {
format => "(<length>|thin|thick|medium)
[ (<length>|thin|thick|medium)
[ (<length>|thin|thick|medium)
(<length>|thin|thick|medium)?
]?
]?",
properties => {
'border-top-width' => [1],
'border-right-width' => [2,1],
'border-bottom-width' => [3,1],
'border-left-width' => [4,2,1],
},
serialise => sub {
my $p = shift;
my @vals = map $p->{"border-$_-width"},
qw/top right bottom left/;
$vals[3] eq $vals[1] and pop @vals,
$vals[2] eq $vals[0] and pop @vals,
$vals[1] eq $vals[0] and pop @vals;
return join " ", map length $_ ? $_ : 'medium', @vals;
},
},
border => {
format => "(<length>|thin|thick|medium) ||
(none|hidden|dotted|dashed|solid|double|groove|ridge|
inset|outset) || (<colour>)",
properties => {
'border-top-width' => [1],
'border-right-width' => [1],
'border-bottom-width' => [1],
'border-left-width' => [1],
'border-top-style' => [2],
'border-right-style' => [2],
'border-bottom-style' => [2],
'border-left-style' => [2],
'border-top-color' => [3],
'border-right-color' => [3],
'border-bottom-color' => [3],
'border-left-color' => [3],
},
serialise => sub {
my $p = shift;
my $ret = '';
for(qw/ width style color /) {
my $temp = $p->{"border-top-$_"};
for my $side(qw/ right bottom left /) {
$temp eq $p->{"border-$side-$_"} or return "";
}
length $temp and $ret .= "$temp ";
}
chop $ret;
$ret
},
},
bottom => {
format => '<length>|<percentage>|auto',
default => 'auto',
inherit => 0,
},
'caption-side' => {
format => 'top|bottom',
default => 'top',
inherit => 1,
},
clear => {
format => 'none|left|right|both',
default => 'none',
inherit => 0,
},
clip => {
format => '<shape>|auto',
default => 'auto',
inherit => 0,
},
color => {
format => '<colour>',
default => 'rgba(0,0,0,1)',
inherit => 1,
},
content => {
format => '( normal|none|open-quote|close-quote|no-open-quote|
no-close-quote|<string>|<url>|<counter>|<attr> )+',
default => 'normal',
inherit => 0,
list => 1,
},
'counter-increment' => {
format => '[(<identifier>) (<integer>)? ]+ | none',
default => 'none',
inherit => 0,
list => 1,
},
'counter-reset' => {
format => '[(<identifier>) (<integer>)? ]+ | none',
default => 'none',
inherit => 0,
list => 1,
},
'cue-after' => {
format => '<url>|none',
default => 'none',
inherit => 0,
},
'cue-before' => {
format => '<url>|none',
default => 'none',
inherit => 0,
},
lib/CSS/DOM/PropertyParser.pm view on Meta::CPAN
$vals[1] eq $vals[0] and pop @vals;
return join " ", map length $_ ? $_ : 'none', @vals;
},
},
cursor => {
format => '[(<url>) ,]*
(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)',
default => 'auto',
inherit => 1,
list => 1,
},
direction => {
format => 'ltr|rtl',
default => 'ltr',
inherit => 1,
},
display => {
format => 'inline|block|list-item|run-in|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',
default => 'inline',
inherit => 0,
},
elevation => {
format => '<angle>|below|level|above|higher|lower',
default => '0',
inherit => 1,
},
'empty-cells' => {
format => 'show|hide',
default => 'show',
inherit => 1,
},
float => {
format => 'left|right|none',
default => 'none',
inherit => 0,
},
'font-family' => { # aka typeface
format => '(serif|sans-serif|cursive|fantasy|monospace|
<str/words>)
[,(serif|sans-serif|cursive|fantasy|monospace|
<str/words>)]*',
default => 'Times, serif',
inherit => 1,
list => 1,
},
'font-size' => {
format => 'xx-small|x-small|small|medium|large|x-large|xx-large|
larger|smaller|<length>|<percentage>',
default => 'medium',
inherit => 1,
},
'font-style' => {
format => 'normal|italic|oblique',
default => 'normal',
inherit => 1,
},
'font-variant' => {
format => 'normal | small-caps',
default => 'normal',
inherit => 1,
},
'font-weight' => {
format => 'normal|bold|bolder|lighter|
100|200|300|400|500|600|700|800|900',
default => 'normal',
inherit => 1,
},
font => {
format => "[ 'font-style' || 'font-variant' || 'font-weight' ]?
'font-size' [ / 'line-height' ]? 'font-family'",
special_values => {
caption => '13px Lucida Grande, sans-serif',
icon => '13px Lucida Grande, sans-serif',
menu => '13px Lucida Grande, sans-serif',
'message-box' => '13px Lucida Grande, sans-serif',
'small-caption' => '11px Lucida Grande, sans-serif',
'status-bar' => '10px Lucida Grande, sans-serif',
},
serialise => sub {
my $p = shift;
my $ret = '';
for(qw/ style variant weight /) {
length $p->{"font-$_"}
and $ret .= $p->{"font-$_"}." ";
}
$ret .= length $p->{'font-size'}
? $p->{'font-size'}
: 'medium';
$ret .= "/$p->{'line-height'}" if length $p->{'line-height'};
$ret .= " " . ($p->{'font-family'} || "Times, serif");
$ret
},
},
height => {
format => '<length>|<percentage>|auto',
default => 'auto',
inherit => 0,
},
left => {
format => '<length>|<percentage>|auto',
default => 'auto',
inherit => 0,
},
'letter-spacing' => { # aka tracking
format => 'normal|<length>',
default => 'normal',
inherit => 1,
},
'line-height' => { # aka leading
format => 'normal|<number>|<length>|<percentage>',
default => "normal",
inherit => 1,
},
'list-style-image' => {
format => '<url>|none',
default => 'none',
inherit => 1,
},
'list-style-position' => {
format => 'inside|outside',
default => 'outside',
inherit => 1,
},
'list-style-type' => {
format => 'disc|circle|square|decimal|decimal-leading-zero|
lower-roman|upper-roman|lower-greek|lower-latin|
upper-latin|armenian|georgian|lower-alpha|
upper-alpha',
default => 'disc',
inherit => 1,
},
'list-style' => {
format => "'list-style-type'||'list-style-position'||
'list-style-image'",
serialise => sub {
my $p = shift;
my $ret = '';
for(qw/ type position image /) {
$p->{"list-style-$_"}
and $ret .= $p->{"list-style-$_"}." ";
}
chop $ret;
$ret || 'disc'
},
},
'margin-right' => {
format => '<length>|<percentage>|auto',
default => '0',
inherit => 0,
},
'margin-left' => {
format => '<length>|<percentage>|auto',
default => '0',
inherit => 0,
},
'margin-top' => {
format => '<length>|<percentage>|auto',
default => '0',
inherit => 0,
},
'margin-bottom' => {
format => '<length>|<percentage>|auto',
default => '0',
inherit => 0,
},
margin => {
format => "(<length>|<percentage>|auto)
[ (<length>|<percentage>|auto)
[ (<length>|<percentage>|auto)
(<length>|<percentage>|auto)?
]?
]?",
properties => {
'margin-top' => [1],
'margin-right' => [2,1],
'margin-bottom' => [3,1],
'margin-left' => [4,2,1],
},
serialise => sub {
my $p = shift;
my @vals = map $p->{"margin-$_"},
qw/top right bottom left/;
$vals[3] eq $vals[1] and pop @vals,
$vals[2] eq $vals[0] and pop @vals,
$vals[1] eq $vals[0] and pop @vals;
return join " ", map $_ || 0, @vals;
},
},
'max-height' => {
format => '<length>|<percentage>|none',
default => 'none',
inherit => 0,
},
'max-width' => {
format => '<length>|<percentage>|none',
default => 'none',
inherit => 0,
},
'min-height' => {
format => '<length>|<percentage>|none',
default => 'none',
inherit => 0,
},
'min-width' => {
format => '<length>|<percentage>|none',
default => 'none',
inherit => 0,
},
orphans => {
format => '<integer>',
default => 2,
inherit => 1,
},
'outline-color' => {
format => '<colour>|invert',
default => 'invert',
inherit => 0,
},
'outline-style' => {
format => 'none|hidden|dotted|dashed|solid|double|groove|ridge|
inset|outset',
default => 'none',
inherit => 0,
},
'outline-width' => {
format => '<length>|thin|thick|medium',
default => 'medium',
inherit => 0,
},
outline => {
format => "'outline-color'||'outline-style'||'outline-width'",
serialise => sub {
my $p = shift;
my $ret = '';
for(qw/ color style width /) {
length $p->{"outline-$_"}
and $ret .= $p->{"outline-$_"}." ";
}
chop $ret;
length $ret ? $ret : 'invert';
},
},
overflow => {
format => 'visible|hidden|scroll|auto',
default => 'visible',
inherit => 0,
},
'padding-top' => {
format => '<length>|<percentage>',
default => 0,
inherit => 0,
},
'padding-right' => {
format => '<length>|<percentage>',
default => 0,
inherit => 0,
},
'padding-bottom' => {
format => '<length>|<percentage>',
default => 0,
inherit => 0,
},
'padding-left' => {
format => '<length>|<percentage>',
default => 0,
inherit => 0,
},
padding => {
format => "(<length>|<percentage>)
[ (<length>|<percentage>)
[ (<length>|<percentage>)
(<length>|<percentage>)?
]?
]?",
properties => {
'padding-top' => [1],
'padding-right' => [2,1],
'padding-bottom' => [3,1],
'padding-left' => [4,2,1],
},
serialise => sub {
my $p = shift;
my @vals = map $p->{"padding-$_"},
qw/top right bottom left/;
$vals[3] eq $vals[1] and pop @vals,
$vals[2] eq $vals[0] and pop @vals,
$vals[1] eq $vals[0] and pop @vals;
return join " ", map $_ || 0, @vals;
},
},
'page-break-after' => {
format => 'auto|always|avoid|left|right',
default => 'auto',
inherit => 0,
},
'page-break-before' => {
format => 'auto|always|avoid|left|right',
default => 'auto',
inherit => 0,
},
'page-break-inside' => {
format => 'avoid|auto',
default => 'auto',
inherit => 1,
},
'pause-after' => {
format => '<time>|<percentage>',
default => 0,
inherit => 0,
},
'pause-before' => {
format => '<time>|<percentage>',
default => 0,
inherit => 0,
},
pause => {
format => '(<time>|<percentage>)(<time>|<percentage>)?',
properties => {
'pause-before' => [1],
'pause-after' => [2,1],
}
},
'pitch-range' => {
format => '<number>',
default => 50,
inherit => 1,
},
pitch => {
format => '<frequency>|x-low|low|medium|high|x-high',
default => 'medium',
inherit => 1,
},
'play-during' => {
format => '<url> [ mix || repeat ]? | auto | none',
default => 'auto',
inherit => 0,
},
position => {
format => 'static|relative|absolute|fixed',
default => 'relative',
inherit => 0,
},
quotes => {
format => '[(<string>)(<string>)]+|none',
default => 'none',
inherit => 1,
list => 1,
},
richness => {
format => '<number>',
default => 50,
inherit => 1,
},
right => {
format => '<length>|<percentage>|auto',
default => 'auto',
inherit => 0,
},
'speak-header' => {
format => 'once|always',
default => 'once',
inherit => 1,
},
'speak-numeral' => {
format => 'digits|continuous',
default => 'continuous',
inherit => 1,
},
'speak-punctuation' => {
format => 'code|none',
default => 'none',
inherit => 1,
},
speak => {
format => 'normal|none|spell-out',
default => 'normal',
inherit => 1,
},
'speech-rate' => {
format => '<number>|x-slow|slow|medium|fast|x-fast|faster|slower',
default => 'medium',
inherit => 1,
},
stress => {
format => '<number>',
default => 50,
inherit => 1,
},
'table-layout' => {
format => 'auto|fixed',
default => 'auto',
inherit => 0,
},
'text-align' => {
format => 'left|right|center|justify|auto',
default => 'auto',
inherit => 1,
},
'text-decoration' => {
format => 'none | underline||overline||line-through||blink ',
default => 'none',
inherit => 0,
},
'text-indent' => {
format => '<length>|<percentage>',
default => 0,
inherit => 1,
},
'text-transform' => {
format => 'capitalize|uppercase|lowercase|none',
default => 'none',
inherit => 1,
},
top => {
format => '<length>|<percentage>|auto',
default => 'auto',
inherit => 0,
},
'unicode-bidi' => {
format => 'normal|embed|bidi-override',
default => 'normal',
inherit => 0,
},
'vertical-align' => {
format => 'baseline|sub|super|top|text-top|middle|bottom|
text-bottom|<percentage>|<length>',
default => 'baseline',
inherit => 0,
},
visibility => {
format => 'visible|hidden|collapse',
default => 'visible',
inherit => 1,
},
'voice-family' => {
format => '(male|female|child|<str/words>)
[, (male|female|child|<str/words>) ]*',
default => '',
inherit => 1,
list => 1,
},
volume => {
format => '<number>|<percentage>|silent|x-soft|soft|medium|loud|
x-loud',
default => 'medium',
inherit => 1,
},
'white-space' => {
format => 'normal|pre|nowrap|pre-wrap|pre-line',
default => 'normal',
inherit => 1,
},
widows => {
format => '<integer>',
default => 2,
inherit => 1,
},
width => {
format => '<length>|<percentage>|auto',
default => 'auto',
inherit => 0,
},
'word-spacing' => {
format => 'normal|<length>',
default => 'normal',
inherit => 1,
},
'z-index' => {
format => 'auto|<integer>',
default => 'auto',
inherit => 0,
},
);
$CSS21->add_property( $_ => $properties{$_} ) for keys %properties;
=pod
=cut
our $Default = $CSS21;
=head1 SEE ALSO
L<CSS::DOM>
( run in 0.632 second using v1.01-cache-2.11-cpan-39bf76dae61 )