DEV Community

Cover image for I created my own Pure CSS Micro-Framework, a tale πŸ™ƒ
Felippe Regazio
Felippe Regazio

Posted on • Edited on

I created my own Pure CSS Micro-Framework, a tale πŸ™ƒ

Cover Photo by Kelly Sikkema on Unsplash

But Why?

Ok, thats a Funny story. But, first of all, here is the link in case you are curious about the result: https://felippe-regazio.github.io/plume-css/. I called it Plume-CSS. You can install it using NPM, Yarn or you can just download the package and load the styles on your document, check the link to know more about. On this post i want to talk about how i started writing some basic styles and features and ended up with a micro-framework S:

Plume-CSS?

I started to build this micro-framework as a personal study. But things scaled very fast as i got more and more excited while coding it. The original idea was to create a Basic CSS file to use as a tiny framework when starting simple and small projects, or just as a fast start point to grow solid. Something like Skeleton and Milligram, or even small.

Just pure CSS and a basic set of directly styled elements, nothing more. No bunch of classes, no JS. The only difference is that Plume would be scoped, the styles should be applied under a main class. Plume should also style a larger set of elements, as progress, meter, checkboxes, radio, fieldsets, etc. And i quickly made it, but i didn't stop.

I styled a large set of native HTML elements (almost all of them) with a clean and basic style. The styles were applied under the class plume. In this same week i wrote the post CSS Custom Properties (vars) with SASS/SCSS, a practical architecture strategy exposing some ideas in SASS architecture for themeable projects.

So i thought "Hey, Plume should be themeable too. I should apply the ideas described on my last post on this study".

Getting Themeable

So i turned my tiny css framework into a themeable tiny framework. I mapped the main characteristics of a basic css design project and turned into a set off CSS Custom Properties on the :root. Then i used this custom properties to style the elements.

Also i used the custom properties to define the elements specific styles as Buttons, Checkboxes and Radio, and to create pseudo inputs as the Input Toggle, for example (Yes, pure CSS). I ended up with a set of 70+ CSS Custom Props working together to build the framework default appearance. If you are familiarized with CSS Custom Props, you know that represents a high customization power.

Then i thought "Its annoying to code the themes while creating them, we change things a lot and have to keeping overriding a lot of props on the code and checking if its all ok. Would be cool to have a Theme Editor with a live visual feedback.

Theme Editor

That was the hardest part. Basically its an UI-Kit (all styled elements putted on a same page - as a demo) and a side menu containing a Form.

Every input on the form controls a different CSS Custom Property. So, as you tune the properties using the Theme Editor, the property is overrided and the page style is automatically updated, giving you an immediate visual feedback.

That was tricky because the binding between the input and the properties are not hard coded. The Theme Editor extracts the Plume-CSS from the page style, then extract all the CSS Custom Properties on the :root scope, converts them it into a JSON and use this Json to build a Form. You can also see the auto generated theme source code, or download it.

After all, i had to persist the Theme somewhere. As im using GitHub pages, i have no database, and Local Storage would be a bad idea (what if i want to show my theme to a friend?). The solution was to persist the theme in the URL:

For each theme changing event, the Theme Editor will save its state on the URL by converting the current form into a Query String (GET Style), compressing it using lz-string compression, and attaching it to the URL. When i load the page, i just invert process: i get the URL, decode it and use the result to fill the form. Now, Themes are stored in the URL.

You can check the Theme Editor by visiting the Plume link on the beginning of this article and clicking on the top left button. The bottom left button is a list of already-made Themes that you can load.

The Prefixer

At this point i was like "man, i need to stop tuning this thing, i already made a lot compared to my initial idea". But then a concern popped in my mind:

If i want this micro-framework to be fully-scoped, i cant just use a wrapper class. I'll need to prefix all the classes, data-properties and other selectors to really avoid collision. As the styles are applied on bare elements, all the classes and data-properties are just atomic utilities, its better to prefix it.

