The "OhSnap!" series explores bite-sized tips that you can apply today.
Intro
Today we are going to walk through the folder structure of a React project that I recently completed.
I am using the node-sass npm package, and staying always from any CSS frameworks like Bulma or Bootstrap.
After some research and trial/error, I found that the below system worked well for me. Hopefully it helps you as well.
The Folder Structure
The following has been simplified for the sake of clarity, but the essential structure is still the same. You can view the actual Github repository here.
/src
• ———— /components
• |———— /NominationContainer
• |———— NominationContainer.js
• |———— nominationContainer.scss <—— (section 2)
•
•
• ———— /sassStyles <—— (section 1)
• |———— _animations.scss
• |———— _functions.scss
• |———— _global.scss
• |———— _mixins.scss
• |———— _typography.scss
• |———— _variables.scss
Section 1
This folder sits outside of the components and holds all partials and styles that can effect multiple components. As you will see in Section 2, individual components will import from these partials as needed.
• ———— /sassStyles <—— (section 1)
• |———— _animations.scss
• |———— _functions.scss
• |———— _global.scss
• |———— _mixins.scss
• |———— _typography.scss
• |———— _variables.scss
_animations.scss
This partial stores the actual @keyframe
CSS animations. It helps to drastically reduce the size of component stylesheets. In our example this file stores 22 animations, which is almost 800 lines of code! That is a lot of space saved in our component files, that now just need to reference this file.
_functions.scss
This partial contains any SASS functions which process and return a value. I didn't use them in this project, but a great example of them can be found in this StackOverflow thread.
_global.scss
This partial contains styling that overrides global elements, such as the #root
or body
elements. In our example it is also importing the _variable.scss
file to reference a color.
_mixins.scss
This partial can hold any block of code that is repeatable. In our example I am using mixins to determine breakpoint sizes. They are also using variables, so if my overall lg
size changes, it will update everywhere.
_typography.scss
This partial holds major typography element styles such as h1-h6
, p
, and global classes or ids. As you can see in our example, I like to stay away from applying super-specific properties here, like color. This way I have the flexibility of changing it in different parts of the app, without worrying about specificity.
_variables.scss
This partial contains repeatable property values, such as brand colors and sizes. By storing #002e25
in the variable $primaryDark2Color
I can apply it to properties like color
and border
while preserving the option to change the color globally later on.
Section 2
This is an example of an individual component with a .js
file and its associated .scss
file for styling.
/src
• ———— /components
• |———— /NominationContainer
• |———— NominationContainer.js
• |———— nominationContainer.scss <—— (section 2)
nominationContainer.scss
This is an example of an individual component's .scss
file and I have included its code below. Note how it imports the animations
, variables
, and mixin
partials.
Because of this, animations just require 2 lines of code to establish the settings. Colors are based on variables and media queries are pulled from mixins.
In the future, I can just change these in their original partial files and they will update here.
@import '../../../sassStyles/variables';
@import '../../../sassStyles/animations';
@import '../../../sassStyles/mixins';
.nom-container {
background: $primaryDark1Color;
height: 100%;
padding: 26px 20px;
margin-top: 15px;
opacity: 0;
-webkit-animation: fade-up 1s cubic-bezier(0.165, 0.840, 0.440, 1.000) 1.4s both;
animation: fade-up 1s cubic-bezier(0.165, 0.840, 0.440, 1.000) 1.4s both;
@include customMinBreakPoint(1024) {
margin-top: 0;
padding: 26px 0 50px 0;
-webkit-animation: fade-left 1s cubic-bezier(0.165, 0.840, 0.440, 1.000) both;
animation: fade-left 1s cubic-bezier(0.165, 0.840, 0.440, 1.000) both;
}
&__counter-wrapper {
display: flex;
justify-content: center;
margin-bottom: 30px;
margin-top: 0;
opacity: 0;
-webkit-animation: fade-up 0.9s cubic-bezier(0.165, 0.840, 0.440, 1.000) 1.6s both;
animation: fade-up 0.9s cubic-bezier(0.165, 0.840, 0.440, 1.000) 1.6s both;
@include customMinBreakPoint(1024) {
justify-content: flex-end;
margin-right: 50px;
margin-bottom: 75px;
-webkit-animation: fade-up 0.9s cubic-bezier(0.165, 0.840, 0.440, 1.000) 0.25s both;
animation: fade-up 0.9s cubic-bezier(0.165, 0.840, 0.440, 1.000) 0.25s both;
}
@include customMinBreakPoint(1400) {
margin-right: 12%;
}
@include customMinBreakPoint(1500) {
margin-right: 15%;
}
}
}
Thumbnail designed with Figma
Top comments (4)
if we import variables/mixins in multiple files it may duplicate the same CSS in multiple files. Is it an optimized solution?
My thought too... There should be a way to import all variables/mixins globally so all other scss files can reference it
There are ways to configure webpack to do it (stackoverflow.com/questions/355334..., dev.to/dennisfrijlink/comment/19dh5)
And here's an option with creating an additional
'global-imports.scss'
file to use across the different component scss, or to import globally through webpack.sassStyles/_global-imports.scss:
nominationContainer.scss
Variables (sass variables) and mixins are sass constructs that are not rendered as css on their own, so including them multiple times will not result in duplicated css.
Animations, however, are css definitions, so importing the animations partial multiple times across components would duplicate the css. However, there's no need to import animations into the component file to use them in the app. It would be enough to import the animations a single time into a
main.scss / main.css
file that is included in the app at the top level, and the browser would have those keyframe definitions loaded in and any other css that refers to it would work.This is exactly the issue, I'm facing. I am tempted to use for global variables and scss for the rest.