-
Notifications
You must be signed in to change notification settings - Fork 10k
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
CSS Isolation in Blazor Components #10170
Comments
IMO, CSS selector already provide enough complexity with selectors so you don't need this kind of feature. And this adds coupling between the framework, the css extension you choose (less, sass) and the css building tool you choose (webpack). An external project might be a better fit as every Blazor user won't get all the dependencies this feature needs. |
@RemiBou I totally disagree. Using CSS without this feature is like writing code without namespaces. Sure, I can write super long and specific class names in code and not use namespaces, but that is an awful way to work. CSS Isolation is something that once you use it, like namespaces, you never want to go back to not using it. I think this is a feature that would be a great addition. |
@RemiBou yeah with CSS there's a lot you can do for sure but what we're referring to here is really support of Shadow DOM from the Web Components specification (https://www.w3.org/TR/css-scoping-1/#shadow-dom). It would be awesome to see these standards baked into the framework itself with the ability to toggle it on or off if you didn't want to use it. |
I am sure it will be good what you offer but for now I build dynamic css and load it as part of blazor component so I don't need any isolation because css is constructed for particular component and loaded/unloaded with component. Here is POC repo which is not updated to latest version I use in my blazor virtual grid. |
@Lupusa87 unfortunately, that doesn;t provide CSS Isolation. That means you still get CSS bleed and all the other issues of Global Scoped CSS. |
I use CSS grids to define my pages' layouts. Each page or component will have a different css grid layout, which will also be responsive. CSS isolation is important for this use case to prevent me from having to guarantee each style has an application-wide unique name. |
I agree with this request. I convert an Angular app to Blazor and missed this feature. Thank you for considering adding the opt-in capability. |
Here is a workaround https://github.com/alexandrereyes/BlazorScopedCss |
why not use the style we already have, for example add the In 1 file
<h1>My Component/h1>
@code{
// code goes here
}
@css{
// scoped css
) In multi files
|
@vertonghenb I totally love it!
So you could add the scoped javascript code as well. This should then be packed into the javascript that is loaded from blazor and should be accessible through JSInterop. |
Without CSS Isolation, the css of different UI libraries will easily conflict each other. I always spent lots of time to fix the css conflict when develop the asp.net mvc applications. Please support it. |
Well I'd suggest to use css and js isolation.
It should add some hashes or whatnot of the component itself to the classes and functions. With this, no css and js libraries would collide. And as an addition: it would be nice to actually use the templating language (i.e. razor and the c# compiler) in css and js. For example if we have a design system in place: // Colors.cs
static class Colors {
public static readonly string White = "#fff";
}
// MyComponent.razor
<div class="foobar"></div>
@css {
.foobar {
background-color: {Colors.White};
}
} Maybe this could be compiled and the values of the class properties are compiled into the css of the component? With this, the values don't have to be repeated everytime. And then there could be LESS / SASS? :-) |
+1 for this feature and all other features that make the design story as good as React/Vue/Angular. |
My preferred JS library for CSS in JS is JSS. <Styled @bind-Classname="@example1">
background-color: hotpink;
</Styled>
<div class="@example1">The background of this div is hotpink</div>
@code {
private string example1;
} Even JS doesn't really do CSS isolation without interacting with a library - which is probably a good thing since you can control which plugins and features you want to have. But, it would be nice to have CSS syntax highlighting and intellisense available - perhaps hinted with Attributes - within Styled tags in libraries like Blazor Styled |
If the "css" also allows to "import url('sample01.css')", sure, I upvote. Same for "jss". The worthy functionality is "isolation of assets that affect only that component". +1 with @JustinCouto . This functionality could/should be optional. A razor component is meant to be re-usable, and in my tests, @zzg890 issues are similar to mine, I always get conflicts and waste time. This could allow us to simply call the razor component, from a RCL for example, and be sure that component will render properly, and will not be affected by other styles, of the main site/project. |
+1 @buehler This could possibly remove the node.js dependency that you'd mostly need if you need a css preprocessors while benefiting from being strongly typed. This is somewhat similar to how React inline styles work, with styles being an object (class in C#'s case) and exposes properties in one place and possibly compose them using existing .net classes that already does this (e.g. // App Themes.cs
public static class ThemeColors
{
public static Color Primary = Color.Blue;
}
// SomeComponent.razor
@css {
.transparent-blue { color: Color.FromArgb(0.5, ThemeColors.Primary) }
}
<button class="transparent-blue"> Transparent primary button </button> |
I think it would be more beneficial to make it straightforward to use custom elements as they have CSS isolation and it's baked into them and otherwise have the case to be just like it is currently, "random fragments". This way Blazor can be used to author web components and be useable with web components authored elsewhere in a platform compatible way. Though if thinking CSS isolation explicitly, a good integration with Web APIs and in this case up and coming feature such as Constructable Stylesheets would be nice. It looks, though that if one does something like web components already, this is either a prerequisite or follows from it (depending on which features one schedules first). Something to think with Shadow DOM styles. Related: #6218. Maybe worth pointing ount the SPA frameworks are also moving towards custom elements (and web components) and that one should be able to build PWAs without SPAs. |
I'm having a similar issue presently while working on nested components but with style isolation. it seems https://blazorstyled.io is the only option to make this work for now. But for Blazor to win the heart of many, it should have a baked in support for style isolation as it holds in major SPA frameworks. |
I think there should be a way to do CSS isolation in Blazor, but I'm not sure about the idea of baking anything into the core of Blazor @huzaynbolt - The other main SPA frameworks don't do this. They, like Blazor work with the DOM. Which for styling purposes, includes setting inline-styles and class names on DOM elements. (which razor syntax already does just fine). The actual styles that get applied by the browser to a DOM element based on CSS selectors can come from style tags, css files etc. The razor syntax can already achieve the same level of inline styling as React for example: <div style="background: @Model.Bg">...</div> <div style={{ background: bg }}>...</div> There's loads of different ways of achieving CSS isolation (shadow DOM, JSS style injection, etc) and I don't think Blazor users should be stuck with one baked in one. |
@saborrie I agree somewhat now thinking it through. It shouldn't be a core Blazor feature since CSS a web construct while Blazor (or razor components) should be agnostic to these concepts since on other areas CSS doesn't apply. E.g. Android / iOS / Desktop for Blazor Native applications. Maybe a better way is at least having an integration point on Razor components for other build-time tools to participate on the compilation process, being able to read attribute values or something similar without having to do Regex text parsing on the |
After posting this request months ago and following the responses, I feel that some people responding might not use CSS Isolation in large SPA applications and that they may be underestimating the need for this feature. To me, it doesn't matter if this is a core automatic feature or a separate library that you must include to get the feature, but I believe it is still core to building SPA apps using HTML/CSS as the view layer. Being able to isolate the CSS for an individual component knowing with certainty there will be no CSS bleed or naming collision/accidental overrides is critical. The simplicity of being able to have a style called .item in many components at any level in your application is extremely freeing and useful. You can actually name your styles for what they are not worrying about how those names are impacting the rest of your application. This feature dramatically reduces accidental global cascading issues that developers have been dealing with for years. The global nature of CSS has always been problematic. Is global CSS still needed? Yes. However, like anything global, it should be used sparingly. Here is the approach that is used in Angular: Three Modes of Component EncapsulationDevelopers who use component-scoped CSS in Angular will default to emulated mode for this encapsulation. In emulated mode, we generate and attach random attributes to each instantiated component, and then create styles that use those generated attributes as selectors. We also support Native mode, which will use Shadow DOM to create additional contexts and prevent cross-component leakage of styles. This will work in any browsers with support for Shadow DOM v1. Native mode creates a shadow root under each component, which will isolate the component completely, even from styles defined globally (global styles DO pierce components with emulated view encapsulation). The third and last encapsulation you can choose is None, which means that all of your CSS ends up being globally applied. You can use this if you want to opt-out of Angular’s style encapsulation completely. We have been using Angular for years and our team is simply not going to be willing to move to something that doesn't have a way of doing this. It is one of our favorite features and it helps to raise the quality level of our applications. It's one of those things that you simply don't realize the power of until you have leveraged it in a large application in a major way. It is a once you try it, you could never go back kind of things. Hopefully, there will be a way to do this in blazer. I think it is critical enough that it should be part of the core framework even if you have to include it separately |
By referring to other SPA frameworks doing it, I am not deliberating on the underlying functionality used but the syntactic sugar that came out of the box that makes it easy to work with. This is a sample style block in a Vuejs component that makes it easier to work with isolated styles. N.B: All CSS styles are all isolated to the component hence reducing style conflicts |
dotnet/AspNetCore.Docs#19360 Docs are coming |
Hello again, First request I have regarding this, is that please make it more flexible regarding simplified names, or some custom rules probably via some custom folders. Second request or question is that, can we pass/reference a whole Scss library located in an assembly in another assembly (consumer) and read/reference those Scss defined classes/variables without the need of copying all those Scss files from the source library to any consumer libraries/applications? Thanks. |
You can have your own convention to do this, you'll need to define an MSBuild ItemGroup for it, but that's it.
We don't embed anything into the assembly, the outputs are just static web assets that get bundled into nuget packages. You can choose to bundle your scss files in any package you are building and use those with your SASS compiler, but you'll have to do that yourself through MSBuild. The only thing that we do across packages is bundle css in the host project/wasm app project. |
The platform I built is doing these tasks, the problem about it as I mentioned earlier is all those SCSS files would be copied into every consumer project, which it could be better if we could use them like a shortcut/reference. |
I'm not sure what that means. Static web assets are not copied during development and are only copied during publish, if you are using SASS you can get the list of paths you care about and pass them to the SASS compiler as load paths, and that shouldn't involve any copying. At the time you detect and collect your SASS files you can remove them from the static web assets item group and that would prevent any copying during publish. You'll have to write some MSBuild, but I do believe this is doable. |
My platform copies the referenced Sass files via MSBuild, currently don't know how practically I can get the list of paths and pass them to the SASS compiler while they are placed in some referenced packages, guess need to read the packages and then make sure the compiler can find them. Seems I need to play more with it, learn more about SASS compilation and the scenario I am trying. Thanks for the answer. |
I am curious to know if the team had any thoughts or discussions on how the dev inner loop might later be improved here, i.e making a css change, waiting 10 seconds for a rebuild / compile, and then f5 refresh of the browser isn't the best it could be productivity-wise, where minor css tweaks are concerned, and that was my only concern right now really. Tied into this, perhaps you might not want to pay the added build cost of bundling all the assets into a single output file on every build, but only want to do that for a release build? Lastly, perhaps I want to add my own CSS and JS files alongside each component, but I don't want blazor (msbuild) to process them at all - say I'd prefer to use rollup etc - is there going to be an easy way to "Opt" files out of the blazor msbuild logic, but still keep them in the same folder structure (alongside the component.razor file), should I wish to do so? |
As a separate work item, we're working on improving the inner-loop dev experience, e.g., minimizing the time between code changes and seeing the updates in your browser. If we can make this sufficiently fast then hopefully it's not relevant to do anything special for CSS, since all changes would go through quickly enough.
Combining the files will only take the tiniest fraction of a second, so I don't think it's desirable to go through a completely different loading process in development (risking bugs that only occur in prod) to skip that. The real cost of a rebuild is the aggregation over everything that the build process does.
Yes, there's an MSBuild property to disable the bundling. If you enable this, it makes it your responsibility to take the scoped CSS files from the |
Thanks @SteveSandersonMS that sounds good.
Could / will this process include the production of a source map, so that when debugging, we can still refer back to the original individual files? When a bug occurs (or when inspecting css), the source map is going to allow us to see which exact file in the project the problem stems from, which is massively helpful! |
Yes, our design includes allowing for that. However we're not implementing source maps for bundled CSS in .NET 5 due to time constraints. We think relatively few people depend on source maps for CSS compared with source maps for JavaScript. If you're keen, we'd be interested in taking a PR that adds support for generating source maps. Until then, the bundled CSS contains generated comments that tell you which file each part of the CSS comes from. I know it's not as slick as a source map but it's one step on the process. |
Has there been documentation written on this yet? |
|
bUnit needs to identify attributes added to the render tree by Blazor (attributes to HTML elements). For scoped css, the Is this always the case? I.e. can I detect the scoped css attributes in the DOM by checking if an attribute starts with |
When the Razor SDK chooses scope identifiers for
This would then emit the attribute There's no particular reason why someone would want to do this unless they are really customizing how the CSS scoping works in some advanced way. However if someone does want to do that, we let them do so. My guess is that bUnit doesn't need to be concerned about custom CSS scoping attributes. If a developer is doing something to create their own attribute names, then it makes sense for bUnit to treat them like any other attribute, and developers would have to specify their custom attribute names directly in their tests for them to pass. |
Indeed. That has been my design philosophy. Anything devs add to their components and thus expect to see in the output should be part of the semantic comparison done by bUnit. Thanks for making this clear. |
would it be possible to have support for the |
@qin-guan Could you please open a separate issue with this feature request and some more details about what you're trying to accomplish? We don't support Razor syntax in CSS files today, but maybe there is a different way to accomplish what you want. |
Also please note that it's not our goal to recreate the functionality you'd get from a CSS preprocessor such as Less or Sass. If you want those features, we recommend you use Less/Sass to generate your |
@danroth27, @SteveSandersonMS I believe @qin-guan wants to have runtime support for variables in CSS files. h1
{
color: @MyH1Color;
} Razor file: <h1>Very important header</h1> code
{
string MyH1Color = "blue";
// some code to change MyH1Color to "red"
} |
OK, thanks for clarifying. That's not something we expect to do, as it's substantially outside the normal ways of implementing styling. In the rare case where something like this would be needed, I'd recommend just using a <h1 style="color: @MyH1Color">Hello</h1> Another way you could do this (if you need to affect lots of elements at once) is by declaring a CSS variable in your h1 {
color: var(--my-h1-color);
} ... and then using JS interop to update the variable value: js.InvokeVoidAsync("document.documentElement.style.setProperty", "--my-h1-color", MyH1Color); The suggestion of dynamically rendering CSS stylesheets using Razor syntax would most likely not perform well as the browser would have to recompute styles for every element each time the stylesheet is dynamically replaced. |
I have just returned to this thread to write about CSS variables and it looks that it is to late. You have been faster. Thank you @SteveSandersonMS and all guys from ASP.NET team for your hard work. |
@qin-guan If you are looking for the ability to modify styles at runtime based on variables and don't want to use inline styles, perhaps using an external library such as https://blazorstyled.io/ would be more appropriate. |
@SteveSandersonMS the style attribute is what i'm currently doing to style my components, but it gets quite messy with increasing number of styles, and styles for |
@qin-guan My understanding is that there are generally two types of styling approaches to take.
With the built in "static" styles approach, you could generate multiple classes and switch between them using a variable giving the component a "variable" style. Anything beyond this will require third party library support. In the case of https://blazorstyled.io/, the styles are processed and cached and end up as classes that you apply to your components. It is based on the very popular https://styled-components.com/ for React. There are a lot of people who disagree on what the "right" way is, so I don't believe this is something that a framework should enforce. For example, in React there is no concept of "dynamic" styles (outside of using the As it stands, I believe there are a decent amount of options to choose from and no need for additional options to be baked it. If anything the thing that is lacking is the tooling support for third party DSL's in the Razor LSP, but that is a completely different topic :) |
@ChristopherHaws i see, i think BlazorStyled would work for my use case, thanks :) |
Is it possible to run the preprocessor and bundler without using MSBuild to build the whole project? I'm trying to implement hot-reload for scoped CSS, but it seems like all the code is in the build tasks. |
@ionoy It's implemented as some MSBuild tasks, and you can tell MSBuild to run certain specific tasks without the rest of the build pipeline if you want. For example, We don't specifically document which MSBuild tasks are used internally within the build pipeline for CSS isolation. If you read the sources you could figure it out, but note that these are implementation details that are subject to change in the future. CC @javiercn in case you think it's applicable to document what's needed to do this. |
@SteveSandersonMS Thank you for the suggestion! I'll give it a try, I think this solution should do nicely. |
First of all, we love Blazor!
The only thing keeping us from moving to Blazor as our core front-end technology is the lack of CSS Isolation in Blazor Components. We currently use Angular and it has awesome support for CSS Isolation. This feature has changed the way we develop UI and we could never go back to not having it. We like the unopinionated approach you are taking with Blazor, but this is a feature we believe is essential and worth adding. We don't believe you need to have full web component support, but we do believe having the ability to turn on CSS Isolation at a component level or in an entire project would be an amazing addition that would enable better apps, app management, and a nicer experience for developers. Please add this feature.
@danroth27 @shanselman @SteveSandersonMS
The text was updated successfully, but these errors were encountered: