NightPack is a development framework based on Webpack 4.x. This is a child of NightVue project that inherited its main principles. It is made for developers who don't need Vue.js functionality.
While many other frameworks offer ready-to-use UI solutions, NightPack gives you the maximum freedom to develop your own web interfaces. The ideological basis of the framework is the most useful utilities from Bootstrap 4.x, many of which have been improved. NightPack uses best practices from Material Design 2 throughout. The framework is powered by Webpack CLI 3.x, one of the most convenient tools for developing modern websites.
NightPack is build for Front-end developers who don't like rewriting the built-in styling solutions of third-party frameworks and plugins. It's for those who prefer to develop "from scratch". For those who need framework with ready-to-use UI solutions, we would recomend to use popular ones like Bootstrap, Materialize, Foundation, or whatever you like.
Modules:
- webpack v4.43.0
- webpack-cli v3.3.12
- jquery v3.5.1
- babel v8.0.6
- sass-loader v8.0.0
- css-loader v3.2.0
- autoprefixer v9.8.4
- file-loader v6.0.0
- html-loader v0.5.5
- mini-css-extract-plugin v0.8.0
- pug-html-loader v1.1.5
- svg-sprite-loader v5.0.0
- svg-url-loader v5.0.1
Features:
- Hot-reload dev server
- Well organized file structure
- Pug templates support
- Scss/Sass support with prefixer
- Bunch of Scss mixins and functions
- Flexbox grid
- Normalize.css
- SVG sprite loader
- Images loader
- Fonts loader
Clone repo and install dependencies
git clone https://github.com/nightrunner91/nightpack.git
npm i
Run hot-reload dev server
npm run watch
Build your project
npm run build
.
├── src
│ ├── assets
│ ├── fonts
│ ├── icons
│ └── images
│ ├── scripts
│ └── components
│ app.js
├── styles
| ├── @core
│ └── helpers
│ _functions.scss
│ _mixins.scss
│ _varaibles.scss
│ globals.scss
│ normalize.scss
│ typography.scss
│ ├── animations
│ ├── components
│ └── sections
│ nightvue.scss
│ style.scss
│ └── views
│ ├── core
│ ├── elements
│ ├── layouts
│ ├── sections
│ _mixins.pug
│ index.pug
│ index.js
|
| webpack.config.js
Let's take a look at the crucial parts of framework.
src/assets
folder includes any types of assets you are using in your project, such as icons, fonts, images, files etc. NightPack uses set of Webpack and Sass loaders to easy serve and manage themsrc/scripts
folder includes all scripts you are using in your project.src/scripts/app.js
file is where you import and run plugins and other stuff
src/styles
folder includes stylesheets, Sass functions and mixins, usefull utilities.src/styles/@core
folder includes crucial NightPack Sass mixins, functions and code generators to work withsrc/styles/@core/helpers
- the folder includes SCSS files that generates utility classnames to use in HTML (grid, spacers, text styles, colors etc.)src/styles/@core/globals.scss
- this is key file where we import all functions, mixins and variables from so-called files at the same directorysrc/styles/@core/typography.scss
file describes all text styles (headings, displays, paragraphs, fonts etc)src/styles/@core/normalize.scss
makes browsers render all elements more consistently and in line with modern standards. It is basicly slightly modified SCSS version of widely used Normalize.css
src/styles/animations
folder includes @keyframessrc/styles/components
folder includes styles for reusable components like buttons, dropdowns, inputs, avatars, modals, alerts, etc.src/styles/sections
folder includes styles for "big" and unique parts like: header, footer, article, hero, etc.src/styles/nightvue.scss
file includes all NightPack settings, styles and code generatorssrc/styles/style.scss
is file where you can write your own styles
src/views
folder includes Pug templates and pages you are using in your project.src/index.js
is the root file where you import styles, scripts, icons etc.
- Layout
- Grid
- Typography
- Position
- Display
- Spacing
- Sizing
- Colors
- Gradients
- Opacity
- Icons
- Radius
- Shadows
- Z-index
- Transitions
- Animations
- Rotations
- Utilities
Nightpack uses Pug's built-in features to create page templates. You must have knowledge of Pug to work with NighPack.
The following template is provided by default in NightPack:
include ../_mixins
block globalVars
- var fooGlobal = "foo"
block innerVars
doctype html
html(lang="en")
head
+meta
body
+header
block content
+footer
The _mixins
block contains all the global Pug mixins in your project. By default, it already has header()
and footer()
, which are attached to <body>
tag.
The globalVars
and innerVars
blocks are optional, but may come in handy in the future. Their names speak for themselves - you can store global and local variables in them, respectively.
The <head>
tag contains the mixin declared earlier in _mixins
- this is meta()
describing the meta tags.
The content
block is where the main content of the page will be mounted. For example, our index.pug
page contains the following content:
extends layouts/_default
block innerVars
- var fooLocal = "foo"
block content
main(class="main")
+intro
The intro
mixin in this case is the welcome message saved in a separate file in the views/sections/_intro.pug
folder:
mixin intro()
div(class="d-flex flex-column justify-content-center align-items-center vw-100 vh-100")
img(
class="mb-4 no-select"
src="../assets/images/logo.png"
alt='logo')
h1(class="m-0")
span(class="clr-primary") Night
span(class="clr-info") Pack
All of the above is advisory in nature and serves as the basis for a quick start of development. You are free to change this structure as it is more convenient for you. You can find more details about the layout system in the official documentation.
NightPack grid system is built with flexbox and is fully responsive. It uses a series of containers, rows, and cols to align content. If you are not familiar with flex we recomend to read this article.
There are 3 types of containers in NightPack:
- boxed - on each
$breakpoint
container will have fixedmax-width
based on$containers
map - combined - container will have
max-width
of last value from$containers
map, then will have 100% - full - container will always have 100% width
Base grid settings are stored in _varaibles.scss file:
$num-cols: 12;
$gutter-width: 1rem;
$grid-type: 'combined';
// Breakpoints are dublicated in 'store/modules/config.js'
$breakpoints: (
xs: 576px,
sm: 768px,
md: 992px,
lg: 1200px,
xl: 1400px
);
// Containers max-widths (if you are using 'boxed' or 'combined' type)
$containers: (
xs: 540px,
sm: 720px,
md: 960px,
lg: 1140px,
xl: 1320px
);
To apply column width in HTML you can use prepared classnames col-${breakpoint}-${value}
:
div(class="container")
div(class="row")
div(class="col col-12 col-xs-10 col-sm-11 col-md-8 col-lg-6 col-xl-4")
width 12 by default
width 10 on 'xs' breakpoint
width 11 on 'sm' breakpoint
width 8 on 'md' breakpoint
width 6 on 'lg' breakpoint
width 4 on 'xl' breakpoint
If you need apply offset to column use offset-${breakpoint}-${value}
classnames like this:
div(class="container")
div(class="row")
div(class="col col-4 offset-xs-4 offset-sm-5 offset-md-8 offset-lg-0")
offset 4 columns on 'xs' breakpoint
offset 5 columns on 'sm' breakpoint
offset 8 columns on 'md' breakpoint
don't do any offset on 'lg' breakpoint
If you need apply order to column use order-${breakpoint}-${value}
classnames like this:
div(class="container")
div(class="row")
div(class="col col-6 order-xs-1 order-md-5")
order 1 on 'xs' breakpoint
order 5 on 'md' breakpoint
Although HTML method is very familiar to most developers, we highly recomend to use Sass mixins to build grid directly in SCSS files. This will Pug templates noticeably cleaner and at the same time help keep all the styles in one place.
To convert any selector to container just apply @container()
mixin to it:
@include container();
@include container('full');
@include container($type: 'boxed', $gutter: 2rem);
From now on this selector will have same properties as .container
class. Notice that you can define $type
and $gutter
.
Just like with container you can convert any selector to .row
. Simply apply @row()
mixin to it. Additionally you can pass $gutter
value. It will apply alternate negative left and right margins:
@include row();
@include row(0);
@include row($gutter: 2rem);
To apply column styles use @col()
mixin. If you don't pass any params mixin will apply only padding-left
and padding right
based on $gutter-width
varaible. To apply width properties you can pass number from 1 to 12 for each breakpoint:
@include col();
@include col(12);
@include col(10, $md: 8);
@include col(10, $md: 8, $lg: 6, $xs: 12);
@include col(12, 10, 10, 8, 6, 9);
If you need apply offset to column use @offset()
mixin. It will add margin-left
property to selector. You can pass number from 0 to 12 for each breakpoint. Note that if you don't pass any params, mixin won't apply any styles:
@include offset(6);
@include offset(0, $sm: 4);
@include offset(10, $md: 8);
@include offset(10, $md: 8, $lg: 6, $xs: 12);
@include offset($sm: 1, $lg: 4, $xl: 0);
In case you need apply order to column use @order()
mixin. It will apply order
property from 1 to 12 to selector:
@include order(2);
@include order(1, $sm: 4);
@include order(1, $md: 2, $lg: 3, $xs: 12);
@include order($sm: 12, $lg: 4, $xl: 3);
NightPack provides set of handy media queries based on $breakpoints
. You can use queries based on min-width
and max-width
:
// min-width queries
$xs-up; // > 576px
$sm-up; // > 768px
$md-up; // > 992px
$lg-up; // > 1200px
$xl-up; // > 1400px
// max-width queries
$xs-dw; // < 578px
$sm-dw; // < 767px
$md-dw; // < 991px
$lg-dw; // < 1199px
$xl-dw; // < 1399px
Or queries between breakpoints:
$xs-sm; // 576px … 767px
$sm-md; // 768px … 991px
$md-lg; // 992px … 1199px
$lg-xl; // 1200px … 1399px
Here are some examples of usage:
@media #{$sm-up} { ... } } // styles applies above 768px
@media #{$md-up} { ... } } // styles applies above 992px
@media #{$xl-dw} { ... } } // styles applies below 1399px
@media #{$lg-dw} { ... } } // styles applies below 1199px
@media #{$sm-md} { ... } } // styles applies between 768px … 991px
@media #{$md-lg} { ... } } // styles applies between 992px … 1199px
NightPack stores all typography settings in Sass maps located in _varaibles.scss file. In typography.scss file are described styles for headings, displays, body text, lists, and more.
We recomend to start with importing fonts by using @font-face
mixin. Make sure to store your fonts in src/assets/fonts
folder. Each font must be saved in a folder with the same name as font itself. By default NightPack uses Onest. This is how we stored and imported it, use this as an example to add your own fonts:
// Font files location:
├── src
│ ├── assets
│ ├── fonts
│ └── Onest
// Import font using @font-face mixin:
@include font-face('Onest', 'OnestRegular', 400, normal, 'recent');
@include font-face('Onest', 'OnestMedium', 500, normal, 'recent');
@include font-face('Onest', 'OnestBold', 700, normal, 'recent');
@include font-face('Onest', 'OnestBlack', 900, normal, 'recent');
These are Sass maps with typography settings we talked earlier. Each one is self explanatory, so take a look at them:
$font-families: (
base: "Onest",
headings: "Onest",
displays: "Onest"
);
$line-heights: (
1: 1,
25: 1.25,
50: 1.5,
75: 1.75,
2: 2,
);
$text-aligns: (
left: left,
center: center,
right: right,
justify: justify
);
$font-weights: (
lighter: lighter,
bolder: bolder,
100: 100, // thin
200: 200, // extra light
300: 300, // light
400: 400, // normal
500: 500, // medium
600: 600, // semi bold
700: 700, // bold
800: 800, // extra bold
900: 900, // black
);
$text-transforms: (
lowercase: lowercase,
uppercase: uppercase,
capitalize: capitalize
);
$font-styles: (
normal: normal,
italic: italic,
oblique: oblique
);
$text-decorations: (
underline: underline,
line-through: line-through,
none: none
);
$text-wraps: (
normal: normal,
nowrap: nowrap,
pre: pre,
pre-line: pre-line,
pre-wrap: pre-wrap
);
$word-brakes: (
normal: normal,
break-all: break-all,
keep-all: keep-all,
break-word: break-word,
);
$letter-spacings: (
normal: normal,
tight: -0.05em,
wide: .1em,
wider: .5em,
);
Important part is settings for headings and displays:
$headings-fz: (
h1: 4.5rem,
h2: 2.5rem,
h3: 1.75rem,
h4: 1.25rem,
h5: 1rem,
h6: 0.875rem,
);
$headings-lh: map-get($line-heights, 25);
$headings-fw: map-get($font-weights, 500);
$headings-margins: (
top: map-get($spacers, 1),
bottom: map-get($spacers, 50),
);
$displays-fz: (
display-1: 74px,
display-2: 62px,
display-3: 48px,
display-4: 34px,
);
$displays-lh: map-get($line-heights, 25);
$displays-fw: map-get($font-weights, 500);
$displays-margins: (
top: map-get($spacers, 1),
bottom: map-get($spacers, 50),
);
Here you can manage styles for base body text, small and tagline styles:
$base-fz: 16px; // CRUCIAL VALUE! A lot of things depends on it. Be aware.
$base-lh: map-get($line-heights, 50);
$base-fw: map-get($font-weights, 400);
$small-fz: 0.875; // Ratio of text size for <small> tag and .small classname
$small-lh: map-get($line-heights, 25);
$small-fw: map-get($font-weights, 400);
$tagline-fz: 1.25; // Ratio of text size for .tagline classname
$tagline-lh: map-get($line-heights, 50);
$tagline-fw: map-get($font-weights, 500);
For each Sass map NightPack generates set of utility classnames to use in HTML:
.font-base { font-family: "Onest" }
.font-headings { font-family: "Onest" }
.font-displays { font-family: "Onest" }
.line-height-1 { line-height: 1 }
.line-height-25 { line-height: 1.25 }
.line-height-50 { line-height: 1.5 }
.line-height-75 { line-height: 1.75 }
.line-height-2 { line-height: 2 }
.text-left { text-align: left }
.text-center { text-align: center }
.text-right { text-align: right }
.text-justify { text-align: justify }
.text-underline { text-decoration: underline }
.text-line-through { text-decoration: line-through }
.text-none { text-decoration: none }
.white-space-normal { white-space: normal }
.white-space-nowrap { white-space: nowrap }
.white-space-pre { white-space: pre }
.white-space-pre-line { white-space: pre-line }
.white-space-pre-wrap { white-space: pre-wrap }
.word-break-normal { word-break: normal }
.word-break-break-all { word-break: break-all }
.word-break-keep-all { word-break: keep-all }
.word-break-break-word { word-break: break-word }
.text-lowercase { text-transform: lowercase }
.text-uppercase { text-transform: uppercase }
.text-capitalize { text-transform: capitalize }
.font-weight-lighter { font-weight: lighter }
.font-weight-bolder { font-weight: bolder }
.font-weight-100 { font-weight: 100 }
.font-weight-200 { font-weight: 200 }
.font-weight-300 { font-weight: 300 }
.font-weight-400 { font-weight: 400 }
.font-weight-500 { font-weight: 500 }
.font-weight-600 { font-weight: 600 }
.font-weight-700 { font-weight: 700 }
.font-weight-800 { font-weight: 800 }
.font-weight-900 { font-weight: 900 }
.font-normal { font-style: normal }
.font-italic { font-style: italic }
.font-oblique { font-style: oblique }
.spacing-normal { letter-spacing: normal }
.spacing-tight { letter-spacing: -0.05em }
.spacing-wide { letter-spacing: 0.1em }
.spacing-wider { letter-spacing: 0.5em }
Each classname supports breakpoints. You can use template ${property}-${breakpoint}-{$value}
to easy change text styles across different breakpoints. For example this font-weight
will apply only on sm
breakpoint:
@media screen and (min-width: 768px) {
.font-weight-sm-500 {
font-weight: 500 ;
}
}
To apply small styles to text you can add .small
classname or wrap element in <small></small>
tag. Another way is to use @small()
mixin:
div(class="small")
I am small text
small
Me too!
@include small()
Apply tagline styles to text in similar way:
div(class="tagline")
I am tagline text
@include tagline()
Often you need to truncate some long text and put dots at the end of the line. Use one of these helpers to do that:
div(
class="text-truncate"
style="width: 120px;")
I am very long text and I will be truncated at 120px width
div(class="text-truncate max-w-25")
I am very long text and I will be truncated at 25% width
div(class="text-dotted")
I will not be truncated, but will have '…' at the end
.text-truncate {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.text-dotted {
&:after {
content: '…'
}
}
Or use @text-truncate($width)
mixin for that. It requires a single argument $width
in px
or %
.
@include text-truncate(150px)
// =>
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
max-width: 150px;
These utility classnames will help you to set and change position property of elements.
.position-relative { position: relative }
.position-absolute { position: absolute }
.position-static { position: static }
.position-fixed { position: fixed }
.position-static { position: static }
Each classname supports breakpoint, so you can easily change behaviour of element across different breakpoints. Use template .position-${breakpoint}-{$value}
for that. For example, this element will be in position: absolute
only on LG breakpoint:
@media screen and (min-width: 1280px) {
.position-lg-absolute {
position: absolute
}
}
Display system allows you to change display property and quickly manage the layout, alignment, and sizing of elements with a full suite of responsive flexbox utilities. If you are not familiar with flex we advice you to read this article first. Utility classnames are generated in _display.scss file.
Here are listed possible variants of display
property:
.d-none { display: none }
.d-block { display: block }
.d-inline { display: inline }
.d-inline-block { display: inline-block }
.d-flex { display: flex }
.d-inline-flex { display: inline-flex }
.d-table { display: table }
.d-table-cell { display: table-cell }
.d-table-row { display: table-row }
NightPack generates classnames based on flexbox settings:
flex-direction
justify-content
align-items
align-self
align-content
flex-wrap
flex-grow
flex-shrink
Here are possible variants for each of those:
.flex-row { flex-direction: row }
.flex-row-reverse { flex-direction: row-reverse }
.flex-column { flex-direction: column }
.flex-column-reverse { flex-direction: column-reverse }
.justify-content-start { justify-content: start }
.justify-content-end { justify-content: end }
.justify-content-center { justify-content: center }
.justify-content-between { justify-content: space-between }
.justify-content-around { justify-content: space-around }
.align-items-start { align-items: start }
.align-items-end { align-items: end }
.align-items-center { align-items: center }
.align-items-baseline { align-items: baseline }
.align-items-stretch { align-items: stretch }
.align-self-start { align-self: start }
.align-self-end { align-self: end }
.align-self-center { align-self: center }
.align-self-baseline { align-self: baseline }
.align-self-stretch { align-self: stretch }
.align-content-start { align-content: start }
.align-content-end { align-content: end }
.align-content-center { align-content: center }
.align-content-baseline { align-content: baseline }
.align-content-stretch { align-content: stretch }
.flex-wrap { flex-wrap: wrap }
.flex-nowrap { flex-wrap: nowrap }
.flex-wrap-reverse { flex-wrap: wrap-reverse }
.flex-grow-0 { flex-grow: 0 }
.flex-grow-1 { flex-grow: 1 }
.flex-shrink-0 { flex-shrink: 0 }
.flex-shrink-1 { flex-shrink: 1 }
Each classname supports breakpoints, which can help you to easy change display and flex properties across different breakpoints. Use template ${property}-${breakpoint}-{$value}
for that. Take a look at some examples:
@media screen and (min-width: 1400px) {
.d-xl-none { display: none }
}
@media screen and (min-width: 1200px) {
.flex-lg-column { flex-direction: column }
}
@media screen and (min-width: 992px) {
.justify-content-md-center { justify-content: center }
}
@media screen and (min-width: 768px) {
.align-items-sm-start { align-items: start }
}
@media screen and (min-width: 576px) {
.flex-wrap-xs-nowrap { flex-wrap: nowrap }
}
Often you need to align content right in the center of X and Y axes. In that case use classname .flex-center
on parent element. It also supports breakpoints.
.flex-center {
display: flex;
justify-content: center;
align-items: center;
}
.flex-xs-center { ... } // styles applies above 576px
.flex-sm-center { ... } // styles applies above 768px
.flex-md-center { ... } // styles applies above 992px
.flex-lg-center { ... } // styles applies above 1200px
.flex-xl-center { ... } // styles applies above 1400px
NightPack generates responsive margin and padding utility classnames. The classnames are named using the format {$property}-{$breakpoint}-{$side}-{$size}
.
Where $property
is one of:
m
- for classnames that set property marginp
- for classnames that set property padding
Where $breakpoint
is one of:
xs
- for classnames that set property property on XS breakpoint > 576pxsm
- for classnames that set property property on SM breakpoint > 768pxmd
- for classnames that set property property on MD breakpoint > 992pxlg
- for classnames that set property property on LG breakpoint > 1200pxxl
- for classnames that set property property on XL breakpoint > 1400px- blank - if you want to set a margin and padding on all breakpoint
Where $side
is one of:
t
- for classnames that set property margin-top or padding-topb
- for classnames that set property margin-bottom or padding-bottoml
- for classnames that set property margin-left or padding-leftr
- for classnames that set property margin-right or padding-rightx
- for classnames that set property both *-left and *-righty
- for classnames that set property both *-top and *-bottom- blank - for classnames that set property a margin or padding on all 4 sides of the element
Where $size
is one of spacing sizes defined in _varaibles.scss file:
$spacer: 1rem;
$spacers: (
0: 0,
1: ($spacer * .25),
2: ($spacer * .5),
3: ($spacer * .75),
4: ($spacer * 1),
5: ($spacer * 1.25),
6: ($spacer * 1.5),
7: ($spacer * 1.75),
8: ($spacer * 2),
9: ($spacer * 2.25),
10: ($spacer * 2.5),
11: ($spacer * 2.75),
12: ($spacer * 3),
13: ($spacer * 3.25),
14: ($spacer * 3.5),
15: ($spacer * 3.75),
16: ($spacer * 4),
17: ($spacer * 4.25),
18: ($spacer * 4.5),
19: ($spacer * 4.75),
20: ($spacer * 5),
auto: auto
);
$base-mg: map-get($spacers, 1); // Universal margin used for <p>, <ul> etc.
We crated a tool NightPack Spacers Generator, where you can quickly see spacing results based on your initial settings.
In case you prefer SCSS method to define spacers use spacer()
function for that.
- If you pass one param it will return spacer value
- If you pass two params it will return X and Y spacer values
- If you pass four params it will return top, right, bottom and left spacer values
padding: spacer(2);
// => padding: .25rem;
padding-right: spacer(5);
// => padding-right: 1.25rem;
margin: spacer(3, auto);
// => margin: .75rem auto;
margin: spacer(5, auto, 2, 0);
// => margin: 1.25rem auto 0.25rem 0;
Beside that NightPack generates classnames which you might use to position elements in absolute
or fixed
position. These classnames uses pattern ${side}-${size}
:
.top-2 { top: .25rem }
.right-10 { right: 2.5rem }
.bottom-4 { bottom: 1rem }
.left-5 { left: 1.25rem }
And of course they also support breakpoints:
@media screen and (min-width: 768px) {
.right-sm-4 {
right: 1rem
}
}
These utility classnames can be used apply to selector these CSS styles: width
, max-width
, min-width
, height
, max-height
, min-height
. And units can be percentages %
or relative to viewport vw
and vh
.
NightPack generates set of classnames which uses format ${property}-${breakpoint}-${size}
, where ${property}
is one of:
w
- forwidth
in%
vw
- forwidth
invw
max-w
- formax-width
in%
max-vw
- formax-width
invw
min-w
- formin-width
in%
min-vw
- formin-width
invw
h
- forheight
in%
vh
- forheight
invw
max-h
- formax-height
in%
max-vh
- formax-height
invw
min-h
- formin-height
in%
min-vh
- formin-height
invw
Where $size
is one of sizing values defined in _varaibles.scss file:
$sizings: (
0: 0,
25: 25,
50: 50,
75: 75,
100: 100,
auto: auto
);
Here are generated sizing classnames based on 50 size as an example:
.w-50 { width: 50% }
.vw-50 { width: 50vw }
.max-w-50 { max-width: 50% }
.max-vw-50 { max-width: 50vw }
.min-w-50 { min-width: 50% }
.min-vw-50 { min-width: 50vw }
.h-50 { height: 50% }
.vh-50 { height: 50vh }
.max-h-50 { max-height: 50% }
.max-vh-50 { max-height: 50vh }
.min-h-50 { min-height: 50% }
.min-vh-50 { min-height: 50vh }
You can also apply ${breakpoints}
to dynamically change behavior on different screen sizes. For example, this min-width
style will apply only below 768px (sm breakpoint):
div(class="min-w-sm-50 min-w-75")
I have min-width 50% below 768px and 75% above
@media screen and (min-width: 768px) {
.min-w-sm-50 {
min-width: 50%;
}
}
.min-w-sm-75 {
min-width: 75%;
}
Don't forget that you can also apply auto
sizing to an element:
.w-auto { width: auto }
.max-w-auto { max-width: auto }
.min-w-auto { min-width: auto }
.h-auto { height: auto }
.max-h-auto { max-height: auto }
.min-h-auto { min-height: auto }
NightPack uses Sass maps to store project colors. This maps will help you quickly and easily loop over a list of colors and their hex values.
$colors
map includes all available "basic" colors in project$grays
map includes achromatic list (shades of gray between#fff
and#000
)$theme-colors
map includes semantically named colors composed from maps above
All this maps are described in _varaibles.scss file:
$colors: (
'red': #F44336,
'pink': #EC407A,
'orange': #FF9800,
'yellow': #FFEE58,
'green': #47b05b,
'brown': #795548,
'teal': #009688,
'cyan': #00BCD4,
'blue': #2196F3,
'purple': #682CAB,
);
$grays: (
'white': #ffffff,
'gray-1': #eaeaea,
'gray-2': #d5d5d5,
'gray-3': #bfbfbf,
'gray-4': #aaaaaa,
'gray-5': #959595,
'gray-6': #cccccc,
'gray-7': #6a6a6a,
'gray-8': #555555,
'gray-9': #404040,
'gray-10': #2b2b2b,
'black': #000000,
);
$theme-colors: (
'primary': map-get($colors, 'purple'),
'secondary': map-get($colors, 'blue'),
'success': map-get($colors, 'green'),
'info': map-get($colors, 'teal'),
'warning': map-get($colors, 'yellow'),
'danger': map-get($colors, 'red'),
'light': map-get($grays, 'gray-2'),
'dark': map-get($grays, 'gray-8'),
);
In map $levels
you can define levels of lightening and saturation of each color in $theme-colors
map. By default this map has 5 levels:
$levels: (
1: 10%,
2: 20%,
3: 30%,
4: 40%,
5: 50%,
);
NightPack automatically generates classnames from maps $grays
and $theme-colors
above. Each color have unique classname with background-color
, color
and fill
styles and uses template ${property}-${color}
, where ${property}
is one of:
bg
for background-colorclr
for text colorfill
for SVG fill color
Here are some examples:
.bg-white { background-color: #ffffff }
.clr-white { color: #ffffff }
.fill-white { fill: #ffffff }
.bg-gray-1 { background-color: #eaeaea }
.clr-gray-1 { color: #eaeaea }
.fill-gray-1 { fill: #eaeaea }
.bg-primary { background-color: #682CAB }
.clr-primary { color: #682CAB }
.fill-primary { fill: #682CAB }
Additionally for each color NightPack generates classnames with brightened, darkened, saturated and desaturated color variations from $theme-colors
map. We are using mix() and scale() functions for that. They help to create smooth and steady color pallete. We created NightPack Pallete Generator to quickly see the results, check it out.
Generated classnames uses pattern ${property}-${color}-${style}-${level}
. Let's take a look at color variations of primary
color:
.clr-primary-light-1 { color: #7741b3 }
.clr-primary-light-2 { color: #7f4cb8 }
.clr-primary-light-3 { color: #8656bc }
.clr-primary-light-4 { color: #8e61c0 }
.clr-primary-light-5 { color: #956bc4 }
.clr-primary-dark-1 { color: #5e289a }
.clr-primary-dark-2 { color: #582591 }
.clr-primary-dark-3 { color: #532389 }
.clr-primary-dark-4 { color: #4e2180 }
.clr-primary-dark-5 { color: #491f78 }
.clr-primary-sat-1 { color: #6828af }
.clr-primary-sat-2 { color: #6825b2 }
.clr-primary-sat-3 { color: #6823b4 }
.clr-primary-sat-4 { color: #6721b6 }
.clr-primary-sat-5 { color: #671fb8 }
.clr-primary-desat-1 { color: #6832a5 }
.clr-primary-desat-2 { color: #6936a1 }
.clr-primary-desat-3 { color: #69399e }
.clr-primary-desat-4 { color: #693c9b }
.clr-primary-desat-5 { color: #693f98 }
Beside that you can use rgba
versions of $theme-colors
. For each opacity
value from $opacities
map NightPack generates set of transparent colors:
$opacities: (
0: 0%,
1: 5%,
2: 15%,
3: 25%,
4: 35%,
5: 45%,
6: 55%,
7: 65%,
8: 75%,
9: 85%,
10: 95%
);
These classnames uses pattern ${property}-${color}-opacity-${opacity}
. Take a look at rgba
variants of success
color as example:
.bg-success-opacity-0 { rgba(71, 176, 91, 0) }
.bg-success-opacity-1 { rgba(71, 176, 91, 0.05) }
.bg-success-opacity-2 { rgba(71, 176, 91, 0.15) }
.bg-success-opacity-3 { rgba(71, 176, 91, 0.25) }
...
.bg-success-opacity-10 { rgba(71, 176, 91, 0.95) }
If you need apply colors in SCSS files you can use color($name, $style, $level)
function. It returns hex value of color by its $name
. Additionally you can pass optional arguments $style
and $level
to determine level of brightness or saturation. Or you can define it's $opacity
level. Here are some examples of usage in SCSS:
box-shadow: 1px 1px 4px color('primary');
// => box-shadow: 1px 1px 4px #682CAB;
border-color: color('secondary', light, 2);
// => border-color: #42a6f5;
border-color: color('success', dark, 4);
// => border-color: #358444;
color: color('danger', sat, 2);
// => color: #f64234;
background-color: color('warning', desat, 4);
// => background-color: #eadd6d;
color: color('white');
// => color: #ffffff;
color: color('white', $opacity: 5);
// => color: rgba(255, 255, 255, 0.45);
fill: color('gray-4');
// => fill: #aaaaaa;
Working with linear-gradient
may be akward and cluncy sometimes. It's not easy to remember all settings and features of this CSS function. NightPack provides some tools to easy manage group of gradients and create new ones with ease. Read MDN Documentation describing linear-gradients
if you are not quite familiar with them.
First of all NightPack uses Sass map $gradients
to store all gradients used in project. This map is located in _varaibles.scss file. By default there are already 4 gradients as examples:
$gradients: (
primary_success: (
direction: 145deg,
fallback: map-get($theme-colors, 'primary'),
list: (
lighten(map-get($theme-colors, 'primary'), map-get($levels, 2)) 10%,
lighten(map-get($theme-colors, 'success'), map-get($levels, 1)) 80%
)
),
primary-light-3_primary: (
direction: to bottom,
fallback: map-get($theme-colors, 'primary'),
list: (
map-get($theme-colors, 'primary'),
lighten(map-get($theme-colors, 'primary'), map-get($levels, 3))
)
),
red_yellow_blue: (
direction: to right,
fallback: map-get($colors, 'red'),
list: (
map-get($colors, 'red'),
map-get($colors, 'yellow'),
map-get($colors, 'blue')
)
),
info_transparent: (
direction: 90deg,
fallback: map-get($theme-colors, 'info'),
list: (
map-get($theme-colors, 'info'),
transparent
)
),
);
We recomend to name gradients in such pattern: <color1>_<color2>_<color3>
. It will help you to easy understand what colors are used and what is direction of gradient. Here are some examples: info_success
, primary_danger
, light_dark
, transparent_black
, red_yellow_blue
.
If gradient uses modified color you may name it like this: <color-${style}-${value}>_<color-${style}-${value}>
. For example, gradient named primary-light-3_primary
indicates that it uses lightened by 3 levels $primary
and base $primary
colors and shows the direction of it. Pretty self explanatory, right?
Now let's take a look at gradient itself. Each one is written by template:
gradientName: (
direction: { String },
fallback: { String },
list: ( { String }, { String }, { String }... )
)
Where direction
is obviously direction of linear-gradient
. It may be keyword:
to top
to top right
to right
to bottom right
to bottom
to bottom left
to left
,to left top
or any angle value in deg
, rad
, grad
or turn
.
Parameter fallback
is color by default for unsupported browsers. To know which browsers don't support linear-gradient
visit caniuse.com website.
And finally most inetersting part is list
parameter. This is basicly a list of colors in gradient, separated by a comma. One way to fill it is by using map-get()
function like we did in examples above.
For each gradient in $gradients
map NightPack generates unique classname with template .gradient-${gradient}
:
.gradient-primary_success {
background: #682cab;
background: linear-gradient(145deg, #8e51d2 10%, #68c279 80%);
}
.gradient-primary-light-3_primary {
background: #682CAB;
background: linear-gradient(to bottom, #682CAB, #9b65d8);
}
.gradient-red_yellow_blue {
background: #f44336;
background: linear-gradient(90deg, #f44336, #ffee58, #2196f3);
}
.gradient-info_transparent{
background: #009688;
background: linear-gradient(90deg, #009688, transparent);
}
In case you need apply gradient in SCSS file insted of HTML use @linear-gradient($name)
mixin. It requires only name of gradient from $gradients
map.
@include linear-gradient('primary_success');
// =>
background: #682cab;
background: linear-gradient(145deg, #8e51d2 10%, #68c279 80%);
For each opacity value from $opacities
map NightPack generates utility classnames with pattern .opacity-${value}
:
$opacities: (
0: 0%,
1: 5%,
2: 15%,
3: 25%,
4: 35%,
5: 45%,
6: 55%,
7: 65%,
8: 75%,
9: 85%,
10: 95%
);
.opacity-0 { opacity: 0 }
.opacity-1 { opacity: 0.05 }
.opacity-2 { opacity: 0.15 }
.opacity-3 { opacity: 0.25 }
...
.opacity-10 { opacity: 0.95 }
These classnames supports $breakpoints
so you can easily manage opacity
level on each specific breakpoint. Use template .opacity-${breakpoint}-{$value}
to do that. For example this opacity
will apply only on lg
breakpoint:
@media screen and (min-width: 1280px) {
.opacity-lg-5 {
opacity: 0.45
}
}
In case you need apply opacity
in SCSS use opacity($level)
function:
opacity: opacity(0);
// => opacity: 0;
opacity: opacity(1);
// => opacity: 0.05;
opacity: opacity(3);
// => opacity: 0.25;
opacity: opacity(7);
// => opacity: 0.65;
opacity: opacity(10);
// => opacity: 0.95;
To serve SVG icons NightPack uses SVG Sprite Loader.
Store your icons in src/assets/icons/library
folder. We already included there 3 icons for example. There are many icon packs on internet, just pick whatever you like most and import icons in this folder.
├── src
│ ├── assets
│ ├── icons
│ ├── library
│ face.svg
│ lightbulb.svg
│ link.svg
│ index.js
Plugin automatically creates and injects in <body>
client-side SVG sprite containing each icon from the folder above. Keep in mind that each icon will have an id based on its name. To include icon in HTML use this structure:
svg: use(xlink:href='#face')
If you are not quite familiar with this feature read MDN Docs.
To set icon size add corresponding classnames. All icon sizes are stored in $icons
map located in _varaibles.scss file:
$icon-sizes: (
2xs: 0.625em, // 10px
xs: 0.75em, // 12px
sm: 0.857em, // 14px
md: 1em, // 16px
lg: 1.25em, // 20px
xl: 1.5em, // 24px
2xl: 2em, // 32px
);
svg(class="icon-size-2xs"): use(xlink:href='#face')
svg(class="icon-size-xs"): use(xlink:href='#face')
svg(class="icon-size-sm"): use(xlink:href='#face')
svg(class="icon-size-md"): use(xlink:href='#face')
svg(class="icon-size-lg"): use(xlink:href='#face')
svg(class="icon-size-xl"): use(xlink:href='#face')
svg(class="icon-size-2xl"): use(xlink:href='#face')
In case you prefer to set icon size in SCSS file, use @icon-size
mixin. This mixin apply specific width
and height
to an element. If you apply this mixin to selector you can be pretty sure it will have passed dimensions no matter what and will not be compressed or stretched:
@include icon-size(sm);
// =>
width: 0.875em;
max-width: 0.875em;
min-width: 0.875em;
height: 0.875em;
max-height: 0.875em;
min-height: 0.875em;
We recomend to use predefined icon sizes from $icons
map, but here you can pass whatever dimensions you want:
@include icon-size(18px, 34px);
// =>
width: 18px;
max-width: 18px;
min-width: 18px;
height: 34px;
max-height: 34px;
min-height: 34px;
NightPack uses Sass map $radiuses
to store all variants of border-radius
. By default it includes:
$radiuses: (
'small': 4px,
'base': 8px,
'large': 20px,
'circle': 100%,
'zero': 0
);
For each value from this map NightPack generates set of utlity classnames to use in HTML. Pattern depends on which angle or angles you want to modify:
.radius-${type}
- for classnames that set property to all angles.radius-tl-${type}
- for classnames that set property to top-left angle.radius-tr-${type}
- for classnames that set property to top-right angle.radius-bl-${type}
- for classnames that set property to bottom-left angle.radius-br-${type}
- for classnames that set property to bottom-right angle.radius-t-${type}
- for classnames that set property to top-left and top-right angles.radius-r-${type}
- for classnames that set property to top-right and bottom-right angles.radius-b-${type}
- for classnames that set property to bottom-left and bottom-right angles.radius-l-${type}
- for classnames that set property to bottom-left and top-left angles
These classnames supports $breakpoints
so you can easily manage border-radius
type on each specific breakpoint. Use template .radius-${direction}-${breakpoint}-{$type}
to do that. For example this element will have "large" border-radius
only on sm
breakpoint:
@media screen and (min-width: 768px) {
.radius-b-sm-large {
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
}
}
In case you prefer SCSS method, use radius($type)
function. It requires type of border-radius
you want to apply to an element:
border-radius: radius('small');
// => border-radius: 4px;
border-radius: radius('circle');
// => border-radius: 100%;
border-top-left-radius: radius('zero');
// => border-top-left-radius: 0;
NightPack stores all types of box-shadows in $shadows
map located in _varaibles.scss file. By default this map contains list of shadows based on Material methodology:
$shadows: (
level-1: (0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)),
level-2: (0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23)),
level-3: (0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)),
level-4: (0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22)),
level-5: (0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22)),
);
Sure you can remove them and/or add your own. For example this website provides a large collection of beautiful box-shadows.
For each type from this map NightPack generates classnames using pattern .shadow-${type}
:
.shadow-level-1 { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24) }
.shadow-level-2 { box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23) }
.shadow-level-3 { box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23) }
.shadow-level-4 { box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22) }
.shadow-level-5 { box-shadow: 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22) }
In case you prefer to use them in SCSS file use shadow($type)
function. It requires name of shadow as parameter:
box-shadow: shadow('level-1');
// => box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
box-shadow: shadow('level-2');
// => box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
box-shadow: shadow('level-3');
// => box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
box-shadow: shadow('level-4');
// => box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
box-shadow: shadow('level-5');
// => box-shadow: 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22);
Z-index property has a huge role in how web interface works. To position elements in Z-axis NightPack provides list of utility classnames. Taking into account that each project is unique and NightPack don't has any pre-build components we decided to make an unversal list of z-indexes from -1 to 12. It's quite possible that this solution won't work for you, in that case use any other you like more.
Utility classnames uses format .z-plus-${value}
for positive values and .z-minus-${value}
for negatives. You can also determine start and end values in _zindex.scss file:
$zindex-start: -1;
$zindex-end: 12;
.z-minus-1 { z-index: -1 }
.z-0 { z-index: 0 }
.z-plus-1 { z-index: 1 }
.z-plus-2 { z-index: 2 }
.z-plus-3 { z-index: 3 }
.z-plus-4 { z-index: 4 }
.z-plus-5 { z-index: 5 }
.z-plus-6 { z-index: 6 }
.z-plus-7 { z-index: 7 }
.z-plus-8 { z-index: 8 }
.z-plus-9 { z-index: 9 }
.z-plus-10 { z-index: 10 }
.z-plus-11 { z-index: 11 }
.z-plus-12 { z-index: 12 }
Each of these classnames supports $breakpoints
so you can easily manage z-index
value on each specific breakpoint:
@media screen and (min-width: 1280px) {
.z-lg-plus-12 {
z-index: 12
}
}
NightPack provides set of most usable transition timings in web. They are stored in $transition-timings
map located in _varaibles.scss file:
$transition-timings: (
linear: cubic-bezier(0, 0, 1, 1),
ease: cubic-bezier(0.25, 0.1, 0.25, 1),
ease-in: cubic-bezier(0.42, 0, 1, 1),
ease-out: cubic-bezier(0,0,0.58,1),
ease-in-out: cubic-bezier(0.42, 0, 0.58, 1),
standard: cubic-bezier(0.4, 0, 0.2, 1),
emphasized: cubic-bezier(0.0, 0, 0.2, 1),
decelerated: cubic-bezier(0.0, 0.0, 0.2, 1),
accelerated: cubic-bezier(0.4, 0.0, 1, 1),
sharp: cubic-bezier(0.4, 0, 0.6, 1)
);
- First group are "standard" easing functions, that are already well described in MDN Docs
- Second group are easings from Material Design 2 guidelines. They have some similarities with previous group, although they are developed to be more "eye catchy" and each one serves some purpose
- Third group is where you can add your own easings. We added there "sharp" easing. This curve may be used for objects that may return to the screen at any time in fast way. Try cubic-bezier.com - it's a cool tool to create your own easings
Besides timing functions there is set of transition speed:
$transition-speed: (
shortest: .15s,
shorter: .2s,
short: .25s,
base: .3s,
slow: .375s,
slower: .5s,
lazy: .75s,
);
NightPack generates classnames based on this maps to use them in HTML:
.timing-linear { transition-timing-function: cubic-bezier(0, 0, 1, 1) }
.timing-ease { transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1) }
.timing-ease-in { transition-timing-function: cubic-bezier(0.42, 0, 1, 1) }
.timing-ease-out { transition-timing-function: cubic-bezier(0,0,0.58,1) }
.timing-ease-in-out { transition-timing-function: cubic-bezier(0.42, 0, 0.58, 1) }
.timing-standard { transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1) }
.timing-emphasized { transition-timing-function: cubic-bezier(0.0, 0, 0.2, 1) }
.timing-decelerated { transition-timing-function: cubic-bezier(0.0, 0.0, 0.2, 1) }
.timing-sharp { transition-timing-function: cubic-bezier(0.4, 0.0, 1, 1) }
.speed-shortest { transition-duration: .15s }
.speed-shorter { transition-duration: .2s }
.speed-short { transition-duration: .25s }
.speed-base { transition-duration: .3s }
.speed-slow { transition-duration: .375s }
.speed-slower { transition-duration: .5s }
.speed-lazy { transition-duration: .75s }
But we recomend to apply transitions in SCSS files. To do that use transition()
and complex-transition()
functions.
Function transition()
returns transition based on $property
, $speed
, $timings
and $delay
params. Only first one param is required, others are by default base => .3s
, ease
and 0s
. Function searches params in $transition-speed
and $transition-timings
maps, but you could pass whatever you want. We advice you to pass predefined $speed
and $timing
values tho. Here are some examples of usage:
transition: transition(transform);
// => transition: transform 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
transition: transition(opacity, short, ease-in);
// => transition: opacity 0.25s cubic-bezier(0.42, 0, 1, 1);
transition: transition(background-color, slow, emphasized);
// => transition: background-color 0.375s cubic-bezier(0, 0, 0.2, 1);
transition: transition(color, lazy, linear, 1s);
// => transition: color 0.75s cubic-bezier(0, 0, 1, 1) 1s;
transition: transition(box-shadow, 2s, cubic-bezier(.08,1.04,.82,-0.73));
// => transition: box-shadow 2s cubic-bezier(.08,1.04,.82,-0.73);
If you need apply many transitions at once we recomend to use complex-transition()
function. It does basically the same as previous one, but you can write many transitions in clear and fancy way like this:
transition: complex-transition(
transition(opacity, short, ease-in),
transition(background-color, slow, emphasized),
transition(color, lazy, linear, 1s),
);
// => transition: opacity 0.25s cubic-bezier(0.42, 0, 1, 1), background-color 0.375s cubic-bezier(0, 0, 0.2, 1), color 0.75s cubic-bezier(0, 0, 1, 1) 1s;
We have prepared a mixin that will make it easier for you to write and manage animations in your project. To include animation to selector use @animation($name, $duration, $delay, $count, $direction, $timing, $mode, $state)
mixin, where:
$name
- name of animation.$duration
- duration of animation. Could be predefined value from$transition-speed
map located in _varaibles.scss file or any other value in seconds (s) or miliseconds (ms).$delay
- specifies the amount of time in seconds (s) or miliseconds (ms) to wait from applying the animation to an element before beginning to perform the animation. By default it is equal to 0.$count
- sets the number of times an animation sequence should be played before stopping. Default is 1 time.$direction
- sets whether an animation should play forward, backward, or alternate back and forth between playing the sequence forward and backward. By default is set to "normal".$timing
- sets how an animation progresses through the duration of each cycle. Could be predefined value from$transition-timings
map located in _varaibles.scss file or any transition you want. Default is 'ease-in'.$mode
- sets how a CSS animation applies styles to its target before and after its execution. Default is 'forwards'.$state
- sets whether an animation is running or paused. By default it's 'running' state.
If you are not sure what each of parameters means check out MDN Docs for in-depth explanation.
Now let's take a look at example of usage:
@include animation(
$name: spin,
$duration: slow,
$delay: 1s,
$count: infinite,
$direction: reverse,
$timing: emphasized
$state: paused
);
// =>
animation: spin 0.375s cubic-bezier(0, 0, 0.2, 1) 1s infinite reverse forwards paused;
Only first two parameters are required, so you can shorten mixin like that if your are okay with default values:
@include animation(
$name: spin,
$duration: 2s
);
// =>
animation: spin 2s cubic-bezier(0.42, 0, 1, 1) 0s 1 normal forwards;
Often you need to rotate element by some degree. In CSS you may use transform: rotate()
for that. NightPack provides some utility classnames to make it a little bit easier.
Most common rotation angles are: 0°
, 90°
, 180°
, 270°
and 360°
.
For each angle NightPack generates classname with pattern .rotate-${direction}-${angle}
, where direction
might be minus
or plus
:
.rotate-minus-270 { transform: rotate(-270deg) }
.rotate-minus-180 { transform: rotate(-180deg) }
.rotate-minus-90 { transform: rotate(-90deg) }
.rotate-0 { transform: rotate(0deg) }
.rotate-plus-90 { transform: rotate(90deg) }
.rotate-plus-180 { transform: rotate(180deg) }
.rotate-plus-270 { transform: rotate(270deg) }
.rotate-plus-360 { transform: rotate(360deg) }
In this section are collected small helpers which didn't find a place in the sections listed above. These classnames are described in _utilities.scss file:
.cursor-pointer { cursor: pointer }
.cursor-help { cursor: help }
.cursor-wait { cursor: wait }
.cursor-move { cursor: move }
.cursor-not-allowed { cursor: not-allowed }
.cursor-context-menu { cursor: context-menu }
.cursor-alias { cursor: alias }
.no-select { user-select: none }
.no-overflow { overflow: hidden }
.no-events { pointer-events: none }
.visible { visibility: visible }
.invisible { visibility: hidden }