Open oscarotero opened 2 months ago
In this issue, we want to discuss the best way to store and organize CSS packages for better reusability.
I like this as the initial goal.
- Every package has a README.md file with the description of the package, how to use it, the author, etc.
I am not certain we need readmes, other than:
- Is this file enough? Do we need a more structured format (like JSON, toml, etc) to store info like author, license, etc?
Always bugs me that the license file has to be included separately after specifying it in package.json (or specified after adding the license file, however one looks at it), maybe we can avoid that duplication and repetition by using a standardized comment at the top of the CSS or HTML file for all metadata? Seems like you are already leaning this way and there is precedent like style.css in WP themes or JSDoc.
Some package registries have the concept of "scope" to group different packages under the same scope (scopes used to be the author name or a framework with several packages) making the paths a bit bigger
<scope>/<package>/<module>
. Do we need it? The problem I see is not all packages need a scope. It's pretty common to see scopes and packages with the same name. An alternative solution could be to allow submodules if needed. For example:<package>/<module>/<submodule>
. This would fit well for simple packages (with just one module) and big packages with many modules and submodules.
On one hand leaving out scope makes things easier all around, and submodules fit better with the cascade design of CSS itself, and history of CSS modules.
On the other hand everyone ends up adding scopes later on anyway, so by leaving it out are we doomed to add it more awkwardly in the future?
The current modules are stored in HTML files. HTML is a very versatile format that can contain stuff of different types. The HTML follows the following structure:
<!-- Comment with the module description in markdown format. --> <p>HTML elements for the demo</p> <style> .host { /* User settings */ ... /* Implementation */ ... } </style> <style> /* Additional styles only for the demo */ </style>
We use an HTML comment to include a description of the module in markdown format.
- Is this enough? Should we have a more structured format like JSON or YAML?
The first
<style>
element is considered the code of the module. It's the code that you will get when importing the module into your project.Additional
<style>
elements are considered styles for the demo but don't belong to the module. They are ignored when importing the module into a project.This format allows us to store not only the CSS code of the module but also everything needed to test the code in a browser in just a single file. It works out of the box, without any tooling, just open this file in a browser and you will see a demo of the module.
This is clever in many ways but I think slightly too clever for its own good. My most immediate suggestion is to make the first style tag an import
instead, so that the CSS code we care about is self-contained in a CSS file I can import, or throw on a CDN, or open in an editor, select all, copy, and paste whenever I want without having to fussily select the contents of the first style tag.
- What happens if in our code we are using the same CSS properties for another purpose? Should we encourage the use of underscored property names?
Underscores are interesting, as would be an enforced namespace like the .host
class, maybe host_
? Then it’s easier to swap with find and replace?
In the current format, this class is always
.host
. This allows us to replace it with something else easily.In the vs code plugin, when a module is imported, the
.host
class is replaced with a class following the.<package>_<module>
pattern (see video), and the class is automatically selected to easily edit it.This method would allow us to, for example, import a module from a CDN with a custom class name. Example:
@import "https://cdn.css.gal/<package>/<module>.css?class=my-class-name";
This sounds great so we nest everything under host? Nesting selector only when necessary or encouraged always?
.host {
--host_border: 1px solid black;
--host_border-radius: 0.5rem;
--host_family: Baskerville;
--host_style: italic;
border: var(--host_border);
border-radius: var(--host_border-radius);
& figcaption {
font-family: var(--host_family);
font-style: var(--host_style);
}
}
You'll definitely want to do user/organisation level scopes, not doing that from the get-go with npm was a mistake (something deno's jsr fixed).
tbh, npm should've dropped the ability to create new scopeless packages years ago, imo.
@rdela Thanks for your comments!
I am not certain we need readmes,
Maybe they don't have to be mandatory, but I think most packages will need some contextual information (the purpose of the project, links to the homepage, how to use it, etc). And README.md files are like a standard, they work out of the box everywhere.
Always bugs me that the license file has to be included separately after specifying it in package.json (or specified after adding the license file, however one looks at it)
My idea was to avoid a package.json
-like file in order to make it more simple to publish packages and place everything in a readme file (even the license). But maybe it's too simple?
On the other hand everyone ends up adding scopes later on anyway, so by leaving it out are we doomed to add it more awkwardly in the future?
Yup. In practice <scope>/<package>/<module>
is the same as <package>/<module>/<submodule>
. So I think it's a matter of naming. As an idea, there might be packages with only one module (or we can allow to configure the "main" module), so it could be access from <scope>/<package>
(without specifying the module). And even "main" package of a scope so we can import just the scope. (just thinking out loud).
This is clever in many ways but I think slightly too clever for its own good.
Yes, after thinking more about this, I agree with you. Maybe the html should contain only the demo code and import the module code with <link re="stylesheet">
or @import
.
Underscores are interesting, as would be an enforced namespace like the .host class, maybe host_?
That's a good point. Underscores use to be used for internal or hidden stuff. And these custom properties work like a public API, intended for customization. host_
prefix seems a better option, but maybe too long for my taste.
Nesting selector only when necessary or encouraged always?
There are some cases in which Nesting selector doesn't fit well (for example reset/normalize libraries), but I'd encourage them whenever possible. It's supported by all browser and easy to flat them with a css processor like postcss.
@ThisIsMissEm The purpose was to avoid import things like normalize.css/normalize.css/normalize.css
(scope/package/module) that could be possible for single files packages. But I see your point.
An option is to allow to define a default module and package, so if it's omited, the default value will be served. So you can import normalize.css
, normalize.css/normalize.css
or normalize.css/normalize.css/normalize.css
and in all cases, you're importing the same code.
Looking at normalize.css
, I'd guess the published package would be necolas/normalize.css/normalize.css
, though, arguably in a module/package system, you should be able to just do necolas/normalize.css
and load the default entrypoint.
i.e., necolas is the owner of that package.
In this issue, we want to discuss the best way to store and organize CSS packages for better reusability.
How to organize the code
Currently, the registry works in the following way.
<package>/<module>
syntax. I.e.animate.css/bounce
.How to store modules?
The current modules are stored in HTML files. HTML is a very versatile format that can contain stuff of different types. The HTML follows the following structure:
<style>
element is considered the code of the module. It's the code that you will get when importing the module into your project.<style>
elements are considered styles for the demo but don't belong to the module. They are ignored when importing the module into a project.This format allows us to store not only the CSS code of the module but also everything needed to test the code in a browser in just a single file. It works out of the box, without any tooling, just open this file in a browser and you will see a demo of the module.
How to create the CSS code
The CSS code should be the most flexible and customizable as possible, CSS properties to configure the behavior are recommended. For example:
How to fix class name conflict?
A CSS module can use a class name in the selector that is already being used in your project, which causes a conflict. This is why the code of the module must use the CSS nesting style to only declare the class once, so it's easier to change:
In the current format, this class is always
.host
. This allows us to replace it with something else easily. In the vs code plugin, when a module is imported, the.host
class is replaced with a class following the.<package>_<module>
pattern (see video), and the class is automatically selected to easily edit it. This method would allow us to, for example, import a module from a CDN with a custom class name. Example:This is an open discussion, feedback is very welcome!