Preserve authored CSS specificity (#4024)

* feat: preserve authored CSS specificity

* chore: update tests to use :where()

* test: fix HTML and CSS test

* test: fix imported markdown CSS test

Co-authored-by: Nate Moore <nate@astro.build>
This commit is contained in:
Nate Moore 2022-07-23 13:11:12 -05:00 committed by GitHub
parent 7db1cc20e9
commit 1215e731b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 24 additions and 15 deletions

View file

@ -0,0 +1,9 @@
---
'astro': patch
---
**BREAKING** Implement [RFC0012](https://github.com/withastro/rfcs/blob/main/proposals/0012-scoped-css-with-preserved-specificity.md) to preserve authored specificity for Astro scoped styles.
If you use a mix of global styles and Astro scoped styles, **please visually inspect your site** after upgrading to confirm that styles are working as expected.
If you previously relied on Astro's scoped styles to increase the specificity of your selectors, please update your selectors to use an additional class. For example, updating `div` to `div.my-class` will match the previous behavior.

View file

@ -82,7 +82,7 @@
"test:e2e:match": "playwright test -g" "test:e2e:match": "playwright test -g"
}, },
"dependencies": { "dependencies": {
"@astrojs/compiler": "^0.21.0", "@astrojs/compiler": "^0.22.0",
"@astrojs/language-server": "^0.20.0", "@astrojs/language-server": "^0.20.0",
"@astrojs/markdown-remark": "^0.12.0", "@astrojs/markdown-remark": "^0.12.0",
"@astrojs/prism": "0.6.1", "@astrojs/prism": "0.6.1",

View file

@ -46,7 +46,7 @@ describe('CSS', function () {
expect(el2.attr('class')).to.equal(`visible ${scopedClass}`); expect(el2.attr('class')).to.equal(`visible ${scopedClass}`);
// 2. check CSS // 2. check CSS
const expected = `.blue.${scopedClass}{color:#b0e0e6}.color\\\\:blue.${scopedClass}{color:#b0e0e6}.visible.${scopedClass}{display:block}`; const expected = `.blue:where(.${scopedClass}){color:#b0e0e6}.color\\\\:blue:where(.${scopedClass}){color:#b0e0e6}.visible:where(.${scopedClass}){display:block}`;
expect(bundledCSS).to.include(expected); expect(bundledCSS).to.include(expected);
}); });
@ -69,11 +69,11 @@ describe('CSS', function () {
}); });
it('<style lang="sass">', async () => { it('<style lang="sass">', async () => {
expect(bundledCSS).to.match(new RegExp('h1.astro-[^{]*{color:#90ee90}')); expect(bundledCSS).to.match(new RegExp('h1\\:where\\(.astro-[^{]*{color:#90ee90}'));
}); });
it('<style lang="scss">', async () => { it('<style lang="scss">', async () => {
expect(bundledCSS).to.match(new RegExp('h1.astro-[^{]*{color:#ff69b4}')); expect(bundledCSS).to.match(new RegExp('h1\\:where\\(.astro-[^{]*{color:#ff69b4}'));
}); });
}); });
@ -308,10 +308,10 @@ describe('CSS', function () {
it('resolves Astro styles', async () => { it('resolves Astro styles', async () => {
const allInjectedStyles = $('style[data-astro-injected]').text(); const allInjectedStyles = $('style[data-astro-injected]').text();
expect(allInjectedStyles).to.contain('.linked-css.astro-'); expect(allInjectedStyles).to.contain('.linked-css:where(.astro-');
expect(allInjectedStyles).to.contain('.linked-sass.astro-'); expect(allInjectedStyles).to.contain('.linked-sass:where(.astro-');
expect(allInjectedStyles).to.contain('.linked-scss.astro-'); expect(allInjectedStyles).to.contain('.linked-scss:where(.astro-');
expect(allInjectedStyles).to.contain('.wrapper.astro-'); expect(allInjectedStyles).to.contain('.wrapper:where(.astro-');
}); });
it('resolves Styles from React', async () => { it('resolves Styles from React', async () => {

View file

@ -29,7 +29,7 @@ describe('Imported markdown CSS', function () {
expect(importedAstroComponent?.name).to.equal('h2'); expect(importedAstroComponent?.name).to.equal('h2');
const cssClass = $(importedAstroComponent).attr('class')?.split(/\s+/)?.[0]; const cssClass = $(importedAstroComponent).attr('class')?.split(/\s+/)?.[0];
expect(bundledCSS).to.match(new RegExp(`h2.${cssClass}{color:#00f}`)); expect(bundledCSS).to.include(`h2:where(.${cssClass}){color:#00f}`);
}); });
}); });
describe('dev', () => { describe('dev', () => {
@ -53,7 +53,7 @@ describe('Imported markdown CSS', function () {
const cssClass = $(importedAstroComponent).attr('class')?.split(/\s+/)?.[0]; const cssClass = $(importedAstroComponent).attr('class')?.split(/\s+/)?.[0];
const allInjectedStyles = $('style[data-astro-injected]').text().replace(/\s*/g, ''); const allInjectedStyles = $('style[data-astro-injected]').text().replace(/\s*/g, '');
expect(allInjectedStyles).to.match(new RegExp(`h2.${cssClass}{color:#00f}`)); expect(allInjectedStyles).to.include(`h2:where(.${cssClass}){color:#00f}`);
}); });
}); });
}); });

View file

@ -26,7 +26,7 @@ describe('Partial HTML', async () => {
// test 2: correct CSS present // test 2: correct CSS present
const allInjectedStyles = $('style[data-astro-injected]').text(); const allInjectedStyles = $('style[data-astro-injected]').text();
expect(allInjectedStyles).to.match(/\.astro-[^{]+{color:red}/); expect(allInjectedStyles).to.match(/\:where\(\.astro-[^{]+{color:red}/);
}); });
it('injects framework styles', async () => { it('injects framework styles', async () => {

View file

@ -438,7 +438,7 @@ importers:
packages/astro: packages/astro:
specifiers: specifiers:
'@astrojs/compiler': ^0.21.0 '@astrojs/compiler': ^0.22.0
'@astrojs/language-server': ^0.20.0 '@astrojs/language-server': ^0.20.0
'@astrojs/markdown-remark': ^0.12.0 '@astrojs/markdown-remark': ^0.12.0
'@astrojs/prism': 0.6.1 '@astrojs/prism': 0.6.1
@ -526,7 +526,7 @@ importers:
yargs-parser: ^21.0.1 yargs-parser: ^21.0.1
zod: ^3.17.3 zod: ^3.17.3
dependencies: dependencies:
'@astrojs/compiler': 0.21.0 '@astrojs/compiler': 0.22.0
'@astrojs/language-server': 0.20.1 '@astrojs/language-server': 0.20.1
'@astrojs/markdown-remark': link:../markdown/remark '@astrojs/markdown-remark': link:../markdown/remark
'@astrojs/prism': link:../astro-prism '@astrojs/prism': link:../astro-prism
@ -2960,8 +2960,8 @@ packages:
leven: 3.1.0 leven: 3.1.0
dev: true dev: true
/@astrojs/compiler/0.21.0: /@astrojs/compiler/0.22.0:
resolution: {integrity: sha512-g+zkKpTsR0UCDiOAhjv0wQW0cPYd+2Hb5/z+ovIEu7K/v8z2jiQZqvhPvIsjI5ni+5rMFgjjoZWhkMCq+e4bOg==} resolution: {integrity: sha512-TF3zwbPIgr3UPPkVquKUzSGsIqGKh3Gi34Y29+HZvL+YmrkAk+GAuUkOo2EXDJ6aS2Oxq0k7KO/yQ2LjkWl83A==}
dev: false dev: false
/@astrojs/language-server/0.20.1: /@astrojs/language-server/0.20.1: