Many popular CSS frameworks like Tailwind CSS (https://tailwindcss.com) and USWDS (https://designsystem.digital.gov/) are beginning to use colons in CSS identifiers (class names) in order to support responsive prefixes and state variants. For example, in Tailwind CSS, you can use the following to support different styles in different states:
<button class="bg-transparent hover:bg-blue text-blue-dark hover:text-white...">
Hover me
</button>I discovered this issue when trying to create a view with a grid display. When I tried to set the custom CSS class for columns to "grid-col-12 tablet:grid-col-4", I am seeing the colon being stripped out. This class value is being passed through `Html::cleanCssIdentifier` which I believe is stripping the colon.
| Comment | File | Size | Author |
|---|---|---|---|
| #2 | allow_colons_css_identifiers-3050007-2.patch | 1.09 KB | rromore |
Comments
Comment #2
rromore commentedComment #3
cilefen commentedIf colons are allowed by the W3 in class names (I guess Tailwinds doesn’t break pseudo-classes in the style sheet?) then this is a bug. But also note the character is configurable: https://tailwindcss.com/docs/configuration/#app
Comment #4
rromore commentedTechnically, according to the CSS specification, "...identifiers (including element names, classes, and IDs in selectors) can contain only the characters [a-zA-Z0-9] and ISO 10646 characters U+00A0 and higher, plus the hyphen (-) and the underscore (_); they cannot start with a digit, two hyphens, or a hyphen followed by a digit. Identifiers can also contain escaped characters and any ISO 10646 character as a numeric code (see next item). For instance, the identifier 'B&W?' may be written as 'B\&W\?' or 'B\26 W\3F'" (https://www.w3.org/TR/CSS21/syndata.html#value-def-identifier). From just looking at the source of the `Html::cleanCssIdentifier` method, I believe it supports all of these conditions except the last one.
Comment #5
rromore commentedI would also just like to quickly note that the patch I've attached to the issue does work, but applying it might produce some unintended consequences depending on the class names you've used for selecting in CSS or JS. For example, I have a view called "News" with a block display. Before applying the patch, the class value of this block div element was "block block-views block-views-blocknews-block-1". After applying the patch, it is now "block block-views block-views-block:news-block-1".
Comment #6
cilefen commentedComment #7
cilefen commentedSo an escaped colon is stripped too?
Comment #8
rromore commentedYep, unfortunately. Without patch and without slash:
https://i.imgur.com/NqrbWZb.png
https://i.imgur.com/Zk0bsmH.png
Without patch and with slash:
https://i.imgur.com/UtcAGxh.png
https://i.imgur.com/2q6y7dP.png
With patch and without slash (& with slash since the slash gets removed anyways):
https://i.imgur.com/1wtOCnt.png
Also, thank you for pointing me to the Tailwind CSS configuration options. I am using USWDS and I don't believe it currently supports a configurable separator, and have opened a related issue here: https://github.com/uswds/uswds/issues/3045.
Comment #10
chris burge commentedThe issue isn't with the colons, specifically. It's with escaped characters more generally. There's a sister issue at #2916377: Html::cleanCssIdentifier Strips Valid Escaped Characters where they're solving for slash and '@' sign (but not colons).
Comment #13
mattsmith321 commentedI'm using the patch provided in #2. I also acknowledge the authors comment in #5 about unintended consequences. With that said, is there a way to update the preg_replace parameters to be less greedy? Or, phrased a little differently, to only allow colons in specific class names that I allow?
Here is an example of the USWDS class names that I am using:
desktop:grid-col-3 tablet:grid-col-6 usa-card mobile-lg:grid-col-12
While USWDS has way too many combos if you factor in the left and right side of the colon (2,828 unique combos to be exact), the left side boils down to:
*desktop:
*hover:
*mobile-lg:
*tablet:
The only challenge might be dealing with the spots that use desktop:hover: / mobile-lg:hover / tablet:hover but I'm not worried about that.
So is there a way to update pattern parameter to include a check for the literal string of "desktop:" or the unicode equivalent? I know there is a way in regex in general and I was trying to work my way through it last night but then killed my installation and couldn't get back even after undoing my changes.
Thanks for any help. Yes, I know that putting in these literal exceptions is not a good fix, but I want to avoid the unintended consequences of changing a whole bunch of Drupal generated class names.
Comment #14
mattsmith321 commentedWell that didn't take long to run into the unintended consequences of the greedy colon replacement. Lots of colons started showing up in the various Drupal managed class names, especially around views and blocks. I spent a couple hours trying to modify the regex pattern to try to narrow it down to something along the lines of
\b(desktop|tablet|mobile-lg)\:\bbut didn't have much luck. To make it work for now, I added code to replace the colons with a placeholder and then swapped them back out after the stripping call.I acknowledge it is a bit of a hack but I'm at least trying to narrow the scope of the replacement as much as possible. At the end of the day, I really need to support the USWDS use of colons. We have already created custom twig files in a couple of scenarios just to be able to use the colons in class names. This 'fix' should prevent that from multiplying going forward.
I am not wrapping it in a patch since I don't think this is the best solution that will work for everyone. I am however posting the code in case it helps someone else out.
Comment #18
smustgrave commentedWondering if there has been any change? Still an issue for uswd and more gov sites are using uswds now.
Comment #19
cilefen commentedI don’t understand the question.
Comment #20
smustgrave commentedJust seeing if anyone has come up with a good solution. Thought about whitelisting the class attribute but that doesn't seem right. USWDS library has been picking up steam lately so this is becoming an issue across multiple projects.
Comment #21
rromore commentedWith the latest versions of USWDS (the library, not the theme) you can change the character that separates the responsive and state prefixes from the main class: https://github.com/uswds/uswds/blob/develop/src/stylesheets/theme/_uswds....
Comment #22
ocastle commentedThis issue isn't limited to just a colon within libraries. Some libraries also use '@' symbols in their css classes. e.g. uikit. https://getuikit.com/docs/visibility
Comment #23
lendudeSeems like the colon was included in #2916377: Html::cleanCssIdentifier Strips Valid Escaped Characters now too.
I'm going to close this as a duplicate but feel free to re-open this issue is you feel this is addressing a different issue, or that you feel the colon needs a separate issue.