Benefits of using CSS modules with React/Vue - css

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.

Related

Using css variable with styled-compoents

I know you can wrap your react app with <ThemeProvider /> and you can set a variable for the theme and access it like so:
const Text styled`
color: ${((props) => props.theme.red)};
`
But it's it CSS itself have the variable feature?
You can just do
:root {
--red: tomato;
}
.text {
color: var(--red);
}
is it ok to mix them? or stick to either styled-components or CSS?
Yes it is OK. Those 2 technologies have nothing to do with each other and are not conflicting.
As long as your components can inherit the CSS variables (AKA custom properties) they will work.
Just make sure they are really inherit.
Clearly defining variables on the root element selector (html) will make them available everywhere, but sometimes you don't want global variables, but more local, per page/area/component, so you need to structure you code taking that into account.
The real power of CSS variables is in their inheritance (unlike SCSS variables which are injected/replaces during the build-process).
The power of styled-components is isolation & the ability to share code with javascript. This does hinder their ability to inherit CSS variables defined at parents-level.
You need not bother yourself with this question at all, and simply ignore the fact you are using styled-components. All that matters is the HTML structure, which how inheritance works.
I Googled things for you:
https://medium.com/fbdevclagos/how-to-leverage-styled-components-and-css-variables-to-build-truly-reusable-components-in-react-4bbf50467666
https://betterprogramming.pub/7-ways-to-inherit-styles-using-styled-components-69debaad97e3
https://dev.to/arnonate/using-css-variables-to-tame-styled-component-props-2f9o

Reactjs, Bem naming nested structure with SCSSModule

We are using SCSS, SCSSModule and BEM naming methodology. I have researched the best structure for nested elements. I've seen different syntaxes and still have question mark in my head. I saw the symbol differences, for example some teams use "block__element_modifier", some use "block__element--modifier". I know basic usage of BEM. We shouldn't nest the elements with multiple underscored syntax(block__element__nested is wrong). Currently we are using BEM like
block__element--modifier
and nested elements are written with extra hyphen prefix.
Think that the card component structure like below
card
----header
----------title
----------subtitle
----body
----footer
and we code the sass like
// example.scss
.card {
&__header {
// some css
&-title {
// some css
}
&-sub-title {
// some css
}
}
}
and its classes' output is:
card
card__header
card__header-title
card__header-subtitle
Most of the answers in stackoverflow and also some of articles don't suggest BEM as above. They suggest like this:
.card {
&__header {
// some css
}
&__title {
// some css
}
&__sub-title {
// some css
}
}
and its output turn into this:
card
card__header
card__title
card__subtitle
But If I apply as in option 2, I can't figure out which element is in which when I only read scss file. On the other hand, we can understand that in the first option. But the disadvantage of the first option is that the elements become more dependent on each other. For example, when a new div comes between nested elements, I need to refactor related nested class names in the jsx file.
(But still think that it is very useful to understand which elements are nested in the scss file.)
The question is, is my BEM naming wrong or is there such a use in community?
Note: I said we use "module.scss" but I didnt give example in that format. I know, I didnt want to confuse with camelCase things in js.
Your naming is not wrong; it works and it satisfies the BEM pattern; but personally I would not recommend it, and would instead recommend the popular approach.
Your current approach encodes the DOM nesting of elements into the class names. If you need to make changes with regard to the nesting -for example you need an additional wrapper somewhere, which from my experience is a rather common occurence- you will need to change all nested class names. I would be immensely annoyed by that.
And a second drawback of your current approach is that it produces rather long class names.
But what I think is really the biggest drawback of it:
It forces you to nest your SCSS exactly like the DOM nesting to be able to build up the class names. This -in my opinion- makes the SCSS unnecessairily complicated.
With the popular approach your nesting depth for the styles can stay shallow and therefore easier to handle by humans, without messing up the braces { } or needing to nest and unnest rules when the DOM structure changes.
In one of my projects we started with your approach and later changed to the popular approach, and I experienced it as an improvement.
One example:
<div className="card">
<div className="card__header">
<div className="card__branding">
<Logo className="card__logo" />
<span className="card__brandname">Nutrax</span>
</div>
<h2 className="card__title">Recommendation for hard working web devs!<h2>
<div>
<div className="card__body">
Try Nutrax for Nerves!
<div>
<div className="card__footer">
<Button className="card__button">Find nearest store</Button>
<Button className="card__button card__button--promoted">Buy online</Button>
<div>
</div>
.card {
&__header {}
&__body {}
&__footer {}
&__branding {}
&__logo {}
&__brandname {}
&__title {}
&__button {
&--promoted {}
}
}
Now move the branding into the body, no problem, the changes are minimal, and you don't even need to change the SCSS.
PS: You mentioned that you use SCSSModules; I'm not sure I understand what that means. I'm well aquainted with css-modules and I use them usually in my react projects, which completely removes the need for BEM and I can just use rather simple class names that will be automatically scoped to my component only.
If that is also the case with SCSSModules in your project I don't see the need to apply BEM.

Hash or prefix all CSS class names in a Vue CLI project to avoid class inheritance

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

CSS Modules - referencing classes from other modules

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.

How to select certain properties from CSS?

I have three big CSS files which have many classes. Same of those classes have the same name but are in different files.
Example:
CSS1:
...
.btn-primary {
background: #000;
}
...
CSS2:
...
.btn-primary {
background: #fff;
}
...
and CSS3:
...
.btn-primary {
background: #4285F4;
}
...
Let's assume that all three CSS are called in my HTML page.
Is there a way to select in my web page only the .btn-primary class from CSS3? If yes, how could I do it?
No.
If a stylesheet is loaded into a page, and it has a ruleset with selector that matches an element, then it will apply to that element.
Rules which provide conflicting information for a particular property will overwrite each other in the standard cascade order.
Not as is, but you could alter your style sheets so that it reads like this:
.btn-primary, .btn-primary.style1 { ... }
.btn-primary, .btn-primary.style2 { ... }
.btn-primary, .btn-primary.style3 { ... }
Then you could get the specific styles by using the following class:
<a class='btn-primary style2'>Stylesheet 2</a>
In short, you'll need to add some sort of additional method of narrowing down the different styles.
--
Another possibility would be to convert your css files to scss like so:
.style1 {
.btn-primary { ... }
}
You could then use the styling from specific sheets like so:
<div class='style1'>
<a class='btn-primary'>Stylesheet 1</a>
</div>
An apologetic into: the following is, in my opinion, a wrong solution. I wanted to add it as I can think of situations where you have to find this kind of hacky ways rather than change the css files.
Generally speaking, as Quentin and Bryant pointed out - there is no "namespacing" for css files and so if you load all the css files you will end up with the last overriding file's selector classes (among the name-conflicted ones) and won't be able to choose between them.
If (for some odd reason) you don't care about Chrome users - you can probably use the cssRules or rules properties of the document.styleSheets[i] object - for each loaded stylesheet file (i being the number of the file). As noted, this method does not work for Chrome. Fore some reason both cssRules and rules are null in Chrome for each of the styleSheets[i].
My hacky solution:
After loading all the css files as you need,
In javascript code, read the css file you choose as a text file. You can use AJAX for that - see this question and its answers
Search for the selector you want in the text you got and extract that string. You can parse the whole file for example and take the relevant part.
In searching how to help with this step I came across the document.styleSheets[i].cssRules object and the method that doesn't work in Chrome.
Build a style element around it and append that style element to the head element (here's an answer that shows how to create and append style elements to the head element).
This seems like a wrong way to do it from several reasons (performance, elegance, readability) - and probably means the design of the css files is not right for your project (look at Bryant's suggestions) - but I wanted this answer to be here, as there is a way to do it, albeit a hacky one, and if for some reason you can't change the css files and have to use them as is - then here you go.
I don't know what is the usage of this, I mean having three files and storing different styles and even same styles into them.
But there are some tools that will normalize and minify your CSS, for example, take a look at Nano CSS
But, as other answers says it is not possible to say what class from what file apply to this page, and they will overwrite and the last style will apply for the element.
Here is also an example to find out how overwrite works:
#test-link {
display: block;
text-decoration: none;
background: red;
color: white;
}
#test-link {
background: green;
}
#test-link {
background: orange;
}
#test-link {
background: black;
}
<a id="test-link" href="javascript:void(0);">Test link</a>
As you see, just the last style applied for the background color

Resources