-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
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
[theme] Remove hardcoded breakpoints #21778
Comments
|
The two possible solutions I can think of: diff --git a/docs/src/pages/customization/breakpoints/breakpoints.md b/docs/src/pages/customization/breakpoints/breakpoints.md
index 0f5ec2fe63..6a8b9402db 100644
--- a/docs/src/pages/customization/breakpoints/breakpoints.md
+++ b/docs/src/pages/customization/breakpoints/breakpoints.md
@@ -125,6 +125,23 @@ const theme = createMuiTheme({
},
},
});
+
+const aliases = {
+ xs: 'tablet',
+ sm: 'tablet'
+ md: 'laptop',
+ lg: 'desktop',
+ xl: 'desktop',
+};
+
+const getAliasedKey = (key) => (aliases[key] ? aliases[key] : key);
+
+theme.breakpoints.up = (key) => theme.breakpoints.up(getAliasedKey(key));
+theme.breakpoints.down = (key) => theme.breakpoints.down(getAliasedKey(key));
+theme.breakpoints.between = (start, end) => (
+ theme.breakpoints.only(getAliasedKey(start), getAliasedKey(end))
+);
+theme.breakpoints.only = (key) => theme.breakpoints.only(getAliasedKey(key));
```
If you are using TypeScript, you would also need to use [module augmentation](/guides/typescript/#customization-of-theme) for the theme to accept the above values. or diff --git a/packages/material-ui/src/styles/createBreakpoints.js b/packages/material-ui/src/styles/createBreakpoints.js
index 0d7e133abe..dd6787eef7 100644
--- a/packages/material-ui/src/styles/createBreakpoints.js
+++ b/packages/material-ui/src/styles/createBreakpoints.js
@@ -14,19 +14,23 @@ export default function createBreakpoints(breakpoints) {
lg: 1280,
xl: 1920,
},
+ aliases = {},
unit = 'px',
step = 5,
...other
} = breakpoints;
+ const getAliasedKey = (key) => (aliases[key] ? aliases[key] : key);
const keys = Object.keys(values);
function up(key) {
+ key = getAliasedKey(key);
const value = typeof values[key] === 'number' ? values[key] : key;
return `@media (min-width:${value}${unit})`;
}
function down(key) {
+ key = getAliasedKey(key);
const endIndex = keys.indexOf(key) + 1;
const upperbound = values[keys[endIndex]];
@@ -40,6 +44,8 @@ export default function createBreakpoints(breakpoints) {
}
function between(start, end) {
+ start = getAliasedKey(start);
+ end = getAliasedKey(end);
const endIndex = keys.indexOf(end);
if (endIndex === keys.length - 1) {
@@ -60,6 +66,7 @@ export default function createBreakpoints(breakpoints) {
}
function only(key) {
+ key = getAliasedKey(key);
return between(key, key);
} |
Good point. Thank you. I will take a look at how their sass mixins work.
A Tabs.js defines a CSS class scrollButtonsDesktop: {
[theme.breakpoints.down('xs')]: {
display: 'none',
},
}, on the issue under consideration const aliases = {
xs: 'tablet', //640
sm: 'tablet', //640
md: 'laptop', //1024
lg: 'desktop', //1280
xl: 'desktop', //1280
}; we get the string for @media (max-width:1023.95px) {
display: 'none',
}, although we didn't want to hide the scroll buttons at all. I think that in the mapping there should be only significant breakpoints: const aliases = {
sm: 'tablet', //640
md: 'laptop', //1024
lg: 'desktop', //1280
}; and for
Yes, it is. export interface Breakpoints {
...
aliases: Partial<{[key in keyof BreakpointDefaults]: keyof BreakpointValues}>;
} What do you think about changing the signatures of the functions isWidthUp and isWidthDown (point 3)? |
This is another issue: #13448 if you are interested.
Interesting, consideration. I think that if the key or alias isn't present, it should raise a console.error.
We want to change these helpers, at the very least replace them with hooks or maybe even better drop it #17350. |
Hmm. Not exactly. I mean, if we have breakpoints starting only with
Another example, the material core introduces some component const styles = {
root: {
display: 'flex',
[theme.breakpoints.down('xs')]: {
display: 'none',
},
}; if we define aliases for every breakpoint const aliases = {
xs: 'tablet', //640
sm: 'tablet', //640
...
}
const styles = {
root: {
display: 'flex',
[theme.breakpoints.down('tablet')]: {
display: 'none',
},
}; which is incorrect, since Maybe explicit behavior means "I want to have code generated only for the specified breakpoints"? |
These considerations should be handled with overrides, not the breakpoint helper. |
I understood your idea that behavior with partially defined aliases is not clear at first sight. There is another suggestion not to generate code for missing breakpoints and not to have aliases at all.
Bootstrap does not work with components at a high level. <nav class="navbar navbar-expand-lg">
<button class="navbar-toggler" />
<div class="collapse navbar-collapse" />
</nav> .collapse {
display: none;
}
@media (min-width: 992px) {
.navbar-expand-lg .navbar-collapse {
display: flex;
}
.navbar-expand-lg .navbar-toggler {
display: none;
}
} Of course, if we override breakpoints $grid-breakpoints: (
tablet: 640px,
laptop: 1024px,
desktop: 1280px,
); the example above will not work, because another class will be generated ( If Material-UI had the same |
@nkrivous I don't think that this can work because we wouldn't know what to do with the media query, it can be a Thanks for the comparison with Bootstrap. |
Hi @oliviertassinari , anyone is working on it? Can I take this up? |
@Avi98 Ask @nkrivous. But if you have seen any area of the discussion that isn't clear, let us know! At this point, we were hesitating on a. the aliases direction vs b. not rendering anything if a breakpoint is missing, So far, we write the CSS of the components mobile-first (up), with rare exceptions for desktop first (down), this happens when it allows simpler CSS. The issue with b. is that if we don't render anything, the behavior of the components might be unpredictable. This doesn't seem to align with the objective, we still want to the breakpoint but have different names. If we want to change the breakpoint behavior of the components wouldn't it be better to write an override? I would vote for option a. This option also allows us to implements runtime warnings in case the configuration of the theme is wrong: using a breakpoint name that wasn't defined. |
This is still an issue in v5. Looks like there has not been any movement on this in a couple years. I implemented custom breakpoints as shown in the example and noticed some peculiar diffs in my snapshot tests for a Tabs component
Turned out that tabs was using My solution was to add back the breakpoints for xs, sm, md, lg, xl and duplicate the values from other breakpoints, and then hide them from TS. Would be nice if this could be fixed with aliasing. In the meantime, it seems prudent to at least add some sort of note in the documentation. Perhaps we should start the first suggestion you provided in this comment #21778 (comment). IMO adding an aliases object to the breakpoints (like your second example) feels like a more stable solution, but updating the docs seems good enough. I'm happy to make a PR to update the docs. I could also work on the second option of adding an aliases property to the breakpoints object, but I might be a little slower getting that PR ready since I don't have a lot of free time right now. |
There are several places in the codebase where breakpoints are hardcoded.
Since we have the ability to override breakpoints, we should not have hardcoded values in the code
Current Behavior 😯
Expected Behavior 🤔
a) Use a media query only if there is such a breakpoint in the theme
b) Add a new property
alias
tocreateBreakpoints
function to match breakpointsa) Show the necessity for breakpoints
Remove
import { breakpointKeys } from '../styles/createBreakpoints'
;b) Add breakpoints to options implicitly
Your Environment 🌎
The text was updated successfully, but these errors were encountered: