I have understood the concept of CSS modules so much that I am convinced that I do not want to do anything else that that for the future.
Currently I am trying to refactor an existing app to use CSS modules, the app has used classic sass with BEM methodology since.
Before I describe my problem I want to make clear that I undestand that I am addressing an issue that is not really within the domain of CSS modules. One should apply styles solely for usage inside a single module. At the most one should compose CSS classes with other CSS classes of other modules. But basically: You build an (HTML-)module and you use CSS modules to style that module and that's that.
Here's the problem:
In the process of refactoring there is one single issue that derives from having had a SASS-based style system. I can't find a valid method to work with a CSS class within a CSS modules environment when this class should work in combination of another class from another module.
Example in SASS:
[page.scss]
.wrapper {
margin: 0;
}
[headline.scss]
.headline {
color: green;
}
.wrapper {
.headline {
color: orange;
}
}
As you can see: One module (page) defines a CSS class "wrapper", another module defines a CSS class "headline". And, additionally, the class "headline" should behave a bit differently when placed inside the class "wrapper".
Again, I know that this is not really the domain of CSS modules. But I really would like to know if this is somehow doable with CSS modules? The "composes"-feature of CSS modules does not really fit here...
This is a common issue when migrating to CSS Modules. In short, a css module cannot override a style from another css module, and this is by design. Styles are supposed to live with the components that render them, and nowhere else.
What you can do to refactor this is to create a component style variant and explicitly set the variant through a prop when rendered within your wrapper.
For example, suppose your headline component currently looks something like this:
CSS
.headline {
color: green;
}
JSX
import styles from "Headline.css";
const Headline = () => {
return (
<div className={styles.headline} />
);
}
Rather than trying to override the .headline class name from somewhere else, you can create a variant class name that you toggle through a prop:
CSS
.headline-green {
color: green;
}
.headline-orange {
color: orange;
}
JSX
import styles from "Headline.css";
const Headline = ({orange}) => {
return (
<div className={orange ? styles.headlineOrange : styles.headlineGreen} />
);
}
And when you render it from your wrapper, set it to the orange variant:
<Headline orange />
Tip: you can use composes to eliminate duplicate common styles between your variants.
Related
I would like to understand the benefits of using CSS Modules with React/Vue.
Currently in my company developers use the following in development:
return (
<div className={styles.User}>
<div className={styles.name}>...</div>
</div>
)
While using a CSS module file, something like:
.User {
background-color: var(--bg-color, red);
.name { color: white; }
}
What should an HTML output such as:
<div class="_User_xyz_1">
<div class="_name_abc_1">...</div>
</div>
Which is a bit confusing for me, as this "encodes" all the class names and creates a great deal of difficulty if I need to do a parent-level modification. Eg.:
<div class="SomeParent">
<User name="David" />
</div>
So:
.SomeParent {
> .User {
--bg-color: blue; // Will not words, because .User is not .User, in fact.
}
}
In personal projects, I prefer to name the primary element of the template by defining it as a "major class", the main. Eg.:
return (
<div className="User">
<div className="name">...</div>
</div>
)
And a regular CSS/SCSS:
.User {
background-color: var(--bg-color, red);
> .name { color: white; }
}
So a parent element's code can affect a child element under expected and controlled conditions.
My question here is: what are the benefits of using the model that my company uses that I am not able to see? Am I missing something using a more "moderate/primitive" model?
Another possibility is: can I modify the style of child elements through the parent element, even with the name of the classes being encoded this way?
CSS modules generate custom classnames for each style and therefore prevent the problem you are facing in your solution. Because each css module style has its own classname you cannot accidentially change a child components style.
SCSS module styles are applied by very unique classes thanks to the hash, and therefore have no real risk of unintended style collisions. This allows you to use short, meaningful class names without having to think of any global styles you might be colliding with. You can confidently style without fear of breaking things elsewhere in your application.
You could, in theory, add generic class names which are not applied via your scss modules to give your parent component a class name with which to work.
Personally I think the React components should be as modular and generic as possible. I think the way to go is such that types are exported from one component. Styles should be inline or at the bottom at a styles object.
hash className, preventing other developers from quickly decompiling your style scheme.
I'm relatively new to Angular, and I have a doubt about component stylesheets.
I have an Angular 12 app and created a component named my-component. The template of the component in question is something like this:
my-component.html
<div>
...some html...
<some-other-angular-component></some-other-angular-component>
...some other html...
</div>
some-other-angular-component is another component, either from the app itself or a third party library.
Now, what I want to do in my-component is apply some CSS rules to the contents of some-other-angular-component. I know that the HTML it generates contains classes that I can target, so I tried to add this to my component CSS:
my-component.scss
.some-other-angular-component-inner-class {
background-color: red;
}
However, this doesn't work, it appears that the component's CSS file only applies rules to the HTML defined directly in the component's template, not the HTML generated by sub-components.
Is there a way to make this work? I find myself having to add my CSS to the webapp's main style.scss file, even when I want to apply the rule only to the particular some-other-angular-component instance inside of my-component. It makes styling confusing and needlessly fragmented. Is this intended, or what am I missing?
I think you may want to look into View Encapsulation.
#Component({
selector: 'app-no-encapsulation',
template: `
<h2>None</h2>
<div class="none-message">No encapsulation</div>
`,
styles: ['h2, .none-message { color: red; }'],
encapsulation: ViewEncapsulation.None,
})
export class NoEncapsulationComponent { }
These styles will be added to head and will be applicable to other components as well if style rule matches.
Please note, with this you are only enabling this behaviour for just this component. Chances of overlapping CSS rules is still there but is lot less in comparison to directly putting styles in style.css.
I will also suggest that you add .class or #id attribute in mark up to ensure that your rules don't overlap by default.
For example:
.my-component .rule-one {
}
It will ensure that my rules are only applied are on component that has this class applied on it.
I need to hash (or just prefix_) all CSS class names in a Vue CLI project to avoid class inheritance when I embed the app inside an existing HTML page.
Basically the Vue app/widget I've made uses some CSS class names like .title, .container, .date, .location etc, and the problem I've got is that the global CSS on the website where I'm embedding this Vue app already uses the class names .title, .container etc, so it's applying those styles to my Vue app as well. I just want a simple way — maybe using vue.config.js — to instruct webpack to randomly hash or prefix the CSS class names so that they are completely unique and won't inherit any parent styling. Thanks
Thanks to the comments above I managed to get it to work. The implementation is not as straight forward as I'd have liked because it requires changing a lot of my existing code — I was hoping for a quicker, simpler solution that would just take my existing code and hash the preexisting CSS classes — which I'm pretty sure must be possible as it seems like such a trivial task? Anyway, here's my setup for now:
vue.config.js
module.exports = {
css: {
requireModuleExtension: false,
loaderOptions: {
css: {
modules: {
localIdentName: '[hash:6]'
}
}
}
}
}
my-component.vue
<template>
<div :class="$style.myClass"> ... </div>
</template>
<style module>
.myClass {
color: red;
}
</style>
Using the above setup I get a div which, instead of being:
<div class="myClass"> ... </div>
is now rendered as:
<div class="_2d736c"> ... </div>
Note the module attribute on the <style> tag which is important. Also note the class name binding: :class (or v-bind:class) not just class.
Hope that helps someone. Thanks
In my project, I use CSS Modules with Less, which means I get the best of both worlds.
My src folder looks something like this:
components/
[all components]
theme/
themes/
lightTheme.less
darkTheme.less
palette.less
palette.less:
#import './themes/lightTheme.less';
Then, in every component that wants to use colors from the theme, I do:
component.module.less:
#import '../../theme/palette.less';
.element {
background-color: #primary;
}
This structure lets me edit palette.less to import the theme I want to use. The thing is that I want to let the users choose their preferred theme on their own. Themes should be switchable on runtime, which means I somehow need to have both themes compiled.
I imagine the perfect solution to be something like this:
app.less
body {
#theme: #light-theme;
&.dark-theme {
#theme: #dark-theme;
}
}
And then somehow import this #theme variable in every component and read properties from it (i.e. #theme[primary]).
Unfortunately, Less variables scoping don't work like this.
I am open-minded to any solution that uses Less modules.
Thank you!
I know that you've probably looking for a solution that uses Less / CSS modules, but it's very likely that your situation can be solved solely with the use of css variables (as Morpheus commented on your question).
How it would work?
You'd have to ensure all your styling does not use hardcoded values, i.e. instead of:
.awesome-div {
background-color: #fefefe;
}
You would have:
:root {
--awesome-color: #fefefe;
}
.awesome-div {
background-color: var(--awesome-color);
}
Changing between light and dark
There are two ways of changing themes in this approach:
Use vanilla Js code within React to update the :root CSS element, check this codepen for more information;
Just load a component containing all new :root variables in its component.css file;
In React (in vanilla CSS too) you can easily have multiple components/elements declaring their own :root at their .css files.
Furthermore, any new :root will overwrite conflicting values from previous :root. For example if at file app.css we have :root { --color: red; } and, when loading another component, component A for instance, where in component_a.css we have the same variable overwritten, e.g. :root { --color: blue; } the one rendered in our browsers will be the one from component A.
Following this logic, you can have a dummy component that does and renders exactly nothing, but instead in this component.js file you import the .css of a theme, e.g.:
import './light.css'; // suppose this is the light-theme dummy component
When switching themes in your app you'd just have to remove the dummy component from scene and call the other one.
I'm not too experienced with codepen to the point of providing you an example containing imports/modules over there, but I hope the above explanation can give you an idea of what I mean. Still, here's a brief pseudo-code of what I'm intending to demonstrate:
loadTheme() {
if (this.state.theme === 'dark') return <LightTheme />;
if (this.state.theme === 'user-3232') return <UserTheme />;
return <DarkTheme />;
}
render() {
return (
<App>
{this.loadTheme()}
<OtherContent>
</App>
);
}
Check out Styled components, it can do that.
https://www.npmjs.com/package/styled-components
https://styled-components.com/docs/advanced#theming
I did it myself as a Easter Egg in an app of mine, so I know for sure it works. Unfortunately it is closed so I can't show you the code publicly.
I work with CSS rarely, but I really want to style my chart. The chart is from a vue.js library and has predefined CSS classes. I just don't know how I am able to access them.
HTML:
CSS:
This is how the document describes the use of CSS with the library:
It's hard to get the full picture only from the images you shared. But it should be relatively easy to just override the default styles that the library uses. If you know what the class names are.
For example:
<style scoped>
year: {
display: block;
}
</style>
Take a look at scoped styles docs.
What you need is a "deep" selector.
So if you want to override child component's styles your css should look like
.vtc-statistik /deep/ .vtc {
}
The thing is that your scoped styles get compiled to
.daten[data-v-bla-bla]{
...
}
b[data-v-bla-bla]{
...
}
/* and .vtc-statistik with nested .vtc */
.vtc-statistik .vtc[data-v-bla-bla] {
...
}
in order to work the way you expect it to work it should get compiled to
/* */
.vtc-statistik[data-v-bla-bla] .vtc{
...
}
where data-v-bla-bla is a unique id of your component.
Btw. Nested styles are not part of CSS specifications. You should use SCSS / PostCSS / Less to process them.