J2c
CSS in JS library, tiny yet featureful
Install / Use
/learn @j2css/J2cREADME
j2c

A lean, no hassle CSS in JS solution.
Scales from standalone use to isomorphic apps. Compatible with any framework/view library.
Supports building either inline styles of full style sheets.
In sheet mode, j2c follows a 'local by default' approach to make it easier to write components without having to worry about class and animation names clashes.
Like SASS, LESS and Stylus, j2c supports:
- mixins
@extend- nested selectors (in
sheetmode)
All standard CSS at-rules are available out of the box, most importantly:
@mediaand@supportscan be nested anywhere in the sheet@keyframes(with automatic generation of@-webkit-keyframes)@font-face
The home page has a few interactive demos.
Table of Contents
- Installation
- Usage
- Inserting a stylesheet in a document
- Isomorphic app support
- Limitations
- TODO
- License: MIT
Installation
$ npm install j2c
then
var j2c = require('j2c')
There are also separate builds for AMD, ES6 and a global window.j2c in the dist directory.
Usage
j2c can be used to either assemble inline declarations or full style sheets with, by default, locally unique class names.
Here's an example of locallized class names (as pioneered AFAIK by JSS):
sheet = j2c.sheet({
".title": {
font_size: "3rem",
"&:before": {
color: "#00b",
content: "'#'"
}
},
".content": {
line_height: "1.6em",
padding: "2rem"
}
});
Unique class names are generated automatically for title and content:
.content_j2c_fvp6zc2gdj35evhsl73ffzq_0 {
line-height: 1.6em;
padding: 2rem;
}
.title_j2c_fvp6zc2gdj35evhsl73ffzq_0 {
font-size: 3rem;
}
.title_j2c_fvp6zc2gdj35evhsl73ffzq_0:before {
content: '#';
color: #888;
}
sheet is now a String object with a title and content properties that hold the unique class names. It can be used like this in your view, either on the server, in the browser of for isomorphic apps (let's say this is part of a React view):
<div>
<style>{sheet}</style>
<h3 class="{sheet.title}">Hello</h3>
<div class="{sheet.content}">Foo bar baz...</div>
</div>
The <style>{sheet}</style> construct works in modernish browsers (ie9+). For older IE, see below.
Animation names are also "localized" by default, font names are left untouched.
For inline declarations: j2c.inline(declarations)
The j2c function takes in JS objects and builds a property:value; list out of it.
j2c.inline({
backgroundColor:"red",
border: {
top$left: {
width: "1px",
color: "white"
}
}
})
Outputs, as you could expect (white space added for readability):
background-color: red;
border-top-color: white;
border-top-width: 1px;
border-left-color: white;
border-left-width: 1px;
CamelCase and _snake_case names are turned into -dash-case, so that property names can be left unquoted in the source.
Combine (sub)properties who share the same value by using $ as a separator. It is useful to specify vendor prefixes.
Property ordering
Provided you don't delete and re-add properties to your objects, the properties will end up in the CSS sheet in the source order.
Arrays for value overloading and mixins
You can sneak in arrays anywhere in the source tree. It enables many advanced techniques, like:
Overloading properties
If you want to overload a property by using an array at the value level
j2c.inline({
border_color: ["#33e", "rgba(64,64,255,0.8)"],
})
becomes
border-color:#33e;
border-color:rgba(64,64,255,0.8);
Alternatively:
j2c.inline([
{ border_color: "#33e"},
{ border_color: "rgba(64,64,255,0.8)"}
])
and
j2c.inline({
border:[
{color: "#33e"},
{color: "rgba(64,64,255,0.8)"}
]
})
will give the same result.
Mixins
You can mix in properties by using a function call in an array:
function mixin(color) {
return {
border_color: color,
color: color
}
}
j2c.inline([
mixin("red"),
{
font_size:"2em"
}
])
'color:red;
border-color:red;
font-size:2em;'
The mixin could also be a plain JS object if it doesn't need to be customized.
For building a style sheet: j2c.sheet(rules)
Everything found in the inline section applies here too, I recommend you read it first.
To give you a taste of what can be done in j2c, here's a first, rather advanced example.
s = j2c.sheet({
"ul.foo": {
"@media condition": {
color: "red"
},
// properties for the main ul.my_root_class elements
font: {
size: "2em",
family: "sans-serif"
},
// underscores in property names are converted to dashes.
background_color: "#44f",
// CamelCase is also automatically handled.
borderRadius:"2px",
// sub-selector for children element, notice the mandatory initial space
// signifying a child element.
" li": {
padding:{
left: "5px",
top: "10px"
},
// convenient $ shortcut.
border: {left$right: {width: "2px"}}
}
}
})
Output (after indentation):
ul.foo_j2c_fgdl0s2a5fmle5g56rbuax71_0 li{
padding-left:5px;
padding-top:10px;
border-left-width:2px;
border-right-width:2px;
}
ul.foo_j2c_fgdl0s2a5fmle5g56rbuax71_0{
font-size:2em;
font-family:sans-serif;
background-color:#44f;
}
@media condition{
ul.foo_j2c_fgdl0s2a5fmle5g56rbuax71_0{
color:red;
}
}
Were s.foo === "foo_j2c_fgdl0s2a5fmle5g56rbuax71_0 "
Global class and animation names.
You can define or refer to global names using the @global{} pseudo at-rule, and the :global() function. This will thus preserve the .foo, .bar and baz names:
s = j2c.sheet({
"@global": {
"ul.foo": {
font_size: "2em",
}
},
"p:global(.bar)" :{
color:"#f00",
animation_name: ":global(baz)"
},
"@keyframes :global(baz)": {
// define the global "baz" animation here.
}
})
@global blocks also globalize animation names (not shown above).
Combining multiple selectors
TODO: refactor this section to mention the SASS-like & placeholder (at any arbitrary position).
Here's a excerpt from the j2c port of the PocketGrid.
j2c.sheet({"@global": {
".block,.blockgroup":{
",:before,:after":{ // Notice the initial comma.
box_sizing:"border-box"
}
}
}})
Nesting ",:before,:after" inside the ".block,.blockgroup" block combines [".block", ".blockgroup"] with ["", ":before", ":after"], giving
.block,.block:before,.block:after,.blockgroup,.blockgroup:before,.blockgroup:after{
box-sizing:border-box;
}
Mathy folks call this as a Cartesian product.
At-rules
j2c handles @-rules out of the box, including nested ones.
j2c.sheet({
"@media screen": {
" p": {
foo:"bar",
"@media (orientation: landscape)": {
baz:"qux"
}
}
}
})
becomes
@media screen {
p {
foo: bar;
}
@media (orientation: landscape) {
p {
baz: qux;
}
}
}
For @keyframes rules, a @-webkit-keyframes block is automatically created with auto-prefixed property names.
Mixins and @extend
Mixins and @extend make j2c sheets composable. Both techniques can be combined.
Mixins and source objects composition
For mixins, arrays works the same way at the selector level as they do at the property/value one. You can therefore use the method described in the "inline" section to c
Related Skills
node-connect
347.6kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
108.4kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
347.6kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
347.6kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
