It is in my understanding that the <style jsx> tag contains an interpolated string in order allow insertion of variables that can be stored and manipulated in javascript as in the following example:
const color = 'red';
return (<div>
<p>Hello</p>
<style jsx>
{`
p {
color: ${color};
}
`}
</style>
</div>);
I am trying to use the previous mechanism to encapsulate the media queries that I use in a single location:
const mediaQueries = {
mobile: '@ media screen and (max-width: 320 px)',
...
};
But when I try to use them as follows:
return (<div>
<p>Hello</p>
<style jsx>
{`
${mediaQueries.mobile} {
p {
color: ${color};
}
}
`}
</style>
</div>);
I get the following error:
Module build failed: Error: /absolute_path/MediaQueryIssueExample/pages/index.js?entry: Nesting detected at 9:21. Unfortunately nesting is not supported by styled-jsx.
at Function.disableNestingPlugin (/absolute_path/MediaQueryIssueExample/node_modules/styled-jsx/dist/lib/style-transform.js:22:13)
at proxy (/absolute_path/MediaQueryIssueExample/node_modules/stylis/stylis.js:1311:30)
at compile (/absolute_path/MediaQueryIssueExample/node_modules/stylis/stylis.js:804:14)
at compile (/absolute_path/MediaQueryIssueExample/node_modules/stylis/stylis.js:366:17)
at compile (/absolute_path/MediaQueryIssueExample/node_modules/stylis/stylis.js:366:17)
at stylis (/absolute_path/MediaQueryIssueExample/node_modules/stylis/stylis.js:1458:16)
at transform (/absolute_path/MediaQueryIssueExample/node_modules/styled-jsx/dist/lib/style-transform.js:120:3)
at processCss (/absolute_path/MediaQueryIssueExample/node_modules/styled-jsx/dist/_utils.js:461:65)
at PluginPass.exit (/absolute_path/MediaQueryIssueExample/node_modules/styled-jsx/dist/babel.js:232:51)
at newFn (/absolute_path/MediaQueryIssueExample/node_modules/babel-traverse/lib/visitors.js:276:21)
The MediaQueryIssue repository contains a minimalistic example that demonstrates the issue.
The error message indicates that nested styling as been detected, this seems odd since I did use only one <style jsx> elements inside the rendered structure of the previous example.
One of the advantages of using styled jsx is the ability to substitute values that can be manipulated in JavaScript in order to kill as much duplication as possible, unfortunately the fact that it is impossible to substitute media queries limits this advantage greatly.
I suspect that this might be a styled jsx specific issue but I am not sure yet and I thought it would better to start the discussion here.
Pointers to where to debug are welcome and I would be glad to contribute fixes if possible.
Try adding support for nesting via PostCSS. A simple solucion could be modify your package.json to something like:
{
"name": "MediaQueryIssue",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "^4.1.0",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"postcss-nested": "2.1.2",
"styled-jsx-plugin-postcss": "0.1.0"
},
"postcss": {
"plugins": {
"postcss-nested": {}
}
}
}
And add a .babelrc
{
"presets": [
[
"next/babel",
{
"styled-jsx": {
"plugins": [
"styled-jsx-plugin-postcss"
]
}
}
]
]
}
This should work :)
@MFCo thank you for your suggestion.
Unfortunately, the error is gone but the media query has no effect.
I created the .babelrc and modified package.json as you indicated, I also made sure to run npm install.
As I mentioned the nesting error is gone, the page loads properly but when I switch to the mobile view nothing changes as if there where no media query.
Here is a chunk of the generated CSS that I get when I inspect the <style> element under the page's <head>:
@media screen and (max-width: 320px).jsx-1595924628
p.jsx-1595924628{color:blue;}
It seems that the media query is interpreted as a CSS class.
Furthermore, I tried to replace the following:
${onMobile} {
p {
color: blue;
}
}
with an explicit and static media query:
@media screen and (max-width: 320px) {
p {
color: blue;
}
}
Only then did it work.
@MissaouiChedy try to keep the value only in the variable:
@media screen and (max-width: ${mobile}) {
p { color: blue }
}
otherwise our CSS parser doesn't have any way to tell that your interpolation is a media query .. it'd rather think that it encountered a nested block.
@giuseppeg thank you for your suggestion.
We started using the SCSS syntax in our styled jsx code which removed the need to wrap media queries in variables.
Now we just use SASS mixins.
Most helpful comment
Try adding support for nesting via PostCSS. A simple solucion could be modify your
package.jsonto something like:And add a
.babelrcThis should work :)