Disclaimer: this issue is meant for capturing breaking changes that we'd like to see changed in v11 to help address some of the consistency issues across styles. None of these changes are final, or implemented, and are subject to change.
The reference implementation for Sass has officially implemented modules. We would love to take the opportunity to update our codebase to leverage this new module system, and specify a direct dependency on a specific sass version (such as dart sass).
Incorporating this proposal will mean that:
import-once mixincarbon-- prefixWe're currently plagued by the fact that any file in our sass source could be imported independently. As a result, we have mechanisms in place for:
In v11, it'd be great if we specified a specific load order for things like a reset, font face, and other global styles. This would then allow folks to import components independently without having to worry about setting flags around emitting CSS side-effects like a reset.
It is important to be intentional with the specificity of our selectors. If a selector is too greedy or specific, it makes it very difficult developers to override or theme the styles it applies. This results in developers adding extra classes, extra wrappers, or targeting _our_ classes.
Example from our code:
.#{$prefix}--form-item.#{$prefix}--checkbox-wrapper:last-of-type {
margin-bottom: rem(3px);
}
User's can supply a custom wrapper class to checkbox, however a single class alone is not enough to override the two classes we've used above:
.custom-checkbox-wrapper:last-of-type {
margin-bottom: 0; // fails
}
div.custom-checkbox-wrapper:last-of-type {
margin-bottom: 0; // also fails
}
Instead, if we recognized that CheckBoxes only ever exist as form-items, it becomes clear the form-item class is superfluous for this rule. If we eliminate it:
- .#{$prefix}--form-item.#{$prefix}--checkbox-wrapper:last-of-type {
+ .#{$prefix}--checkbox-wrapper:last-of-type {
margin-bottom: rem(3px);
}
.custom-checkbox-wrapper:last-of-type {
margin-bottom: 0; // overrides as intended
}
Some simple rules to follow:
ul > li when ul li will do.CSS-in-JS has taken a lot of the React community by storm over the past years. The big wins from doing this are things like:
A, B, andC` we could load in the order:A -> B -> CB -> A -> CAnd I'm sure that there are other great reasons for this, as well.
However, we often run into challenges with the implementation of CSS-in-JS libraries, which is to say that they prefer being loaded as part of the JS for a product instead of emitting stylesheets to off-load this work. This proposal would aim to blend the best of both strategies where we can get programmatic benefits that help to reduce style size, help to eliminate certain classes of bugs, and overall improves the developer experience while still being performant, fast, and reliable.
_Note, a big source of inspiration for this approach comes from Building the new Facebook with React and Relay_
We have the following implementation goals:
Given these goals, the API that we could create may look like:
const styles = stylex.create({
blue: {
color: 'blue',
},
red: {
color: 'red',
},
});
// Generated function can accept Array<keyof T>, where T is object passed to
// stylex.create
styles('blue');
// Can also accept an object with keys of Array<keyof T> and boolean values
styles({
red: false,
blue: true,
});
In a React component, this would look like:
// How you would author
const styles = stylex.create({
default: {
color: 'red',
fontSize: 16,
},
blue: {
color: 'blue',
},
});
function MyComponent(props) {
const className = styles('default', props.isBlue && 'blue');
return <span className={className}>Text</span>;
}
// Optimization pass would:
// 1) substitute property values with class names
const styles = stylex.create({
default: {
color: 'c0',
fontSize: 'c1',
},
blue: {
color: 'c2',
},
});
// 2) Realize that usage can be optimized to be inlined
// this would also drop styles from above and inline class names
function MyComponent(props) {
const className = 'c1 ' + props.isBlue ? 'c2' : 'c0';
return <span className={className}>Text</span>;
}
The build step for CSS may emit two types of files:
components/accordion.{css,scss}This would allow everything to work by default but also allow teams to only include the styles that are needed. A natural challenge here is if we're splitting up our stylesheet how do we make sure that things are correctly duplicated across imports that are brought in 馃
This would be an interesting direction to take the project with tangible benefits for CSS output size and a better development workflow. However, there is risk as this would be an ad-hoc proposal instead of leveraging an existing project. There would also need to be work to figure out how this would play it for how others would consume these styles, or integrate with this to form a complete solution.
Utility classes, as made popular by tachyons or tailwind, would be something really interesting to investigate to see if they make sense in a design system context.
Currently, we haven't specified what we expect teams to be using to compile their Sass. It may be helpful if we changed this to explicitly state the dependency of sass our project uses to prevent confusion moving forward. Most notably, this has come up with the dart sass implementation implementing modules that we are unable to use since we don't specify what sass implementation or version we expect teams to use with our styles.
We currently combine a number of things in a singular package:
This proposal would be for us to decouple these things into their own packages, alongside shipping additional packages that folks may find useful like feature-flags.
@error to enforce Sass type checkingContext: https://github.com/carbon-design-system/carbon/pull/4931#issuecomment-568062734
In #4931, warnings were added to carbon--rem/rem and carbon--em/rem Sass functions to ensure that only values in pixels are provided as arguments. If the values are unitless (or even the wrong unit) then the output of the functions may be invalid CSS that will break a Sass build.
@warn was used in this context, to minimize breaking changes to users. In v11, it is recommended that the @warn blocks are changed to @error blocks. Using @error blocks here will more effectively enforce the type checking of these Sass functions.
In https://github.com/carbon-design-system/carbon/issues/2912 inputs within a modal were reconfigured to utilize background-color: $field-02. It seems this could be applied further to inputs placed within other "container-esque" components that have a $ui-01 background by default. Examples include the Tile and Tabs of type="container".
This was originally raised in https://github.com/carbon-design-system/carbon/issues/4826, PR'ed in https://github.com/carbon-design-system/carbon/pull/5598, and then the changes reverted in https://github.com/carbon-design-system/carbon/pull/5914 due to unintended side effects as Tabs don't currently specify a background color. It seems this should be contained here in a major version bump as it's a potential breaking change for some teams.
Thanks all for weighing in! Going to integrate these suggestions into our roadmap and then out into planning issues 馃憖
Most helpful comment
Proposal: Utility Classes
Utility classes, as made popular by tachyons or tailwind, would be something really interesting to investigate to see if they make sense in a design system context.
Links & Resources