---
title: 'Scss Library Guide(EN)'
disqus: hackmd
---

A convenient Scss library for quick use.
If you prefer **Scss** development and need to collaborate with UI/UX designers following the guidelines, this Library is perfect for you!
Of course, you can also easily extend and maintain this framework!
## Source Code Location
You can use it directly in your project. It supports Vue, React, Nuxt, and Next.
If there are any improvements that can be made, feel free to send a PR after messaging me.
https://github.com/fortes1219/scss-base-library
```bash=
npm install
npm run dev
```
Since ==the author of SassMeister announced on Twitter that it is shut down==if the website is not accessible, it is recommended to use https://sass.js.org/ for preview.
:::info
Before reading this document, please be aware of a few things.
:::
### 1. Consider the Technical Choices within Your Team
If your project does not need to consider changing skins, you can continue to use TailwindCSS, Stylus, bootstrap, or other methods you are familiar with or consider faster.
### 2. Content Will Be Continuously Updated
As browser versions update, the content will be revised periodically. Since I use this library regularly, I might add new features, such as the recently usable :has().
### 3. Treat UI/UX Designers Well
This library essentially needs to follow themes defined with tools like Figma or XD. If you have a designer who can accurately specify each theme color, typography, spacing, and easing, treat them well. It will greatly help with your skin-changing tasks and redesigns.
### Outline
[TOC]
Applicable Version: Sass 1.50.1 +
Testing Tool: Recommended to use Sass.js
## Architecture Diagram
It is recommended to open the image in a new window: https://i.imgur.com/J3hNFJT.png

