using css modules, how can I import classes from a file - css

I am using css modules for my project, and I have a file positioning.css which has some useful classes that I want to import. e.g. .right, .left
What is the best approach for this using CSS Modules?
At the moment I can see 2 options, but they are not all that great:
composition in the component's style
.right {
composes: right from '../styles/positioning.css';
}
or
multiple css module imports in the component
import positioning from '../styles/positioning.css'
import styles from './myComponent.css';
Object.assign(styles, positioning)
class Menu extends Component {
render() {
return (
<div styleName='menu'>
<div styleName='left'>this is left</div>
<div styleName='right'>this is right</div>
</div>
);
}
};
export default CSSModules(Menu, styles);

I have manage to get this working:
// css file
#value class-to-compose from "file-where-class-is-defined.css";
.someclass {
composes: class-to-compose;
// other styles
}

One approach is to collect all app level css variables and calculations at the top level into app.css
#import "./theme/layout.css";
#import "./theme/colors.css";
...
Then reference app.css using
#import "../../app.css";
This way you can manage #import scope inside one file at the root level.

I'll go with the first proposition. (the result is quiet the same)
both proposition have quiet the same result
If someday you have to edit your Menu css, you'll just have to edit your Menu css and not your component.
You let CSSModules take decisions. (more futur proof?)

You could import the css files that you use frequently into a broader CSS file that you import on specific pages, this is taking the second approach but making it cleaner, especially if you have a lot of common core css files that you import on pretty much all pages.

I would advise you to go with [Sass] [1]. Sass allows for the usage of partials (i.e. distributed / scoped css sheets).
You write scoped (to the components you want) css and import all your partials into your main.css then.
Couple of other advantages:
you can do theming by having one partial that defines your them via variables, which you import first and then all your partials can use these variables.
having the css on a scoped level (at least to me) felt more "reactish" where components are supposed to be stand alone, but it also wasn't inline styling, which I find ugly and weird (I don't like to clutter down my .js files with styles)
[1] http://sass-lang.com/

I find this one line very helpful with importing:
#import 'file.css';

You could set these as globals and update their names to be a tad more semantic, like BootStraps pull-right.
If you declare them as
:global(.right) {
/* ... */
}
You can then just use them in your app by preferably importing globals early on in the entry point.

You should take a look at the option by vue.js component (scoped/overall)
You can choose a precompile css language like SASS, which can use #extend ...etc to reuse the common property, like below:
%common {
width: 100%;
height: inherit;
}
.my-class {
#extend %common;
}

Related

SCSS Styling with Next.js

