-
-
Notifications
You must be signed in to change notification settings - Fork 844
Move Tailwind's important rules to a layer before Quasar to make sure they win #5170
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
Conversation
Interesting approach, @evnchn! It feels a bit sketchy to tear apart Tailwind CSS rules, but it's certainly better then what we tried before. I'm a bit concerned about the performance implications of observing and re-processing the document head. That's why I tried moving Quasar rules instead (they don't change). It took me quite a while, but this seems to do the job: @layer theme, base, quasar, nicegui, components, utilities, overrides, quasar_importants;
...
@layer quasar_importants {
/* Do not remove this layer, it is used in the JS to move !important rules from the "quasar" layer here */
} const rules = Array.from(document.styleSheets[0].cssRules);
const source = rules.find((r) => r.layerName === "quasar").styleSheet;
const target = rules.find((r) => r.name === "quasar_importants");
for (let i = source.cssRules.length - 1; i >= 0; i--) {
const rule = source.cssRules[i];
if (rule instanceof CSSStyleRule && /!important/.test(rule.cssText)) {
source.deleteRule(i);
target.insertRule(rule.cssText);
}
} It just bugs me that this snippet randomly jumps between taking 4ms and 800ms. Still investigating... |
Here we go: const rootSheet = document.styleSheets[0];
const rules = Array.from(rootSheet.cssRules);
const source = rules.find((r) => r.layerName === "quasar").styleSheet;
const target = rules.find((r) => r.name === "quasar_importants");
rootSheet.ownerNode.disabled = true;
for (let i = source.cssRules.length - 1; i >= 0; i--) {
const rule = source.cssRules[i];
if (rule instanceof CSSStyleRule && /!important/.test(rule.cssText)) {
source.deleteRule(i);
target.insertRule(rule.cssText);
}
}
rootSheet.ownerNode.disabled = false; Now it always takes around 5ms. The trick is to avoid re-rendering while working on the CSS sheet. |
@falkoschindler Awesome idea to move Quasar's importants to a less-important layer than to move Tailwind's importants to a more-important layer (considering importance after But why do it in the browser? Can't we have:
Assuming you have created the |
@evnchn Good idea! It was easier to do it in JS in the browser, but it should be possible as a preprocessing step, ideally in extract_core_libraries.py. |
Heck, I even think that the segregation of important and no-important styles can be officially in Quasar, offering advanced technical people (like us, integrating Quasar into NiceGUI) the flexibility, while everybody else can just import 2 stylesheets / 1 combined stylesheet and get along with their normal usage. Can propose later if it works here, I guess |
Not sure if they like it, but worth a try. Two caveats with the current implementation:
|
from nicegui import ui
@ui.page('/')
def page():
ui.label('This text is always visible')
# Quasar: print-only is hidden on screen, visible on print
ui.label('print-only').classes('print-only')
# Test if user's custom important CSS can override Quasar's print-only class
ui.add_css('''
@layer utilities {
@media screen {
.print-only {
display: block !important;
}
}
}''')
ui.run(show=False, port=9999) |
Let's close this PR in favor of PR #5171. |
### Motivation Fix #5156, in which we see that Tailwind always loses in the CSS importance battle if Tailwind's layer is higher than Quasar. - Tailwind loses to Quasar's `!important` if Tailwind isn't begin with `!` - Tailwind still loses to Quasar since layer order is reversed if both rules are `!important` That's no good. In addition, testing at #5156 (comment) reveals the new behaviour diverges from the old, which is not what we want either. We did try #5166, that didn't work (NiceGUI-native documentation site is broken), while #5167 also didn't work (Quasar-native documentation site shall be broken). #5170 we're almost there but as said in #5170 (comment) we should instead segregate the Quasar styles in the server side Python pre-comute. **Real motivation: Want 3.0 ASAP** **Real motivation 2: Check the pipeline results to see if this broke anything** **Real motivation 3: I look like a 🤡 in #5166** **Real motivation 4: #5170 is not adopted due to frequent updates on head** ### Implementation `quasar_segregator.py` creates the 3 CSS files. ### Progress - [x] I chose a meaningful title that completes the sentence: "If applied, this PR will..." - [x] The implementation is complete. - [x] Separate the mixed ones. I've been stuck for a while - [x] Modify the `index.html` to serve these segregated styles - [x] Minify with `rcssmin` - [x] Beautify with `cssbeautifier` - [x] Document pip install commands - [x] Pytests have been added (or are not necessary). - Again I'm considering it. - [x] Documentation has been added (or is not necessary). - We should probably also document this somewhere just for avoid confusion down the line. - [x] fix comments being moved to wrong code block - [x] integrate with extract_core_libraries.py - [x] add new dev dependencies to pyproject.toml --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Falko Schindler <falko@zauberzeug.com>
Motivation
Fix #5156, in which we see that Tailwind always loses in the CSS importance battle if Tailwind's layer is higher than Quasar.
!important
if Tailwind isn't begin with!
!important
That's no good. In addition, testing at #5156 (comment) reveals the new behaviour diverges from the old, which is not what we want either.
We did try #5166, that didn't work (NiceGUI-native documentation site is broken), while #5167 also didn't work (Quasar-native documentation site shall be broken)
Real motivation: Want 3.0 ASAP
Real motivation 2: Check the pipeline results to see if this broke anything
Real motivation 3: I look like a 🤡 in #5166
Implementation
tailwind_importants
layer before all layers, normally empty and does not affect page operationmoveRules
to be ran, if we detect any changes in<head>
moveRules
to move all!important
rules from Tailwind away fromutilities
intotailwind_importants
so that accounting for the inverse of layer priority, Tailwind wins.Progress
Comprehensive test script
Combines #5156 (comment) and #5167 (comment)
Results
Documentation page screenshot
Additional notes
The value of UnoCSS (#4832) is that we can potentially do the same without the MutationObserver.