## Theme Color
Live Code: [https://codepen.io/fortes-huang/pen/gOdJOWG](https://codepen.io/fortes-huang/pen/gOdJOWG)
Path: **`src/style/config/_theme.scss`**
There are two ways to extract theme colors defined in Figma.
### Class Name
Automatically generate CSS through map traversal and apply it directly.
```sass
$theme-prefix: 'nt'; // Custom prefix
```
```html
<div class="my-text nt-primary-900"></div>
```
The generated CSS will look like this:
```css
.nt-primary-default {
color: #6a675d;
}
.nt-primary-300 {
color: #a09d92;
}
.nt-primary-200 {
color: #bdb9ae;
}
.nt-primary-100 {
color: #d9d5ca;
}
.nt-primary-gradient {
background: linear-gradient(#baa671, #d4be81);
}
.nt-secondary-default {
color: #85754a;
}
```
### useColor
Apply it to any color or background.
```sass
.my-typography {
// Corresponding to primary-900: #15130E
color: useColor(primary, 900);
}
.sample-gradient {
// Corresponding to semantic-dramatic: linear-gradient(#BAA671, #D4BE81)
background: useColor(semantic, dramatic);
}
```
### Source Code Construction
```sass
// Theme name prefix, can be replaced according to different project templates
$theme-prefix: 'nt';
// Theme map of all color swatches
$themeColor: (
primary: (
default: #6a675d,
900: #15130e,
800: #2a2823,
700: #39362d,
...
),(...),(...)
);
@each $category, $color in $themeColor {
@each $variant, $value in $color {
@if type-of($value) == map {
@each $subvariant, $subvalue in $value {
.#{$theme-prefix}-#{'' + $category}-#{$subvariant} {
@if str-index(inspect($subvalue), 'linear-gradient') {
background: $subvalue;
} @else {
color: $subvalue;
}
}
}
} @else {
.#{$theme-prefix}-#{'' + $category}-#{$variant} {
@if str-index(inspect($value), 'linear-gradient') {
background: $value;
} @else {
color: $value;
}
}
}
}
}
// get colors
@function useColor($category, $variant: 'default') {
$color: map-get(map-get($themeColor, $category), $variant);
@return $color;
}
```
## Typography
Here is an overview of how to define the typographic system in your project.
Live Code: [https://codepen.io/fortes-huang/pen/XWPwbXE](https://codepen.io/fortes-huang/pen/XWPwbXE)
### heading
heading text h1 to h6
```sass
/*== h1~h6 ==*/
$headings: (
h1: (
font-size: 40px,
line-height: 48px
),
h2: (
font-size: 32px,
line-height: 40px
),
h3: (
font-size: 26px,
line-height: 28px
),
h4: (
font-size: 21px,
line-height: 21px
),
h5: (
font-size: 18px,
line-height: 18px
),
h6: (
font-size: 16px,
line-height: 16px
)
);
/*== create h1 to h6 ==*/
@each $heading, $properties in $headings {
#{$heading} {
@each $property, $value in $properties {
#{$property}: $value;
}
}
}
/*== result ==*/
h1 {
font-size: 40px;
line-height: 48px;
}
h2 {
font-size: 32px;
line-height: 40px;
}
h3 {
font-size: 26px;
line-height: 28px;
}
```
### font-size & clamp
Font size settings, color matching, and specifying breakpoints to apply **text-overflow: ellipsis**
path:`src/style/config/_typography.scss`
### Usage of Font Sizes:
```html
<div class="my-article nt-text-sm">This is a small size text</div>
<div class="my-article nt-text-base">This is a default size text</div>
<div class="my-article nt-text-lg right">This is a slightly larger text, aligned to the right</div>
```
### Usage with Font Colors:
```html
<div class="my-article nt-text-sm">
This is a text, <span class="nt-accent-600">this part will be colored</span>
</div>
```
### Specify Text Overflow at the Nth Line:
```html
<div class="my-article nt-text-sm clamp-3">
This text will overflow at the third line, now the first line<br />
I am the second line<br />
I am the third line<br />
I am the possibly hidden fourth line
</div>
```
### Preview Effect

### Principles and Source Code
Here we use mixins for text overflow.
path:`src/style/config/_mixins.scss`
```sass
// src/style/config/_mixins.scss
/*== Enable text overflow for a specified number of lines ==*/
// width is used to set a fixed width for the container, accepting fit-content
// -webkit-line-clamp: $line-count = specifies the number of lines to show "..."
%extendEllipsis {
display: -webkit-box;
-webkit-box-orient: vertical;
height: auto;
line-height: inherit;
overflow: hidden;
}
@mixin useEllipsis($width, $line-count) {
width: $width;
-webkit-line-clamp: $line-count;
overflow: hidden;
@extend %extendEllipsis;
}
```
useEllipsis is used in typography.scss
```sass
// map table for font sizes
$textConfig: (
max-clamp: 10,
size-prefix: (
'xs',
'sm',
'base',
'lg',
'xl',
'2xl'
),
size: (
12px,
14px,
16px,
18px,
21px,
24px
),
default-color: #ffffff
);
// give variables for prefix & size
$textPrefixList: map-get($textConfig, size-prefix);
$textSizeList: map-get($textConfig, size);
@each $size in $textSizeList {
$index: index($textSizeList, $size);
// theme-prefix default was 'nt'
.#{$theme-prefix}-text-#{nth($textPrefixList, $index)} {
font-size: px-to-rem($size);
color: map-get($textConfig, default-color);
@for $i from 1 through map-get($textConfig, max-clamp) {
&.clamp-#{$i} {
@include useEllipsis(null, $i);
}
}
@each $align in 'left', 'right', 'center' {
&.#{$align} {
text-align: #{$align};
}
}
}
}
```
```css
// result
.nt-text-xs {
font-size: 0.75rem;
color: #ffffff;
}
.nt-text-xs.clamp-2 {
-webkit-line-clamp: 2;
overflow: hidden;
}
.nt-text-xs.clamp-3 {
-webkit-line-clamp: 3;
overflow: hidden;
}
```
## Adaptor: pixel & rem
A method to convert px to rem or rem to px.
path:`src/style/config/_remAdaptor.scss`
### Applicable Scenarios
If your project and designer have agreed to use proportional scaling to display the mobile site appearance, you will likely need to set up something like this for your project:
https://github.com/fortes1219/scss-base-library/blob/master/rem.js
This script sets the font-size to 100px at a default resolution of 390x884 (iPhone 12/13). The purpose is to dynamically change the body font-size so that the UI's width and height are calculated in rem units, facilitating proportional scaling.
### Usage:
```javascript
// rem.js
function setRootFontSize(doc, win) {
const clientWidth = win.innerWidth || doc.documentElement.clientWidth;
if (!clientWidth) return;
// Check if the device is a PC
const isPC = win.matchMedia("(min-width: 1024px)").matches;
if (isPC) {
doc.documentElement.style.fontSize = "72px";
return;
}
// Set font size based on screen width
const baseFontSize = 100 * (clientWidth / 390);
if (clientWidth >= 540) { // Modify the device width limit as needed
doc.documentElement.style.fontSize = "100px";
} else {
doc.documentElement.style.fontSize = baseFontSize + "px";
}
}
export default setRootFontSize;
```
```javascript
// main.js
import debounce from "lodash/debounce";
import setRootFontSize from "./rem.js";
// Dynamic rem handling with lodash debounce to prevent resize jitter
document.addEventListener("DOMContentLoaded", () =>
setRootFontSize(document, window)
);
const debouncedSetRootFontSize = debounce(
() => setRootFontSize(document, window),
10
);
window.addEventListener("resize", debouncedSetRootFontSize);
window.addEventListener("orientationchange", debouncedSetRootFontSize);
```
```sass
// The actual converted value will change based on the body font-size in rem.js
.my-class {
width: px-to-rem(100px); // 1rem
font-size: px-to-rem(2rem); // 200px
}
```
### Source Code:
```sass
@use 'sass:math';
// Proportional scaling layout will be set with baseRemRate = 100 * (current device width / 750)
// Here the base rate of 100px can be seen as a 100% scale
$baseRemRate: 100px;
@function strip-unit($number) {
@return math.div($number, ($number * 0 + 1));
}
@function px-to-rem($value) {
// unit unit will find out if $value includes a unit
@if unit($value) == 'px' {
@return math.div(strip-unit($value), strip-unit($baseRemRate)) * 1rem;
} @else if unit($value) == 'rem' {
@return strip-unit($value) * $baseRemRate;
} @else {
@error "Invalid unit. Only 'px' and 'rem' units are supported.";
}
}
```
## Mixin: flexBox
path:`src/style/config/_flexbox.scss`
Live Code (codepen): [https://codepen.io/fortes-huang/pen/OJVyVxw](https://codepen.io/fortes-huang/pen/OJVyVxw)
```sass
/* src/style/config/_flexbox.scss */
@mixin flexBox($direction, $alignItems, $justifyContent) {
display: flex;
flex-direction: $direction;
@if ($alignItems != null) {
align-items: $alignItems;
}
@if ($justifyContent != null) {
justify-content: $justifyContent;
}
}
/* usage */
.my-element1 {
@include flexBox(row, null, null);
}
.my-element2 {
@include flexBox(row, center, space-between);
}
.my-element3 {
@include flexBox(column, flex-end, center);
}
```
result:
```css
.my-element1 {
display: flex;
flex-direction: row;
}
.my-element2 {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.my-element3 {
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: center;
}
```
Generally, there is no need to set **flex-shrink (shrink ratio), flex-basis (initial width)**.
If you need to make elements stick to the left and right edges of the parent container after wrapping, using Grid is more ideal.
This is because flexbox is designed to solve the layout problem with a "single row" premise. Using only flexbox makes the code relatively complex to maintain.
You can refer to the following **flexList** to see what conditions are needed.
## flexList
Using flexbox for list items, you need to specify the number of columns in each row, the arrangement, and the width and height of the child elements.
### row-type
Live Code: [https://codepen.io/fortes-huang/pen/jOvKZOr](https://codepen.io/fortes-huang/pen/jOvKZOr)
```html!
<h2>row:</h2>
<div class="flx is-row is-list sp-between wrap w-50vw" data-border="all">
<span>1</span>
<span>2</span>
<span>3</span>
...
...
</div>
```
```sass
@mixin flexListItem($rows, $margin, $unit) {
// The width calculation must offset margin-right because it is 100/$rows,
// so it needs to add 20% of the margin in the end
$mod: (100 / $rows) / 100;
$mod: (100 / $rows) / 100;
width: calc((100% / #{$rows}) - #{$margin + $unit} + (#{$margin} * #{$mod + $unit}));
margin-right: #{$margin + $unit};
margin-bottom: #{$margin + $unit};
&:nth-child(#{$rows}n) {
margin-right: 0;
}
}
span {
@include flexBox(row, center, center);
@include flexListItem(10, 10, 'px');
height: 120px;
background-color: #333;
color: #fff;
}
.flx {
display: flex;
width: 100%;
box-sizing: border-box;
&.is-list::after {
content: '';
display: flex;
flex: 1;
}
// ...
// ...
}
```
Regarding the implementation principle, let's look at an **example**:
Suppose the width of each child element card is `calc(100%/5)`, using `space-between` to align the container left and right:

Here, `align-content: start` is used in `.wrap`, preventing the height between two lines from being increased after wrapping.
Settings to remove the margin for the last element (5n) of each row:
```sass
.child-element {
@include flexBox(row, center, center);
// The width calculation must offset the margin-right of 10px because it is 100/5, so it needs to add 20% of 10px = 2px
width: calc((100%/5) - 10px + 2px);
height: 120px;
margin-right: 10px; // In principle, the margin must be deducted from the calc
margin-bottom: 10px;
background-color: #333;
color: #fff;
// Every 5th element will be the last one in the row
&:nth-child(5n) {
margin-right: 0;
}
}
```
If there is only one element in the second row, it's fine, but if there are more...


`space-between` will separate the two elements in the second row, and it won't work for just one element.
The more extra space, the larger the gap.
Therefore, we use Pseudo Element: after to fill the unhandled space:
```sass
.flx {
display: flex;
width: 100%;
box-sizing: border-box;
// Set ::after as a decoration block with grow = 1, shrink = 1, and basis = auto
&::after {
content: '';
display: flex;
flex: 1;
}
}
```
And add the mixin for child element list items:
```sass
@mixin flexListItem($rows, $margin, $unit) {
// $rows: number of columns in a row, width: calc(100%/$rows)
// $margin: margin width, represented by $mod
// $unit: unit for margin
$mod: (100 / $rows) / 100;
width: calc((100% / #{$rows}) - #{$margin + $unit} + (#{$margin} * #{$mod + $unit}));
margin-right: #{$margin + $mod};
margin-bottom: #{$margin + $mod};
&:nth-child(#{$rows}n) { // nth-child(number + n) means it applies every n elements
margin-right: 0;
}
}
span {
@include flexBox(row, center, center);
@include cards(5, 5, 'px');
height: 120px;
background-color: #333;
color: #fff;
}
```

This way, you can smoothly customize the list regardless of the number of child elements.
### column-type
Live Code: [https://codepen.io/fortes-huang/pen/VwGELJq](https://codepen.io/fortes-huang/pen/VwGELJq)
If **flex-direction: column** is the `basis`, another method will be used, and **`justify-content` must be `flex-start`**.
```htmlembedded
<h2>column:</h2>
<div class="flx is-col is-list wrap w-50vw h-100vh" data-border="all">
<span>1</span>
<span>2</span>
<span>3</span>
...
...
</div>
```
```sass
@mixin flexColumnListItem($rows, $margin, $unit) {
$mod: (100 / $rows) / 100;
height: calc((100% / #{$rows}) - #{$margin + $unit} + (#{$margin} * #{$mod + $unit}));
margin-right: #{$margin + $unit};
margin-bottom: #{$margin + $unit};
&:nth-child(#{$rows}n) {
margin-bottom: 0;
}
}
span {
@include flexBox(row, center, center);
@include flexColumnListItem(4, 10, 'px');
width: 120px;
background-color: #333;
color: #fff;
}
```
To center the child elements, add align-content: center to the parent container, like this:

## Grid List
path:`src/style/config/_grid.scss`
Live Code (codepen): [https://codepen.io/fortes-huang/pen/wvEYOPG](https://codepen.io/fortes-huang/pen/wvEYOPG)
Usage:
```sass
.sample-list {
@include gridList(6, 10px, 100px);
width: 600px;
}
```
Source Code:
:::info
The way to write a grid list:
`$rows` => Number of elements in one row
`$gap` => Spacing between elements
`$autoSize` => Used to specify the minimum height of each element, accepting 'auto' / null / any unit height
When the content height of a specific element in a row is higher than other elements, it will automatically stretch the height of all sibling elements in that row.
:::
```sass
@mixin gridList($rows, $gap, $autoSize) {
display: grid;
grid-template-columns: repeat($rows, 1fr);
grid-gap: $gap;
@if $autoSize == 'auto' or $autoSize == null {
grid-auto-rows: minmax(min-content, max-content);
} @else {
grid-auto-rows: minmax($autoSize, max-content);
}
}
```
## Conclusion
In conclusion, this SCSS library provides a robust and flexible foundation for building scalable and maintainable styles in your projects. By standardizing configurations for colors, typography, spacing, and responsive design, you can ensure consistency and efficiency in your development process. We hope you find these tools and techniques useful in your work.
## Future Work
We are continuously working to improve this library. Future updates may include additional mixins, extended support for new CSS features, and more examples to demonstrate best practices. Stay tuned for more enhancements and feel free to contribute your ideas.
## Acknowledgments
We would like to thank all the contributors and community members who have provided feedback and suggestions. Your support and collaboration are invaluable to the success of this project.
###### tags: `Scss` `Scss Library` `Scss Optimization`, `SCSS best practices`