SPFX - SCSS modules, support for CSS @Container queries
What type of issue is this?
Question
What SharePoint development model, framework, SDK or API is this about?
💥 SharePoint Framework
Target SharePoint environment
SharePoint Online
What browser(s) / client(s) have you tested
- [ ] 💥 Internet Explorer
- [X] 💥 Microsoft Edge
- [X] 💥 Google Chrome
- [ ] 💥 FireFox
- [ ] 💥 Safari
- [ ] mobile (iOS/iPadOS)
- [ ] mobile (Android)
- [ ] not applicable
- [ ] other (enter in the "Additional environment details" area below)
Issue description
I noticed that when compiling .scss modules for an SPFX, CSS container queries are not supported. Since webparts can end up being inserted in to a variety of different container widths, depending on the section layout - it would be really useful to be able to use container queries (which use the parent element width/height as a trigger for CSS styling). My work around at the moment is to include a standard CSS file with the styling that benefits from container queries, and use a unique CSS classname in my SPFX. However, it would be better if you could use these queries in compiled SCSS modules.
Is there a way of doing this?
Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible.
This one can be added to a list of problems:
- @Layered styles: #8725
- Brocken SASS implementation: #8916
Let's talk about container queries for a moment. While they might seem super fancy, they could work better with SharePoint. SharePoint has a 12-grid layout, which is documented here: https://learn.microsoft.com/en-us/sharepoint/dev/design/grid-and-responsive-design
Under the Hood, they use:
- .CanvasSection-xl12 - 12 columns
- .CanvasSection-xl8 - 8 columns
- .CanvasSection-xl6 - 6 columns
- .CanvasSection-xl4 - 4 columns
- .CanvasVerticalSection - Vertical Section
The last vertical section is out of the grid and needs to be added to the documentation.
To make the container query work - you could rely on min-width width of all sorts, but you still don't know the container you are in. If you tend to define container-name as well as container-type then every web part would overwrite each of the values newly with every new webpart, despite for the columns you need to change the out of the box CSS styles, which is not supported nor recommended. If container-name ever has to come from Microsoft, it needs to be documented for us to save to use it.
The other option would be chasing down pixel value for the outer container, which doesn't indicate how many grid columns your web part can populate. Also, you do not know if you may be on four grid columns on a tablet or 12 grid on a desktop. Neither will it be safe when Microsoft changes pixel values only by a bit because your breakpoints may not match.
Container queries in this context are a fragile construct. So the webpart might work today but not tomorrow suddenly out of the blue anymore.
So the safer way is to work with the SharePoint given grid system and not against it as described here - https://n8d.at/how-to-make-your-web-parts-responsive-to-the-parent-container.
Those grid columns are defined and documented, and maybe, in future, we can use something like CSS Subgrid.
We are currently on the sass 1.44, which should already support @ container queries, but those will likely be lost along the way, presumably in postCSS and CSS module compilation.
Would it be great to have it in future - I need to find out where SharePoint and the page designs are heading, so the customisations might break. Also, we need more documentation from Microsoft on the page side of things before we can fully leverage container queries.
What's good for early adoption might not be good for production.
@nick-pape any news or workaround not that?
I found the reason why container queries along side with so many other browser supported web standard do not work.
[email protected] which the SASS SPFx build task uses was released almost 6 years ago and does a decent job by 6 year old standard, by removing all it is unaware of. Such as @layer and @container CSS options.
However a there is a workaround that get offered by the build change and clean-css. It is to disable it completely. The negative impact is that is doesn't do it's magic anymore, while allowing to write web standard and widely browser supported CSS.
Another interesting fact that sp-build-core tasks got already update. Not so the @microsoft/[email protected] package.
The workaround
Like I said the workaround is to disable it completely.
build.sass.setConfig({
dropCssFiles: true,
useCSSModules: true,
warnOnNonCSSModules: false,
cleanCssOptions: {
level: 0,
compatibility: {
colors: {
hexAlpha: false, // controls 4- and 8-character hex color support
opacity: true // controls `rgba()` / `hsla()` color support
}
}
, returnPromise: true
},
autoprefixerOptions: { overrideBrowserslist: ["> 1%", "last 2 versions", "not dead"] }
});
With these options inserted into the gulpfile.js.
cleanCssOptions: {
level: 0,
compatibility: {
colors: {
hexAlpha: false, // controls 4- and 8-character hex color support
opacity: true // controls `rgba()` / `hsla()` color support
}
}
, returnPromise: true
}
Clean CSS Level 0 disable clean-css entirely, not optimal but even better than use this outdate version.
In addition to the autoprefixerOptions:
{
autoprefixerOptions: { overrideBrowserslist: ["> 1%", "last 2 versions", "not dead"] }
}
These options finally remove the support for IE10+ making the CSS by itself more cleaner.
I really hope that we will see these enhancements in the 1.20.0 version of the generator.
@nick-pape @AJIXuMuK @stevesuk
PS: There are in addition to this other bug in the CSS compilation that causes other issues too.
Hello @StfBauer ,
I tried the workaround with no success on the container queries. Do we have an update when this will be officially supported natively by SPFx? We currently use a bunch of media queries like the suggestions in your article for the webpart to know where it is. But I feel this creates a lot more overhead when trying to make things responsive and having to change layouts in multiple locations in your css.
(the attachment below is the same webpart just placed in different placeholders)
Our workaround is to reference a standard CSS file in the project, which we use only for the elements that require a Container query. All the other styling in the project stays within SCSS modules. In the CSS file, we reference the elements we wish to apply Container sizing to by ID - so as not to conflict with the class names generated from the SCSS modules.
It would be great to be able to manage the whole process in SCSS - but our current work-around is OK until the framework is updated.
@tymvios This can be accomplished with using :global and :local statements and use the official CSS classes provided by Microsoft. I wrote a blog post a long time ago and still works today. https://n8d.at/how-to-make-your-web-parts-responsive-to-the-parent-container
Meanwhile I create a SASS Mixin that has all the media queries include too.
You design is fairly easy to accomplish without container queries.
@stevesuk Worked for me without any problem - meanwhile I have a complete blog post out. https://n8d.at/how-to-implement-contemporary-css-in-sharepoint-framework
One thing I had to do is to write SASS in the form of:
@charset "utf-8";
.helloworldcontainer {
display: flex;
container-type: inline-size;
container-name: helloworld;
@container helloworld (width > 300px) {
.helloworld {
background-color: green;
}
}
}
.helloworld {
background-color: lime;
}
When I moved the @container out of the class it haven't worked. With this approach the compiled CSS looked like this:
.helloworldcontainer_2e4f0223 {
display: flex;
container-type: inline-size;
container-name: helloworld
}
@container helloworld (width > 300px) {
.helloworldcontainer_2e4f0223 .helloworld_2e4f0223 {
background-color: green
}
}
.helloworld_2e4f0223 {
background-color: lime
}
With that I was able to successfully apply it to one of my customer projects.
@tymvios You will find the mixin here: https://github.com/pnp/custom-learning-office-365/blob/65c95835c6fab42455649e1dcd4694e9de46d82f/src/webpart/src/webparts/common/_rwd-opt.scss
@nick-pape a new version of clean CSS would be nice too ;) https://n8d.at/how-to-implement-contemporary-css-in-sharepoint-framework
In addition what I recognise is that the build, when media or container query is at the end of the CSS file the last } gets stripped out.
@stevesuk, Just checking in to see if the issue with SCSS modules and @container queries has been resolved on your end, or if you're still facing challenges.
Please let us know if the provided workaround helped or if you need any further assistance.
@Ashlesha-MSFT In the current version, there are still challenges because the CSS pipeline, even with overrides, is a general issue. I'd like to give you a short example.
Code like this is a valid SASS File:
$color-blue: #318eb1;
$color-red: #cc2741;
$color-pink: #da3280;
$color-green: #a7bb38;
$color-yellow: #eeb405;
.outerContainer{
container-type: inline-size;
}
.containerQuery {
display: grid;
// Full width section
@container (width >= 1205px) {
background-color: $color-blue;
grid-template-columns: repeat(12, 1fr);
}
// One column section
@container (width < 1205px){
background-color: $color-red;
grid-template-columns: repeat(12, 1fr);
}
// 2/3 section
@container (width < 793px){
background-color: $color-pink;
grid-template-columns: repeat(6, 1fr);
}
// two column section
@container (width < 587px) {
background-color: $color-green;
grid-template-columns: repeat(4, 1fr);
}
// three column section
@container (width < 476px) {
background-color: $color-yellow;
grid-template-columns: repeat(6, 1fr);
}
}
However, it comes up with the following error message:
[16:52:48] Error - [webpack] 'dist':
./lib/webparts/containerQuery/ContainerQueryWebPart.module.css: Module build failed (from ./node_modules/@microsoft/sp-css-loader/lib-commonjs/index.js):
CssSyntaxError
(11:0) Unclosed block
This is because the end of the CSS file got trimmed and resulted in the following file.
.outerContainer_ec0433ca {
container-type: inline-size
}
.containerQuery_ec0433ca {
display: grid
}
@container (width >=1205px) {
.containerQuery_ec0433ca {
background-color: #318eb1;
grid-template-columns: repeat(12, 1fr)
}
}
@container (width < 1205px) {
.containerQuery_ec0433ca {
background-color: #cc2741;
grid-template-columns: repeat(12, 1fr)
}
}
@container (width < 793px) {
.containerQuery_ec0433ca {
background-color: #da3280;
grid-template-columns: repeat(6, 1fr)
}
}
@container (width < 587px) {
.containerQuery_ec0433ca {
background-color: #a7bb38;
grid-template-columns: repeat(4, 1fr)
}
}
@container (width < 476px) {
.containerQuery_ec0433ca {
background-color: #eeb405;
grid-template-columns: repeat(6, 1fr)
}
// Missing curly bracket at the end }
So it still does not function correctly.
Workaround is to add after the very last CSS and additional code block like this:
.containerQuery {
display: grid;
//...
// three column section
@container (width < 476px) {
background-color: $color-yellow;
grid-template-columns: repeat(6, 1fr);
}
}
.test{
content: "hello world";
}
This unused or maybe used block ensures that the last curly bracket does not get cut off, and the CSS is correctly rendered.
In addition, the clean-css version 4.2.1, which is still used in SPFx, is already 7 years old. It should be updated or removed: For now, we can just disable it by updating the gulp build chain to this:
build.sass.setConfig({
cleanCssOptions: { level: 0 },
autoprefixerOptions: {
overrideBrowserslist: ["> 1%", "last 2 versions", "not dead"]
}
})
Apologies for the delayed response, and thank you for the detailed updates and insights.
We were able to successfully reproduce the issue — the container-type style is applied correctly, but the @container query blocks are stripped out during SCSS module compilation in SPFx.
We've logged this internally as a bug, and our engineering team is actively investigating it. In the meantime, we appreciate the suggested workarounds (such as using plain CSS files), and we’ll explore those options where appropriate.
Thank you again for your continued support and contribution to improving the SPFx development experience.
Well, it is not about the plain file; it is more about the plain placeholder CSS that comes after a container block.
@StfBauer, Based on my testing, even with valid SCSS module code using @container queries, the styles do not apply in the running SPFx web part. It appears that the container query rules are stripped or ignored by the current SPFx build pipeline, likely due to the outdated clean-css version and related post-processing steps.
If you have a working SPFx solution, I’d be happy to test it and share the results with the engineering team for further investigation and potential fixes.
@Ashlesha-MSFT the working solution is provided above.
Step 1: Update gulp file and disable cleanCSS - since the current version is 7 years old.
build.sass.setConfig({
cleanCssOptions: { level: 0 },
autoprefixerOptions: {
overrideBrowserslist: ["> 1%", "last 2 versions", "not dead"]
}
})
Step 2: Add a CSS to the following CSS inside the main webpart outer container
// webpart css class
.containerQuery {
display: grid;
//...
// three column section
@container (width < 476px) {
background-color: $color-yellow;
grid-template-columns: repeat(6, 1fr);
}
}
.test{
content: "hello world";
}
Step 3:
Check the output in the lib folder and check if the @container query is present.
I work with this not only in Demo project but also customer facing project.