I am relatively new to Next.js and the react ecosystem, but have been using it for a lot of my website development lately and so far have been loving it. One thing that is definitely causing some increased development time is how the styling works using SCSS, or at least my understanding of it.
I have built a number of SCSS partial files that contain different pieces of a style guide that I have used for a while - think similar to tailwind where I have predefined a large number of classes to do different things, some as simple as .flex { display: flex; } to more complex styles.
I have imported many of these partials into the globals.scss file so they would be applied everywhere, and some of the other partials are only imported into the specific files that I need them.
The issue I am running into with Next is that if I want to style a global selector, I have to add additional classes to the element. For example, if I had something like this
import styles from './component.module.scss'
export default function Component() {
return (
<div className={styles.classOne}>
<div className="container additionalClass anotherClass"></div>
</div>
);
what would be ideal is to be able to target those classes in the related scss file like so:
.classOne {
background:#000;
.additionalClass {
padding:10px;
}
}
however targeting that .additionalClass does not work, so I would have to switch the js file to be something like
import styles from './component.module.scss'
export default function Component() {
return (
<div className={styles.classOne}>
<div className={`container additionalClass anotherClass ${styles.mySpecificStyleSelector}`}></div>
</div>
);
and then target .mySpecificStyleSelector in the scss. Is this something that is by design with Next or am I missing something that could help with this scenario? I appreciate any input!

React js css stylesheet applied to more than one component

I have a Parent.js component with a child component Child.js inside of it.
Parent.js imports parents.css
Child.js imports child.css
If I define this in child.css:
.example {
font-family: 'Roboto', sans-serif;
}
How come I'm able to use this className in the Parent.js component as well despite not specifying it in the parent.css?
Unless you use unique class names, CSS Modules or some other alternatives available for scoping CSS styles to any component in React, styles specified in any CSS file will be applied globally.
If you want to limit styles to any component, use CSS Modules or make sure every class name is unique in your project.
For details on how to use CSS Modules, see Adding a CSS Modules Stylesheet. You can also look at 9 Ways To Implement CSS in React JS for other available alternatives.
I recommend using unique class names. For example, lets say you have multiple ListView components: MemberUsersListView, AdminUsersListView, TestUsersListView; and each of them needs to be styled differently. I would create the following CSS classes:
.MUListView{
...
}
.AUListView{
...
}
.TUListView{
...
}
I know this seem's annoying, but it's cleaner than applying inline styles and easier to implement on smaller projects.

Switching themes using Less + CSS Modules in React

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.

How can I use a third party CSS library in an Angular component's CSS without duplicating the library?

I have a two components that both rely on effects from hover.css. Both components have SASS files that (simplified) look something like this:
#import '~hover.css/scss/hover';
.some-class a {
#include underline-from-left;
}
Additionally, I have the hover.css library included in my global styles in style.css:
#import '~hover.css/scss/hover';
.some-global-class {
#include some-other-mixin-from-hover;
}
This all works and compiles fine, except for the rather large fly in the ointment that I end up with full hover.css in my compiled application three times - once in styles.js and twice in main.js (once for each component). This is obviously not a sustainable pattern.
If I don't #import hover.css in my components though, Angular won't compile them because they reference a mixin that can't be found. I've tried deep linking just the effects I need from hover.css but that's a hornet's nest because those files have downstream dependencies on other parts of the hover library. This obviously isn't specific to hover, but any scenario in which you'd want to import and use a vendor library in an Angular component's CSS file without duplicating the library.
Any ideas?
What do you have on your hover.scss file? Is it only mixins or other CSS as well? If you only have mixins then you should be fine, if you have some CSS then it will get taken. For example:
This would not cause repetition:
#mixin underline-from-left {
text-decoration: underline;
}
If you have something like this, then the span block will be repeated as many times as you would import it:
#mixin underline-from-left {
text-decoration: underline;
}
span {
display: block;
}
Perhaps an idea is to separate mixins from actual CSS, and then import only the mixins file.

Not entirely sure where am I supposed to write my CSS in a Vue SPA

Up until now, I've always used a single CSS file when creating multiple page applications which would store all my CSS rules.
Now that I'm using Vue.js and components, I am not sure where to write my CSS.
I could write the CSS in the <style></style> tags of a component but to me this only makes sense if the CSS is only used for this specific component. This leaves me wondering where should I write CSS which I would like to be applied globally to everything.
Imagine I have some CSS which I want to be applied to everything like this snippet:
*, *:after, *:before {
margin: 0;
padding: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
text-decoration: none;
}
Where would I write it?
Until a better solution I can offer two suggestions:
1. In App.vue file
If it's just a small amount of code, put it in your App.vue file
As you said:
"I could write the CSS in the tags of a component but to me this only makes sense if the CSS is only used for this specific component."
If you put CSS in the in the <style></style>in any .vue files that's part of your project it's going to be global.
<style></style> get's applied to the whole project unless you add scoped to the tag.
<style scoped>
body {
background: green; /* This won't effected your main <body> tag unless you actually have a `<body>` inside the `<template>` of that file */
}
</style>
2. Import a separate file containing only CSS (updated and easier)
From #Fabjan in the comments.
Just import the .css file in your main.js file:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './assets/lib/css/reset.css' // my own reset file
import './assets/lib/css/myMain.css' // global stylesheet
Make sure to put it before your run your app. new Vue({})
(3. My previous answer:)
You can create a styles.vue and add all your global styles there inside <styles></styles> without scoped. (this worked for me)
Then inside your main.js file you write:
import GlobalStyles from "./assets/lib/css/styles.vue"
Vue.use(GlobalStyles)
Make sure your styles.vue contains at least on tag inside for it to import properly.
<template>
<div class="empty">
</div>
</template>
<style>
body {
background: red;
/* The rest of your Global CSS code */
}
</style>
This feels really tacky but it worked for me now.
Hope it helps and I'd love some feedback or comments if people have better solutions.
Here is my solution to configure global scss with my project that using Nuxt.
Assume that you already have node sass and sass-loader installed.
In nuxt.config.js file add your SCSS path from static or assets folder
css: [
'#/assets/scss/main.scss'
]
Bonus: if you don't like this way maybe you can get a try nuxt-sass-resources-loader

Resources