1549001795
CSS-in-JS refers to a collection of ideas to solve complex problems with CSS. Since it is NOT a particular library, different libs might solve a different subset of problems and use different approaches, depending on their implementation details.
However, all implementations have in common that they tackle the problems using APIs instead of convention and they leverage JavaScript as a language.
CSS historically never had actual modules, neither did JavaScript. Requirements for web applications evolved and JavaScript has added a module system. First in the form of a bolt-on solution (CommonJS), later as a standard, statically analyzable module system known as ECMAScript Modules (ESM).
The reasoning behind modules applies to both JavaScript and CSS: to be able to hide implementation details by exposing only public APIs. We need to be able to decouple subsystems of an application explicitly so that changing code becomes more predictable.
Not every application needs this, but it makes maintaining medium and large applications easier, simplifying modification and deletion of internal implementation details. Problems appear with more complexity, the smaller the application the less complexity it usually contains.
CSS-in-JS relies on JavaScript’s modules implementation.
We know CSS always had a single global namespace, for example, a class can be added to any element, a tag selector can target any element in the document. CSS was initially created to style documents and there was no need for components. The entire page was styled as one big chunk and it usually didn’t involve many people working on it. Since then the complexity of many sites has dramatically increased and this is the main reason why many CSS methodologies were created. None of the conventions is easy to establish and consistently enforce when many people contribute to a project over the years.
Modern websites are complex enough to need many front-end specialists working in separate areas of the site. Those parts are reused across the global site in different ways requiring those blocks to be fully interactive and functional.
The consequence of not having a consistent scoping — styles leaking in an unpredictable manner.
Here is a simplified example of how CSS-in-JS libraries generate a selector:
const css = styleBlock => { const className = someHash(styleBlock); const styleEl = document.createElement('style'); styleEl.textContent = ` .${className} { ${styleBlock} } `; document.head.appendChild(styleEl); return className; }; const className = css(` color: red; padding: 20px; `); // 'c23j4'
CSS-in-JS automates the scoping by generating unique selectors.
CSS offers a rule level code reuse, which means to reuse a style block, a rule has a selector. When selector applies to an element, it applies its entire style block. This is possible in essentially two ways:
1. A CSS rule includes multiple selectors to target different HTML elements.
2. Multiple class names or other attributes are applied to HTML elements, causing them to be targeted by multiple CSS rules.
Neither of those ages well, because both lead to monolithic code structure, where everything depends on everything. It becomes hard to clearly isolate the subsystems.
In the first case, when we add many selectors to a single CSS rule, the rule gets the references to other subsystems. You won’t be able to change those subsystems without touching that rule and it is easy to forget.
In the second case, where we use multiple class names or other attributes, this causes the element to be targeted by multiple CSS rules. This makes the relationship complex again, and again it is easy to forget what needs to be removed.
In both cases, we create dependencies which are hard to understand and change over time without a good strict system in place. It is hard for humans to be that consistent over time.
CSS-in-JS makes dependencies explicit because variables always reference the value in code visually. They are traceable because we can statically analyze where the value comes from. They are granular because we can reuse CSS values, properties or entire style blocks as we see fit.
CSS-in-JS promotes explicit, traceable and granular dependencies.
Due to the implicit relationship between HTML and CSS, it is generally hard to track down unused CSS rules and inform the author or strip them from the bundle. Often you can’t know where the rules have been used. For example, it could be multiple code bases or class names could be conditionally applied from a language that was used to generate HTML or class names have been manipulated by client-side JavaScript.
Over time dead code may have a negative impact on the site performance and the ability of developers to understand the code.
Thanks to explicit, traceable variables and modules in JavaScript, we can implement solutions on top, which create an explicit connection between a CSS rule and the HTML element.
CSS-in-JS helps with removing dead code.
If you build a Single Page Application (SPA) and you split the CSS bundle per page, you can end up with non-deterministic source order specificity. In such situations the order in which CSS is injected depends on user actions, causing selectors to apply unpredictably to the HTML elements.
Imagine you load page A, and then you switch to page B without a full document reload. Technically you loaded CSS-A and then CSS-B. If selectors used in CSS-B supposed to override selectors from CSS-A we are good because CSS for B was loaded later and has a higher source order specificity.
If the next user comes from a link directly to page B, and then switch to page A, CSS-B will be loaded first, and CSS-A afterwards, causing CSS-A to have a higher source order specificity. Now you have to create visual regression tests for any possible navigation among entry points.
To solve this, it helps to tightly couple CSS and HTML, so that we always know what CSS is used by the currently rendered HTML.
CSS-in-JS helps to avoid non-deterministic source order specificity.
The idea to separate the concerns based on a language ignores the fact that CSS was not designed to be truly separated from HTML.
CSS has implicit assumptions about the HTML structure. For example, flexbox layout makes an assumption that containers to position are direct children of the element it was applied to.
When a CSS rule is applied to different HTML elements across our application, we can basically describe it as a “one-to-many relationship”. If you change the CSS rule, you potentially need to modify all related HTML elements.
CSS-in-JS encourages this relationship to be one-to-one, while still keeping the ability to have shared properties. Currently not every CSS-in-JS API enforces one-to-one relationship because many libs support CSS reuse without the corresponding HTML. We need to make developers aware of this!
It doesn’t matter which abstraction you use or none at all, the best way to share CSS is to share the HTML and ensure the CSS it needs gets rendered automatically.
CSS-in-JS encourages the coupling of CSS and HTML.
It is weird because some people refer to CSS as too powerful and some others refer to CSS-in-JS as too powerful regarding a level of abstraction.
The truth is they are both powerful but in different areas. CSS selectors are too powerful because they can target any element across the document. It’s a huge problem since we try to write CSS that has only access to elements within our HTML block or component.
CSS-in-JS helps to constrain that power by scoping its selectors. It is still not a complete solution because those selectors can reach into any child element if a given library supports cascading. It is a good leap forward though towards writing a more constrained CSS by default. Most CSS-in-JS libs support cascading not because its safe, but because it is practical and there are no good alternatives with safety mechanisms so far. Shadow root CSS is still not where it needs to be for mass adoption.
On the other hand, JavaScript is a much more powerful language, because the syntax is more expressive and allows many more patterns and notations. Complex UX logic is often hard to express without having conditionals, functions, and variables. A pure declarative syntax works well when the runtime is highly specialized for the use case, while CSS is used to accomplish a wide variety of tasks.
CSS-in-JS gives the developer more expressiveness while encouraging more maintainable patterns than cascading.
One of the very powerful patterns CSS-in-JS enables is state-based styling. Technically it is usually implemented as a JavaScript function which receives a state object and returns CSS properties. As a result, a CSS rule is generated that corresponds to the state of an element. Compared to a more traditional way, where we build a class attribute containing multiple class names, this has some advantages:
1. Logic responsible for the final CSS rule has access to the state and can be located together with the rest of styles.
2. Logic generating HTML becomes less cluttered by the classes concatenation logic.
Both of these points should make complex state-dependent CSS more readable.
CSS-in-JS gives developers API to describe state-based styles in a better way than using a bunch of conditional class names.
I hope I was able to give you a perspective on the core drivers behind the concept. It is not my intention to judge any technology or to give a complete list of features, which vary between implementations. Also, I am not saying CSS-in-JS is the only future we can have, the point is though that if the community doesn’t understand the problems those tools are trying to solve, how are we going to move forward?
By : Oleg Isonen
#html #css
1632537859
Not babashka. Node.js babashka!?
Ad-hoc CLJS scripting on Node.js.
Experimental. Please report issues here.
Nbb's main goal is to make it easy to get started with ad hoc CLJS scripting on Node.js.
Additional goals and features are:
Nbb requires Node.js v12 or newer.
CLJS code is evaluated through SCI, the same interpreter that powers babashka. Because SCI works with advanced compilation, the bundle size, especially when combined with other dependencies, is smaller than what you get with self-hosted CLJS. That makes startup faster. The trade-off is that execution is less performant and that only a subset of CLJS is available (e.g. no deftype, yet).
Install nbb
from NPM:
$ npm install nbb -g
Omit -g
for a local install.
Try out an expression:
$ nbb -e '(+ 1 2 3)'
6
And then install some other NPM libraries to use in the script. E.g.:
$ npm install csv-parse shelljs zx
Create a script which uses the NPM libraries:
(ns script
(:require ["csv-parse/lib/sync$default" :as csv-parse]
["fs" :as fs]
["path" :as path]
["shelljs$default" :as sh]
["term-size$default" :as term-size]
["zx$default" :as zx]
["zx$fs" :as zxfs]
[nbb.core :refer [*file*]]))
(prn (path/resolve "."))
(prn (term-size))
(println (count (str (fs/readFileSync *file*))))
(prn (sh/ls "."))
(prn (csv-parse "foo,bar"))
(prn (zxfs/existsSync *file*))
(zx/$ #js ["ls"])
Call the script:
$ nbb script.cljs
"/private/tmp/test-script"
#js {:columns 216, :rows 47}
510
#js ["node_modules" "package-lock.json" "package.json" "script.cljs"]
#js [#js ["foo" "bar"]]
true
$ ls
node_modules
package-lock.json
package.json
script.cljs
Nbb has first class support for macros: you can define them right inside your .cljs
file, like you are used to from JVM Clojure. Consider the plet
macro to make working with promises more palatable:
(defmacro plet
[bindings & body]
(let [binding-pairs (reverse (partition 2 bindings))
body (cons 'do body)]
(reduce (fn [body [sym expr]]
(let [expr (list '.resolve 'js/Promise expr)]
(list '.then expr (list 'clojure.core/fn (vector sym)
body))))
body
binding-pairs)))
Using this macro we can look async code more like sync code. Consider this puppeteer example:
(-> (.launch puppeteer)
(.then (fn [browser]
(-> (.newPage browser)
(.then (fn [page]
(-> (.goto page "https://clojure.org")
(.then #(.screenshot page #js{:path "screenshot.png"}))
(.catch #(js/console.log %))
(.then #(.close browser)))))))))
Using plet
this becomes:
(plet [browser (.launch puppeteer)
page (.newPage browser)
_ (.goto page "https://clojure.org")
_ (-> (.screenshot page #js{:path "screenshot.png"})
(.catch #(js/console.log %)))]
(.close browser))
See the puppeteer example for the full code.
Since v0.0.36, nbb includes promesa which is a library to deal with promises. The above plet
macro is similar to promesa.core/let
.
$ time nbb -e '(+ 1 2 3)'
6
nbb -e '(+ 1 2 3)' 0.17s user 0.02s system 109% cpu 0.168 total
The baseline startup time for a script is about 170ms seconds on my laptop. When invoked via npx
this adds another 300ms or so, so for faster startup, either use a globally installed nbb
or use $(npm bin)/nbb script.cljs
to bypass npx
.
Nbb does not depend on any NPM dependencies. All NPM libraries loaded by a script are resolved relative to that script. When using the Reagent module, React is resolved in the same way as any other NPM library.
To load .cljs
files from local paths or dependencies, you can use the --classpath
argument. The current dir is added to the classpath automatically. So if there is a file foo/bar.cljs
relative to your current dir, then you can load it via (:require [foo.bar :as fb])
. Note that nbb
uses the same naming conventions for namespaces and directories as other Clojure tools: foo-bar
in the namespace name becomes foo_bar
in the directory name.
To load dependencies from the Clojure ecosystem, you can use the Clojure CLI or babashka to download them and produce a classpath:
$ classpath="$(clojure -A:nbb -Spath -Sdeps '{:aliases {:nbb {:replace-deps {com.github.seancorfield/honeysql {:git/tag "v2.0.0-rc5" :git/sha "01c3a55"}}}}}')"
and then feed it to the --classpath
argument:
$ nbb --classpath "$classpath" -e "(require '[honey.sql :as sql]) (sql/format {:select :foo :from :bar :where [:= :baz 2]})"
["SELECT foo FROM bar WHERE baz = ?" 2]
Currently nbb
only reads from directories, not jar files, so you are encouraged to use git libs. Support for .jar
files will be added later.
The name of the file that is currently being executed is available via nbb.core/*file*
or on the metadata of vars:
(ns foo
(:require [nbb.core :refer [*file*]]))
(prn *file*) ;; "/private/tmp/foo.cljs"
(defn f [])
(prn (:file (meta #'f))) ;; "/private/tmp/foo.cljs"
Nbb includes reagent.core
which will be lazily loaded when required. You can use this together with ink to create a TUI application:
$ npm install ink
ink-demo.cljs
:
(ns ink-demo
(:require ["ink" :refer [render Text]]
[reagent.core :as r]))
(defonce state (r/atom 0))
(doseq [n (range 1 11)]
(js/setTimeout #(swap! state inc) (* n 500)))
(defn hello []
[:> Text {:color "green"} "Hello, world! " @state])
(render (r/as-element [hello]))
Working with callbacks and promises can become tedious. Since nbb v0.0.36 the promesa.core
namespace is included with the let
and do!
macros. An example:
(ns prom
(:require [promesa.core :as p]))
(defn sleep [ms]
(js/Promise.
(fn [resolve _]
(js/setTimeout resolve ms))))
(defn do-stuff
[]
(p/do!
(println "Doing stuff which takes a while")
(sleep 1000)
1))
(p/let [a (do-stuff)
b (inc a)
c (do-stuff)
d (+ b c)]
(prn d))
$ nbb prom.cljs
Doing stuff which takes a while
Doing stuff which takes a while
3
Also see API docs.
Since nbb v0.0.75 applied-science/js-interop is available:
(ns example
(:require [applied-science.js-interop :as j]))
(def o (j/lit {:a 1 :b 2 :c {:d 1}}))
(prn (j/select-keys o [:a :b])) ;; #js {:a 1, :b 2}
(prn (j/get-in o [:c :d])) ;; 1
Most of this library is supported in nbb, except the following:
:syms
.-x
notation. In nbb, you must use keywords.See the example of what is currently supported.
See the examples directory for small examples.
Also check out these projects built with nbb:
See API documentation.
See this gist on how to convert an nbb script or project to shadow-cljs.
Prequisites:
To build:
bb release
Run bb tasks
for more project-related tasks.
Download Details:
Author: borkdude
Download Link: Download The Source Code
Official Website: https://github.com/borkdude/nbb
License: EPL-1.0
#node #javascript
1596530868
Want to develop a website or re-design using CSS Development?
We build a website and we implemented CSS successfully if you are planning to Hire CSS Developer from HourlyDeveloper.io, We can fill your Page with creative colors and attractive Designs. We provide services in Web Designing, Website Redesigning and etc.
For more details…!!
Consult with our experts:- https://bit.ly/3hUdppS
#hire css developer #css development company #css development services #css development #css developer #css
1626694620
#stubborndevelopers
In this video we will learn below points:
************ Node.JS Tutorial in English 2021 Playlist ************
https://www.youtube.com/watch?v=gs0X92Yx70s&list=PLllIEssCHLKdNEVWsBQ5zcCxLu8Xpsl0E&index=2
************ React.JS Tutorial in Hindi 2021 Playlist ************
https://www.youtube.com/watch?v=F2A1qXcskP8&list=PLllIEssCHLKdRqOrDJdPIeW7nrwPPfa46
#node.js #express.stati #css #js #express js
1624284720
These days a lot of my day-to-day work was centered around the loading speed of our pages. And a big bottleneck was unused code. We were serving too much JS and CSS code that was not used by that page.
While looking at how to improve this I’ve discovered how to use the Coverage tab. Great tool!
It’s a bit hidden in the UI. To activate it you will need to press cmd + shift + p
and search in the list for the Coverage tab.
After you run it it will serve you a report like the one below point to the code that is not needed on your page. The blocks marked with red are not used on your page. This will work both for Javascript and CSS.
#performance #js #css #js and css
1603188000
The other day one of our students asked about possibility of having a CSS cheatsheet to help to decide on the best suited approach when doing this or that layout.
This evolved into the idea of making a visual CSS cheatsheet with all (most) of the common patterns we see everyday and one of the best possible conceptual implementation for them.
In the end any layout could and should be split into parts/blocks and we see every block separately.
Here is our first take on that and we would be happy to keep extending it to help us all.
Please, send you suggestions in the comments in community or via gitlab for the repeated CSS patterns with your favourite implementation for that so that we will all together make this as useful as it can be.
#css #css3 #cascading-style-sheets #web-development #html-css #css-grids #learning-css #html-css-basics