Problem/Motivation
Escaped characters in CSS classes are valid. Several popular CSS/Sass libraries use escaped characters (particularly ones which use the BEM methodology) to denote special uses or characteristics of a CSS class.
For instance, the inuitcss CSS library uses the @
character in CSS classes for identifying responsive breakpoint classes and the forward slash /
character for fractional grid column classes.
Example CSS with Escaped Characters
.u-1\/1 {
// CSS here.
}
.u-1\/2\/@tablet {
// CSS here.
}
.u-1\/3\/@desktop {
// CSS here.
}
Example Markup Using CSS classes with escaped characters
<div class="o-layout__item u-1/1 u-1/2@tablet u-1/3@desktop">
The Html::cleanCssIdentifier
function strips escaped characters however, making Drupal incompatible with CSS which uses them.
Drupal Example of Problem
In a twig template, using the clean_class
filter (which uses Html::cleanCssIdentifier
), such as:
{% set classes = [
'o-layout__item',
('u-1/1'|clean_class),
('u-1/2@tablet'|clean_class),
('u-1/3@desktop'|clean_class),
('u-1/3@desktop'|clean_class)
]
%}
<div{{ attributes.addClass(classes) }}>I'm a div with grid classes</div>
produces the following markup:
<div class="o-layout__item u-1-1 u-1-2tablet u-1-3desktop">I'm a div with grid classes</div>
when the markup should instead be:
<div class="o-layout__item u-1/1 u-1/2@tablet u-1/3@desktop">I'm a div with grid classes</div>
Proposed resolution
Update the regex used in the current Html::cleanCssIdentifier
// Valid characters in a CSS identifier are:
// - the hyphen (U+002D)
// - a-z (U+0030 - U+0039)
// - A-Z (U+0041 - U+005A)
// - the underscore (U+005F)
// - 0-9 (U+0061 - U+007A)
// - ISO 10646 characters U+00A1 and higher
// We strip out any character not in the above list.
$identifier = preg_replace('/[^\x{002D}\x{0030}-\x{0039}\x{0041}-\x{005A}\x{005F}\x{0061}-\x{007A}\x{00A1}-\x{FFFF}]/u', '', $identifier);
// Identifiers cannot start with a digit, two hyphens, or a hyphen followed by a digit.
$identifier = preg_replace([
'/^[0-9]/',
'/^(-[0-9])|^(--)/'
], ['_', '__'], $identifier);
return $identifier;
to allow for escaped characters.