Skip to content

Commit c6600e7

Browse files
authored
fix: Fix CSS rules captured in Safari (#1253)
* fix: Fix CSS rules captured in Safari * Apply formatting changes * add changeset * fix --------- Co-authored-by: mydea <[email protected]>
1 parent d0fbe23 commit c6600e7

File tree

4 files changed

+34
-1
lines changed

4 files changed

+34
-1
lines changed

.changeset/thirty-baboons-punch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'rrweb-snapshot': patch
3+
---
4+
5+
Fix CSS rules captured in Safari

packages/rrweb-snapshot/src/snapshot.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
getCssRulesString,
2323
getInputType,
2424
toLowerCase,
25+
validateStringifiedCssRule,
2526
} from './utils';
2627

2728
let _id = 1;
@@ -53,7 +54,9 @@ function getValidTagName(element: HTMLElement): Lowercase<string> {
5354
function stringifyStyleSheet(sheet: CSSStyleSheet): string {
5455
return sheet.cssRules
5556
? Array.from(sheet.cssRules)
56-
.map((rule) => rule.cssText || '')
57+
.map((rule) =>
58+
rule.cssText ? validateStringifiedCssRule(rule.cssText) : '',
59+
)
5760
.join('')
5861
: '';
5962
}

packages/rrweb-snapshot/src/utils.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,17 @@ export function getCssRuleString(rule: CSSRule): string {
7676
// ignore
7777
}
7878
}
79+
return validateStringifiedCssRule(cssStringified);
80+
}
81+
82+
export function validateStringifiedCssRule(cssStringified: string): string {
83+
// Safari does not escape selectors with : properly
84+
if (cssStringified.includes(':')) {
85+
// Replace e.g. [aa:bb] with [aa\\:bb]
86+
const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
87+
return cssStringified.replace(regex, '$1\\$2');
88+
}
89+
7990
return cssStringified;
8091
}
8192

packages/rrweb-snapshot/test/css.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { parse, Rule, Media } from '../src/css';
2+
import { validateStringifiedCssRule } from './../src/utils';
23

34
describe('css parser', () => {
45
it('should save the filename and source', () => {
@@ -106,4 +107,17 @@ describe('css parser', () => {
106107
decl = rule.declarations![0];
107108
expect(decl.parent).toEqual(rule);
108109
});
110+
111+
it('parses : in attribute selectors correctly', () => {
112+
const out1 = validateStringifiedCssRule('[data-foo] { color: red; }');
113+
expect(out1).toEqual('[data-foo] { color: red; }');
114+
115+
const out2 = validateStringifiedCssRule('[data-foo:other] { color: red; }');
116+
expect(out2).toEqual('[data-foo\\:other] { color: red; }');
117+
118+
const out3 = validateStringifiedCssRule(
119+
'[data-aa\\:other] { color: red; }',
120+
);
121+
expect(out3).toEqual('[data-aa\\:other] { color: red; }');
122+
});
109123
});

0 commit comments

Comments
 (0)