docs/react-v9/contributing/rfcs/react-components/convergence/no-css-shorthands-in-make-styles.md
makeStyles() calls@layershifter
This RFC proposes to forbid usage of CSS shorthands (background, border, margin, padding, etc.) in makeStyles() calls. Only CSS longhands (backgroundColor, marginLeft, paddingLeft, etc.) will be allowed for usage. This will solve the problem with expanding CSS shorthands, see microsoft/fluentui#19402.
/* š” makeStyles() generates hashed classes, but it's not important in this example */
.a {
background-color: red;
}
.b {
background-color: green;
}
.c {
color: yellow;
}
<!-- Case 1: ā Wrong usage -->
<div class="a b c">Hello world!</div>
<!-- Case 2: ā
Correct usage -->
<div class="a c">Hello world!</div>
<div class="b c">Hello world!</div>
This problem is solved by mergeClasses() function: it de-duplicates classes based on property name.
// ā Simplified example
function App() {
// š skips "a", returns only "b c"
return <div className={mergeClasses('a', 'b', 'c')}>Hello world</div>;
}
To summarize: only non colliding properties should be applied to DOM elements with Atomic CSS. This works well for longhands, but there are cases when longhands and shorthands are combined:
makeStyles({
root: { backgroundColor: 'red', background: 'green' },
});
š In this example the problem is the same: both classes will be applied, result depends on insertion order. In the same time it's annoying for customers use longhands, for example:
makeStyles({
shorthands: {
padding: '10px 15px 5px',
border: '1px solid red',
},
longhands: {
paddingTop: '10px',
paddingRight: '15px',
paddingBottom: '5px',
paddingLeft: '15px',
borderTopWidth: '1px',
borderTopStyle: 'solid',
borderTopColor: 'red',
// ...
// 9 more properties for other side i.e. "borderLeft*", "borderBottom*", "borderRight*"
},
});
To allow use shorthands and longhands simultaneously makeStyles() currently uses inline-style-expand-shorthand (the same library is used in FluentUI Northstar, Fela* & Styletron** plugins).
styletron-engine-atomic to work with Atomic CSSHowever there are numerous issues with it (see microsoft/fluentui#19402), but the main problem is it's unclear what to do with CSS variables:
// Input
const input = { padding: 'var(--foo)' };
// Output
const output = {
/* is it safe to expand it at all? */
paddingTop: 'var(--foo)',
paddingRight: 'var(--foo)',
paddingBottom: 'var(--foo)',
paddingLeft: 'var(--foo)',
};
--foo is atomic value, for example 4px--foo is compound value, for example 4px 8pxIt's important for scaling our library to stay with deterministic Atomic classes. For example, we can extract common styles to a stylesheet that will be used across all products.
There were multiple options covered in the original issue (see microsoft/fluentui#19402), but during offline discussion we agreed to go with build time checks instead runtime and rely on TypeScript typings.
The motivation is simple: no one sees console noise, in big applications it usually 100+ development warnings only on initial load.
This means that custom syntax is a discarded solution, for example:
// ā discarded solution, used only for an example
makeStyles({
rootA: {
// 1ļøā£ no custom properties
paddingX: 'var(--foo)',
},
rootB: {
// 2ļøā£ no custom values
padding: { left: 'var(--foo)', right: 'var(--foo)' },
margin: { all: 'var(--foo)' },
},
rootC: {
// 2ļøā£ no custom values
padding: ['var(--foo)', 'var(--foo)'],
},
});
The first part of proposal is to ban CSS shorthands in typings: no shorthand properties = no need to expand them = no issues ā
Proposed to forbid usage of all CSS shorthands (list of CSS shorthands exported from MDN) except vendor prefixed (i.e. -ms, -webkit).
makeStyles({
// šØ TypeScript will throw
rootA: { padding: '4px' },
// ā
TypeScript will pass
rootB: { paddingLeft: '4px', paddingRight: '4px', paddingBottom: '4px', paddingTop: '4px' },
});
As it will be annoying and redundant to use CSS longhands in every case we will have special functions for expansion.
import { shorthands } from '@fluentui/react-make-styles';
makeStyles({
rootA: { paddingLeft: '4px', paddingRight: '4px', paddingBottom: '4px', paddingTop: '4px' },
rootB: {
...shorthands.padding('4px'),
...shorthands.padding('4px', '8px'),
...shorthands.padding('4px', '8px', '16px', 0),
},
});
shorthands.padding('4px') from the example above will expand it two four properties:
shallowEqual(
{ paddingLeft: '4px', paddingRight: '4px', paddingBottom: '4px', paddingTop: '4px' },
shorthands.padding('4px'),
); // returns "true"
Each macro will implement arguments order & expand based on CSS spec.
For initial implementation following shorthands will be implemented:
borderborderLeftborderBottomborderRightborderTopborderColorborderStyleborderRadiusborderWidthmarginpaddingAdditional functions can be implemented based on customer requests.
makeStyles() as they are very lightweight.makeStyles in our documentationNA
NA