Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(theming): Theme specific variables must be set on the root node #36462

Closed
wants to merge 1 commit into from

Conversation

susnux
Copy link
Contributor

@susnux susnux commented Jan 31, 2023

Summary

Currently if you use a css variable which links to an other css variable, like --color-main-background and a theme is enabled, the theme is not used for the variable. See linked issue (same e.g. on forms, see nextcloud/forms#1471 (review)).

The problem is the css variable evaluation order, e.g. consider the browser requests dark color theme but the user selected the bright nextcloud theme, then:

  • HTML tag
    • defines --color-main-background for dark color theme (as requested by the browser)
    • defines --table-color-background to be the same as --color-main-background
  • Body tag
    • redefines --color-main-background to match the theme (because data-theme-light is set on the body tag)
  • Table tag
    • Uses --table-color-background which evaluates to HTML-Tag::--color-main-background and in the context it is set to dark instead of bright.

So the solution is to set data-theme-light on the HTML tag rather than the body tag.

Screenshots

System uses dark color theme, but nextcloud is configured to use the bright theme.
You can see the NcSelect has the wrong background color:

before (currently) after (with this PR)
dark background on bright color theme, hard to read correct bright background on bright color theme, good to read

Checklist

@skjnldsv
Copy link
Member

skjnldsv commented Feb 1, 2023

@susnux can you explain what the NcSelect is doing differently that makes our variables behave differently in body than html? 🤔

@susnux
Copy link
Contributor Author

susnux commented Feb 1, 2023

@susnux can you explain what the NcSelect is doing differently that makes our variables behave differently in body than html? 🤔

As explained above it uses variables defined on the root, that evaluate to another variable, see e.g. here.

--vs-search-input-bg: var(--color-main-background); is defined on the root node, so it will not pickup the overridden variable but the default one.
(The value is computed before passing down to the child)

@skjnldsv
Copy link
Member

skjnldsv commented Feb 1, 2023

Ok, let me explain my concerns (not founded/verified yet)

Definition

When loading the page, we load (in order)

  1. the default light theme on :root
  2. the light, dark, highcontrast-light and highcontrast-dark with appropriate media queries
  3. the user defined theme with [data-theme-xxx] attribute on body
    image

The goal

The goal was to ensure we have priorities and fallback. Since body css vars would always be superior to :root this ensure that:

  1. if no user theme is defined (body[data-theme-xxx]), it fallback to any matching media query (prefer-color-scheme or prefers-contrast)
  2. if no media query match, we fallback to the default :root light theme

I'm trying to ensure this doesn't create regressions and trouble the css priority.
I don't have much time to fully review this in depth and testing all uses cases :)

@susnux
Copy link
Contributor Author

susnux commented Feb 1, 2023

The variables from the theme should have precedence over the default ones, because their specificity score should be higher (because of the data tag).

Edit: Well that's not the case, the specificity of :root and [data-...] is equal, so the last one wins.
To prevent regression from loading order the theming css should be :root[data-theme-...].

@skjnldsv
Copy link
Member

skjnldsv commented Feb 1, 2023

To prevent regression from loading order the theming css should be :root[data-theme-...]

No, because that would prevent us from applying themes to other areas of the page (e.g., the Viewer is always in dark mode, whatever theme is currently active)

@susnux susnux force-pushed the fix/theming-variables branch 2 times, most recently from c5e4883 to b2c869a Compare February 1, 2023 10:48
Signed-off-by: Ferdinand Thiessen <rpm@fthiessen.de>
@susnux susnux force-pushed the fix/theming-variables branch from b2c869a to e911a3e Compare February 1, 2023 10:52
@susnux
Copy link
Contributor Author

susnux commented Feb 1, 2023

No, because that would prevent us from applying themes to other areas of the page (e.g., the Viewer is always in dark mode, whatever theme is currently active)

More like :root[data-theme], [data-theme] {...}, this allows to set the theme for different areas while still override the root variables if necessary.

@susnux susnux requested a review from skjnldsv February 1, 2023 10:54
@skjnldsv
Copy link
Member

skjnldsv commented Feb 1, 2023

My spider senses are tingling. We should be very careful with theming now.
Why not fix the vue-select instead?

https://github.com/nextcloud/nextcloud-vue/blob/093ce19071b66b076b975255810f6f1642eaf855/src/components/NcSelect/NcSelect.vue#L907
Use the root selector (.select it seems) of the component instead of :root ?

@susnux
Copy link
Contributor Author

susnux commented Feb 1, 2023

It can be fixed on the NcSelect, especially to fix apps for older nextcloud versions.
But having the theming not overriding the root variables will create a pitfall for app developers as it is quite common to use :root { variables} when defining variables (at least I never saw body { variables} or similar).
Currently I only know of the NcSelect and the text app issue, but I guess more issues like this will appear over time.

@susnux
Copy link
Contributor Author

susnux commented Feb 1, 2023

https://github.com/nextcloud/nextcloud-vue/blob/093ce19071b66b076b975255810f6f1642eaf855/src/components/NcSelect/NcSelect.vue#L907 Use the root selector (.select it seems) of the component instead of :root ?

Some of the variables are for styling the options list, which is not a child of the select but a modal, so styling must be applied to at least body.

@skjnldsv
Copy link
Member

skjnldsv commented Feb 1, 2023

It can be fixed on the NcSelect, especially to fix apps for older nextcloud versions. But having the theming not overriding the root variables will create a pitfall for app developers as it is quite common to use :root { variables} when defining variables (at least I never saw body { variables} or similar). Currently I only know of the NcSelect and the text app issue, but I guess more issues like this will appear over time.

Well, locally scoped variables are much cleaner than everyone putting their variables in the root tbh :/
Also one of the reason we decided to scope all of our css in the vue components

@come-nc come-nc removed their request for review March 14, 2023 16:05
This was referenced May 3, 2023
@blizzz blizzz mentioned this pull request May 17, 2023
@blizzz blizzz modified the milestones: Nextcloud 27, Nextcloud 28 May 23, 2023
@skjnldsv skjnldsv mentioned this pull request Nov 1, 2023
This was referenced Nov 6, 2023
This was referenced Nov 14, 2023
@blizzz blizzz modified the milestones: Nextcloud 28, Nextcloud 29 Nov 23, 2023
@skjnldsv skjnldsv added 2. developing Work in progress and removed 3. to review Waiting for reviews labels Feb 23, 2024
@susnux
Copy link
Contributor Author

susnux commented Feb 26, 2024

I think this is still a thing, maybe not that important anymore but still something we should look into

  • if no user theme is defined (body[data-theme-xxx]), it fallback to any matching media query (prefer-color-scheme or prefers-contrast)

  • if no media query match, we fallback to the default :root light theme

  1. :root[data-theme] has higher priority over :root
  2. media queries do not add specificity meaning, so the media query code must always be included after the :root fallback, then ✅

Also one of the reason we decided to scope all of our css in the vue components

BTW this is one thing we lately have problems with because people think that "scoped" rules are 2-way scoped but that is not the case they still share the class selector meaning two components called foo will share the same :deep(.foo) or global .foo styles which might conflict.
(Only solution for real 2-way scoping is using css modules)

@susnux susnux added 3. to review Waiting for reviews and removed 2. developing Work in progress labels Feb 26, 2024
This was referenced Mar 12, 2024
@skjnldsv skjnldsv added 2. developing Work in progress and removed 3. to review Waiting for reviews labels Mar 15, 2024
@skjnldsv skjnldsv modified the milestones: Nextcloud 29, Nextcloud 30 Mar 15, 2024
@susnux
Copy link
Contributor Author

susnux commented May 31, 2024

I think we can close this

@susnux susnux closed this May 31, 2024
@susnux susnux deleted the fix/theming-variables branch May 31, 2024 16:10
@skjnldsv skjnldsv removed this from the Nextcloud 30 milestone Aug 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Scoping issue when overriding CSS variables for user-themes Black table on light theme
4 participants