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:
- Define mixins and functions that output the selectors already prefixed
- 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'],
}
}
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)
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
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
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:
True. I'll download your version and try to figure out a solution. If all fails, maybe offer a workaround with spans. Thanks again.
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:
why did you decide against Miligram and Skeleton in the first place
how would you compare plume vs something like MVP.css
Hey! Thanks for your comment!
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.
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.
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.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
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. ๐
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!
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 ; )
Nice work. Plume- css seems too promising. Please add datatable ui ... search indexing etc
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
Can you disable the scoping?
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.
That's amazing job! Very interesting! I will test it!
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!
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.
Congratulations! You did a great job.
uow, thank you Chan!