Skip to content

Customizing Vulk

Philosophy

Vulk is built to be an extremely modular and flexible product. Layouts have been destructured so you can easily switch between them, without breaking your page content. Therefore, page inner content is considered as an aggregate of components that get injected in the currently active layout.

Vulk ships with a Quickstarter project. The Quickstarter is a smaller project that contains only what you need to get started with a lighter and less overwhelming codebase. The recommended way of working is to open both projects, and start copying and pasting what you need from the main Vulk project to the Quickstarter project.

Hybrid Sass

bash
 my-vulk-quickstarter-project/
├── src/
   ├── scss
   ├── abstracts
   ├── bulma-generated
   ├── css-variables
   ├── utilities
   └── main.scss
   └── main.ts
└── index.html

Vulk comes with a great paradigm change regarding the initial Bulma, in terms of Sass implementation. While everyone is familiar with traditional Sass variables like $color, we chose to drop this format to take advantage of the power of native CSS-vars. To support this, we had to make several major changes in the way we handle the compilation of the different color palettes.

The main Bulma framework is built with traditional Sass variables and does not support CSS-vars. We had to find a solution for this. Therefore, we decided to enhance our existing Bulma package with this Bulma plugin: https://github.com/wtho/bulma-css-vars. This plugin fully supports CSS-vars and patches the initial Bulma code base, making possible this implementation.

There are 2 variables sub-folders in Vulk: scss/bulma-generated/ and scss/css-variables. The first one is automatically rendered by a Node.js utility and is in charge of generating all the Bulma variables, based on your configuration.

Changing the main color

If you need to change the Vulk main color, you need to go through a short compilation step. The main color is generated from an HSL format. This means that you will need to define your Vulk primary color in HSL format for it to work. Here are the different steps you need to go through:

  • Choose a primary color for your project. It can be in hex or rgb format, it doesn't matter. Let's go for the example with a purple color like #6621cf.
  • In any colorpicker of your choice, transform your color into an HSL color with a value for each attribute, Hue, Saturation and Luminance. In our case this would result in 264°, 73%, 47%.
  • Open vulk/bulma-css-vars.config.js. In that file replace the values of the primary: hsl(153, 48, 49) block with the values you got one step earlier. You can also change the default values of some basic Bulma variables like dark, link, info etc...
  • Once you're done with that, you're ready to run a utility to generate all your colors.
  • In your terminal, run the pnpm build:update-bulma-colors.
  • Tada! You are now done and all your new colors have been generated for you.
  • Please note that you will also need to change the value of the primary variable inside vulk/src/scss/css-variables/_colors.scss to complete the color setup.

CSS vars syntax

CSS variables use a different syntax than Sass variables. Declaring a new CSS variable is like this:

Declaration

scss
// :root is an alias for html element but with higher priority
:root {
  --myVariable: #fff;
}
scss
// we can override the variable value inside a class scope
.my-red-variable {
  --myVariable: red;
}
html
<!-- we can also override the variable value inside a style scope -->
<span style="--myVariable: blue">
  <!-- ... -->
</span>

Usage

scss
.my-variable-color {
  color: var(--myVariable);
}

Overriding CSS vars

CSS variables are very flexible and can be overridden from almost everywhere, without affecting other components. For example, let's say that you have a component called <SuperButton></SuperButton> and that component has a scoped style attribute (<style lang="scss" scoped></style>), meaning the styles are strictly scoped to that same component. You can override the base --primary variable inside the component without affecting any other one outside the scope of this one. For example, you can do:

vue
<!-- SuperButton.vue -->
<template>
  <button class="super-button">
    <!-- ... -->
  </button>
</template>

<style lang="scss" scoped>
.super-button {
  --primary: blue;
}
</style>

Other Sass files

Vulk relies on the powerful Sass features and a modular structure, letting you handle complex styles in a breeze. You need to import all the SCSS partials into your core file. This is how SCSS files are organized. Partial SCSS file names always start with an underscore like this: _button.scss . They act as chunks of code that you can import only if you need them.

Import styles in Vue

In order to load stylesheets into our application (e.g if you need to add additional styles from a node_modules plugin), we simply need to import css, sass or scss files in the src/styles.ts file. This file is included in your bundle because it is referenced inside root index.html file

typescript
// file: ./src/styles.ts

// ...
import "vue3-carousel/dist/carousel.css";

import "./scss/main.scss";
// ...

All imported files here are to be converted in css, and injected automatically in index.html at build and run time. The injected styles are available globally.

Bulma Integration

Classic Bulma used to be initially integrated with Vulk. This meant that when you changed the $primary Vulk color variable, it took precedence over any Bulma related variable. Vulk now fully supports native CSS variables and dropped Sass variables support during the development phase.

Native Dark Mode

Vulk comes with a native Dark mode. This means that all components are pre-styled for dark mode. You don't have to worry about it, when you turn it on, the colors change seamlessly. Dark mode styling is made through a global .is-dark class added to the page <html> root element. Dark mode is toggled on the body with javascript. In another type of implementation, the body would have to be rendered by the server with the proper class before being served to the client, based on the user selection.

TIP

.is-dark class is not restricted to <html> element, you can add this class to any element, so all childrens will be in dark mode!

Dark Mode and CSS vars

With the introduction of CSS vars, Dark Mode is now handled at the color level. You can control how a CSS variable behaves at runtime, based on the parent classes. For example let's says we have a CSS variable like this: --color: red. We can change the value of this color in dark mode by editing the variable, preventing us to write additional dark mode CSS code.

scss
// Normal mode
:root {
  --color: red;
}

// Dark mode
.is-dark {
  --color: blue;
}

Lazyloading SCSS

bash
 my-vulk-quickstarter-project/
├── src/
   ├── components/
   └── some-component/*.vue

The components folder holds the vue components stored as chunks of reusable UI that can be inserted in all available layout types. Each element is a Vue 3 component with a <style> element that holds required SCSS. This way, you do not load unnecessary CSS when browsing.

They are not added by default to main.scss, instead we lazyload them:

vue
<!-- file ./src/components/my-component/MyComponent.vue -->
<script setup lang="ts">
// ...
</script>

<template>
  <!-- ... -->
</template>

<style lang="scss">
.my-component-wrapper {
  /* custom scss for this component */
  &:hover {
    color: var(--primary);
  }
}
</style>

Vue Components

Vue 3 being very powerful, we built Vulk so you don't have to worry about moving components from a folder to another or from a project to another. It is as simple as copying and pasting your components in the target folder. Because this project uses the unplugin-vite-components, all your components are parsed and available in your pages and other components without a single import statement. We kept the components CSS out of the .vue files so it is easier for you to explore the template styles and to adapt them to your needs.

However, we recommend that when you build your own project with Vulk, you take advantage of the .vue files potential by scoping your styles to your component, like we do with the page components. This way, the component styles are only loaded when the component is displayed.

vue
<script setup lang="ts">
export type MyComponentColors = 'red' | 'blue' | 'green'

export interface MyComponentsProps = {
  color?: MyComponentColors
  label: string
}

const props = defineProps<MyComponentsProps>();
</script>

<template>
  <button class="button" :class="[props.color && `is-${props.color}`]">
    {{ props.label }}
  </button>
</template>

<style lang="scss" scoped>
.button {
  &.is-red {
    color: var(--red);
  }

  &.is-blue {
    color: var(--blue);
  }

  &.is-green {
    color: var(--green);
  }

  &.is-purple {
    color: var(--purple);
  }
}
</style>

All Rights Reserved