Also, the prefix must be configurable. In this cases, the most common approach is to prefix directly on the .scss files. With this in mind, i had 2 options:

  1. Define mixins and functions that output the selectors already prefixed
  2. Define just a $prefix var and use along the code

The two approaches was bad for me. First because introduces a new law on my code, modifying an important common way to do something. Thats bad. Second because would be a very, very, very ugly code.

So, the solution was: prefix at compile time. Im using gulp to put the peaces together on this project. So, i could use it to prefix the resultant CSS: with this in mind, i built a prefixer, and then turned my prefixer into a gulp-prefixer. The ideia was:

Code the sass normally, compile the entire code to css, and use the prefixer to parse the stream prefixing everything in compile time. Then finally save the output.

And it worked. This led me to create a plume.config.js as a simple manner to configure everything.

A Configuration File

So, i decided to not hard code anything. To do it, a simple plume.config.js was introduced, containing the following options:

module.exports = {
  superclass: 'plume',
  outputStyle: 'compressed',
  targetDirName: 'lib',
  prefixer: {
    prefix: 'pm-',
    ignore: ['.plume'],
  }
}
Enter fullscreen mode Exit fullscreen mode

The superclass will be injected on the beginning of the sass files as a variable: $superclass. A sass mixin on the project will use this variable to scope the modules on the plume class, by default. So, this is the wrapper class.

The outputStyle is how the sass processor must output the files. The targetDirName is obvious: where everything will be saved. And then, the prefixer.

You choose your prefix, and pass selectors to the ignore list (there are advanced options as prefix only classes, or only data-attributes). You can also set prefix: false and nothing will be prefixed. The docs also consumes this file and the package.json while being builded to get dynamic information. Now just run a simple npm run build-all and the Micro-Framework and docs will be generated.

We're done!

Uow, that was a lot. One thing led to another, and as i was very excited while coding all the ideas, so i just kept coding. Most of this concepts and strategies are not new, but it was - in first of all - a study case. Was very cool to implement everything from the scratch.

The result was better then i ever could imagine, and i think it could be useful for the community, not only as a CSS Micro-Framework (we have a lot of them), but as a reference, start point, study example, etc.

At the end i got a light, highly themeabe, flexible, completely scoped CSS Micro-Framework. And, as i said, i called it Plume-CSS.

Plume is availabe under GPL License. The code lives on Here:
https://github.com/felippe-regazio/plume-css

Installation and usage docs can be found here:
https://felippe-regazio.github.io/plume-css/

I also put an effort to documenting everything. You will find the docs on the GitHub Page. Technical and Development documentation on the Repository README.md. Feel free to use it as you want, or to contribute.

Top comments (28)

Collapse
 
jeffjadulco profile image
Jeff Jadulco

This is nice! There's a bit of inconsistency though. The meter and progress seemed off compared to the rest. I'm using Firefox. Here's the screenshot: gyazo link

Collapse
 
felipperegazio profile image
Felippe Regazio • Edited

Uow, thats true. What firefox version? I tested with the last one. Also, meter and progress are hard to style natively, and all components are directly styled, there is no opinionated architecture or imposed html structure to build fake elements. This is not wrong of course, but this framework is just not intended to that. Meter and Progress are styled using vendor prefixes, maybe your version doesnt support those vendors yet, ill wait to know about which version are you using and try to figure out if has a workaround. Thanks for your feedback :D

Collapse
 
jeffjadulco profile image
Jeff Jadulco

I'm using Firefox 76.0.1 (64-bit). It looks okay on Chrome though. So yeah I think it doesn't support it yet D:

Thread Thread
 
felipperegazio profile image
Felippe Regazio

True. I'll download your version and try to figure out a solution. If all fails, maybe offer a workaround with spans. Thanks again.

Collapse
 
codiagkai profile image
codiag-kai

Hi Felippe,

Awesome post and a cool project. The idea to scope it is soo important for adopting the styles.

Two questions are spinning in my head:

  1. why did you decide against Miligram and Skeleton in the first place

  2. how would you compare plume vs something like MVP.css

Collapse
 
felipperegazio profile image
Felippe Regazio

Hey! Thanks for your comment!

  1. Skeleton and Milligram are micro-frameworks that i use to fast-build small projects. As there were some points there i would like to be different and i were already experimenting different styling approaches, they automatically became an inspiration.

  2. I didnt know MPV.css. Looks great! MVP.css sure will be a reference for the future. I want a no-classes frameworks by default too, just semantic HTML. MVP seems more mature in this point. I think that the main difference is that Plume is Scoped (as you pointed), but i assume thats easy to achieve with MVP.css. Plume has a larger set of elements styled, also with more consistence (at a first sight): andybrewer.github.io/mvp/mvp.html. The available props to customize are easier to tune on MVP, but Plume seems more complete at this point, but at here i think is more about taste: do you want props or do you want to override selectors? Despite the semantic approach, Plume's also has a nice set of utilities. But at the end, i think its all about your taste and needing. MVP seems really great.

Collapse
 
louislow profile image
Louis Low • Edited

Great work! I can see the plume.css is a component-based framework. Waiting for your new component collection soon. You earned a star at Github, from me.

Collapse
 
felipperegazio profile image
Felippe Regazio

Yes, i have a solid plan to write a "plume components-js" lib also with a simple set of plume-based components using JS web components to encapsulate complex behaviors. Many thanks Loouis :D

Collapse
 
dhintz89 profile image
Daniel Hintz

I just wrote an article about my experience trying out Plume. Spoiler alert: I love it! So simple, but very powerful. Amazing job!

Also, now that I've randomly stumbled into this article and got to read about the backstory, I love it even more. πŸ˜„

Collapse
 
madeindra profile image
Made Indra

This is neat! I like the style you used, gonna star this on github so I can go back when I need to create a web using this style. Thanks!

Collapse
 
felipperegazio profile image
Felippe Regazio • Edited

Thanks Made! Take a look on the bottom left button on the project github page, its a menu with some custom themes to toggle that you might also like ; )

Collapse
 
manishfoodtechs profile image
manish srivastava

Nice work. Plume- css seems too promising. Please add datatable ui ... search indexing etc

Collapse
 
felipperegazio profile image
Felippe Regazio

Would be cool to build some components based on Plume style. But implement a datatable or search indexing i believe it would be problematic since Plume is a pure CSS lib

Collapse
 
moopet profile image
Ben Sinclair

Can you disable the scoping?

Collapse
 
felipperegazio profile image
Felippe Regazio • Edited

Hello Ben, yes its possible. You must clone the Gihub Repository, then in the file "plume.config.js" you must set the { superclass: ... } to "" and the { prefixer: ... } to false. Then run:

npm install
npm run build-all

By doing this, styles will be applied on body instead of the "plume" class (or one designated by you), and the selectors wont be prefixed.

Collapse
 
emanuelgsouza profile image
Emanuel Gonçalves

That's amazing job! Very interesting! I will test it!

Collapse
 
mikaelgramont profile image
Mikael Gramont

This looks flexible enough that I could see myself use it next time I start a project from scratch.
That, and it seems to work like a "regular" CSS framework.

Well done!

Collapse
 
felipperegazio profile image
Felippe Regazio • Edited

Many thanks Mikael! Happy to read that. I thought a lot about if this is a framework or a micro-framework, but there is no grid-system (as a choice), no optionated architecture, no components (cards, menus, sidebars, etc). At the end its just pure and native HTML elements and CSS. A framework for those who like to code the things from scratch, maybe? So i called a micro framework (but i dont know), and yeah, its a pretty complete one haha.

Collapse
 
chanmyaemaung profile image
Chen Lay

Congratulations! You did a great job.

Collapse
 
felipperegazio profile image
Felippe Regazio

uow, thank you Chan!