A developer-first layout engine for web

· 9 min read

First of all, this article has a bit of a headline, and I apologize to the readers. The headline of this article is the layout engine. But I suggest that you must read this headline party article, and you will definitely gain something after reading it.

Why write this article?#

A few days ago, I released one of my front-end open source projects named: Fower. Many users have asked me what is the difference between Fower and Tailwindcss. My answer is that Fower has the same philosophy in utilty-first. In fact, CSS framework with the utilty-first concept has existed for a long time, such as: ACSS, Tachyons.

One of the biggest differences between Fower and Tailwindcss is that Fower provides a very easy-to-use layout tool: Fower Layout toolkit, which is the reason for writing this article. Below I will share in detail the original intention of developing the Fower layout and its design ideas.

Web layout history#

Let's briefly review the history of Web layout. During the entire evolution of Web layout, we have experienced no layout, table layout, positioning layout, floating layout, Flexbox layout, and Grid layout. I will not elaborate on the characteristics and advantages and disadvantages of each layout here. I will only talk about my personal views and conclusions: at the current stage, considering the functionality, ease of use, browser compatibility, etc., using Flexbox layout is the best choice. Some people who are interested in learning more can read the following article.

The core of the layout#

In my opinion, the core of layout is to deal with the spatial relationship between container and items in a certain direction (x, y). There are four essential elements here: container, element, direction, and spatial relationship. In fact, this is also the core of flexbox layout. Almost all concepts and usages of flexbox layout are developed around these four elements. When we get a design draft, if we can quickly identify the containers and elements in it, and clarify their spatial relationship, we can quickly build the interface.

Layout in Sketch and Figma#

layout-sketch layout-figma

Figma and Sketch are two very well-known design software. We can see that they consistently use very vivid directives in the processing of element spatial relations: align to top, align to right, align to bottom, align to left , Align base on space. This is also the most intuitive way.

Layout In Swift UI and Flutter#

Now we look at two modern UI solutions: Swift UI and Flutter, how they deal with UI layout.

In Swift UI, we can see keywords such as HStack, VStack, aligment, space, etc. We found that Swift UI is also developed around four elements: container, element, direction, and spatial relationship:

struct ContentView: View {    var body: some View {        HStack(alignment: .top) {            VStack {                CalendarView()                Spacer()            }            VStack(alignment: .leading) {                Text("Event title").font(.title)                Text("Location")            }            Spacer()        }.padding()    }}

In Flutter, we can see keywords such as Row, Column, aligment, and space. We find that Flutter is also developed around the four elements of container, element, direction, and spatial relationship:

Row(  mainAxisAlignment: MainAxisAlignment.spaceEvenly,  children: [    Image.asset('images/pic1.jpg'),    Image.asset('images/pic2.jpg'),    Image.asset('images/pic3.jpg'),  ],);
Column(  mainAxisAlignment: MainAxisAlignment.spaceEvenly,  children: [    Image.asset('images/pic1.jpg'),    Image.asset('images/pic2.jpg'),    Image.asset('images/pic3.jpg'),  ],);

We found that the layout concept of Swift UI and Flutter is very similar to Flexbox layout. In addition, we found that their layout code is directly attached to the container and elements, unlike the traditional Web, where the style code needs to be separated into a single CSS File. Fower and Swift UI and Fluter use similar concepts, style is part of the container and elements, which is also the choice of modern UI development

Some references:

Disadvantages of Flexbox layout#

The above mentioned the layout methods of design software and modern UI frameworks. They are very similar to the Flexbox layout concept. What are the shortcomings of the Flexbox layout?

Although Flexbox is excellent, but for me, it has one of the biggest shortcoming that it's not developer-first. Flexbox layout is not easy to use enough, and the developer experience is not good enough.

Flexbox has many concepts: main axis, cross axis, direction, align-item, justify-content, flex-start, flex-end, flex-center, etc. The biggest problem is that when the direction of the main axis changes, attributes such as align-items, justify-content make the presentation of the UI very inconsistent with human intuition. Especially for me who are not always writing UI (I often need to write backend, do miscellaneous, etc.), every once in a while, I may forget the usage of align-items, justify-content.

My ideal layout (design plan)#

Above we talked about the shortcomings of Flexbox layout: not developer-first.

My ideal layout method should be as easy to use as modern design software. We only need to pay attention to the four elements of the layout: container, element, direction, and spatial relationship. The usage is to find the container and the element, set the direction of the element in the container, and then set the spatial relationship.

The core here is how to express spatial relationships. I think the most intuitive way of expression is to design software. I abstract this way of expression as: toCenter, toCenterX, toCenterY, toTop, toRight, toBottom, toLeft, toBetween, toAround, toEvenly.

  • toCenter, make children elements align to center, see Online Demo
  • toCenterX, make children elements align to center horizontal, see Online Demo
  • toCenterY, make children elements align to center vertical, see Online Demo
  • toTop, make children elements align to top, see Online Demo
  • toRight, make children elements align to right, see Online Demo
  • toBottom, make children elements align to bottom, see Online Demo
  • toLeft, make children elements align to left, see Online Demo
  • toBetween, make children elements space between, see Online Demo
  • toEvenly, make children elements space evenly, see Online Demo
  • toAround, make children elements space around, see Online Demo

Regardless of whether your container is horizontal (row) or vertical (column), the expressions of these directives such as toRight and toBottom will conform to your visual habits.

Why is this abstract expression better? I think there are several advantages:

  • It is more in line with human intuition. You only need to remember to deal with the spatial relationship according to the direction, such as: toRight, toBotom, etc. There is nothing more in line with human intuition. The other advantage is that your memory burden will become very small.
  • Less code, better maintainability, higher development efficiency

My ideal way of writing code (pseudo code):

1.The following code will automatically center the elements in the container horizontally and vertically, and the container direction is row by default, so it can be omitted:

<Container toCenter>  <ItemA /></Container>

The effect is as follows: layout-1

2.The following code will align the three elements A, B, C to the right in the container. The container defaults to row, so it can be omitted:

<Container toRight>  <ItemA />  <ItemB />  <ItemC /></Container>

The effect is as follows: layout-2

3.The following code will align the two elements A and B to the right in the container. This time we declare column, so the elements are arranged vertically:

<Container column toRight>  <ItemA />  <ItemB /></Container>

The effect is as follows: layout-3

4.Use composition:

<Container toBetween toCenterY>  <ItemA />  <ItemB />  <ItemC /></Container>

The effect is as follows: layout-4

Here are just four pseudo-code examples. In fact, you can use "toLeft", "toRight" and other directives to implement most of the UI layout.

Above, we abstracted the expression of spatial relations and applied directives to the container. Let's take a look at a layout effect, how would you build it with code?

layout-5

Let me talk about my ideal plan, the pseudo code is as follows:

<Container toBetween toCenterY>  <ItemA />  <ItemB selfBottom />  <ItemC /></Container>

Here we abstract another type of directives: selfTop, selfRight, selfBottom, selfLeft, selfStretch. These directives can act on elements to individually control the alignment of elements.

So we have some directives that act on elements:

  • selfTop, make elements seft align to top
  • selfRight, make elements seft align to right
  • selfBottom, make elements seft align to bottom
  • selfLeft, make elements seft align to left
  • selfStretch, make elements seft to Stretch

Finally, summarize our layout tool design plan:

  • Container Direction control directives, use row, column, if not declared, the default is row
  • Container Alignment directives for internal elements: toCenter, toCenterX, toCenterY, toTop, toRight, toBottom, toLeft, toBetween, toAround, toEvenly, these directives can be used to control the alignment of sub-elements, and have nothing to do with row and column directions
  • Element Self-alignment directives: selfTop, selfRight, selfBottom, selfLeft, selfStretch. These directives individually control the alignment of the element itself
  • When any container instruction is used, the flexbox layout will be triggered automatically, no need to manually set the display: flex;

The above 4 design concepts are my personal ideal layout.

Fower Layout#

Back to our title: A developer-first layout engine for web. In fact, flex layout cannot be called a layout engine, so what is it? Maybe we call it a layout toolkit will be more appropriate.

The layout engine here refers to: Fower layout toolkit,A layout tool based on flexbox.

The biggest feature of Fower layout is developer-first, it is very simple to use and in line with people's intuition.

For more detailed information about Fower Layout, you can look at the introduction of the official document: Fower Layout Introduction

Fower v1.0

· 6 min read

After half a year's efforts, today we're finally releasing Fower v1.0.

What is Fower?#

Fower is a styling tool library that allows you to efficiently develop UI. The goal is to make it easier for you to write CSS. The core features of Fower are Atomic, Type Safe, and CSS in JS. It pays great attention to the development experience, allowing you to build user interface quickly and happily.

The Story#

A year ago, our team was developing Web, React native, and Mini Program projects at the same time. In these three types of projects, we used different styling tool:

  • In the Web project, we use styed-component to write style;
  • In the React native project, we use the StyleSheet.create that comes with React native;
  • In the Mini Program project, We use Sass to write css;

The three style solutions are written in different way, which makes us particularly painful when writing styles:

  • The development experience is poor. When developing the same user interface, we need to write three types of css code, and need to constantly switch habits and thinking.
  • The tool chain is too broad and too complicated,,Styled-component、Sass、StyleSheet.create...
  • Development efficiency is low, and there are too many duplicate codes.
  • CSS has many inherent shortcomings and poor maintainability.

Later,We discovered Tailwindcss, A utility-first CSS framework. We started to use Tailwindcss in the web project. After some time, we found that the development experience is very good, the development efficiency is very high, especially suitable for our projects that require a highly customized interface. Unfortunately, Tailwindcss cannot be used directly in non-web projects such as React native.

The members of our team like the style of Tailwindcss, so we create Fower, it allows us to unify the way we write styles for all projects.

Similar to Tailwindcss, we also use the concept of utility-first, but Fower is a bit different. Fower uses Atomic Props to write styles. The code is as follows:

SyntaxError: Unexpected token (1:8)
1 : return ()
            ^
LIVE DEMO

Core concept#

Fower is opinionated and we created it based on the following concepts:

  • utility-first, it allows us to write styles more quickly. Unlike other "utility-first" CSS frameworks, Fower uses "Atomic style prop" to write styles.

  • Type safe, Our team is a heavy user of TypeScript. The intellisense brought by Type safe make us hardly read the documents, and we do not rely on any editor plugin when writing code to get accurate auto-completion.

  • Framework-agnostic, This is one of the main reasons we created Fower. Fower allows you to write styles in React, Vue, and React Native in a consistent way.

  • CSS in JS, We hate to write CSS in a separate CSS file. Pure CSS has many shortcomings, such as: unable to access JS variables; easy to produce style conflicts; easy to generate dead code... We like to use JS (CSS in JS) to write styles, which is more Suitable in the age component. In fact, Fower is not just CSS in JS, we also call it CSS in HTML.

Some Cool feature#

Fower has many features, such as atomic classes, responsiveness, pseudo-classes, themes, design systems, CSS in JS..., I think these are the basic feature of Fower, not special feature.

Fower has a few cool features:

1. Layout Toolkit#

If I were to choose a favorite feature in Fower, it would undoubtedly be the Layout Toolkit.

Fower provides a powerful Flexbox-based layout toolkit. By adjusting the direction and alignment of the layout, you can build most of the layout and make the layout easier.

Compared with the traditional flex layout, the layout of Fower is more abstract and streamlined. The layout of Fower is abstracted as toCenter, toCenterX, toCenterY, toLeft, toTop, toRight, toBottom, toBetween , toEvenly, toAround ten kinds of atomic alignment, you can forget the concept of main axis and cross axis in traditional flex layout when you use them, you only need to have a sense of direction.

Use as below:

<div toCenter bgGray100 square-200>  <div square-60 bgOrange400 rounded-8></div>  <div square-80 bgBlue400 rounded-8></div></div>

For more detailed usage, please see the document: Layout Toolkit

2. Predictable style#

Another cool feature of Fower is the predictable style. In traditional CSS, it's not predictable to override style.

For example, if you have some css rule like below:

.red {  color: red;}.blue {  color: blue;}

And some html with css class "red blue" and "blue red":

<div>  <span className="red blue">Fower</span>  <span className="blue red">Fower</span></div>

Can you judge the color of the text? It's hard to be sure, if we don't see the above CSS code, you can't directly judge the color of the text, you can only find out through debugging with developer tools.

In Flower, you can easily judge the color of the following text:

SyntaxError: Unexpected token (1:8)
1 : return ()
            ^
LIVE DEMO

When we build a reusable component, it's very useful. We can override component style elegantly.

For more detailed usage, please see the document: Predictable style

3. Color helper#

Another cool feature of Fower is the color helper. you can handle color with some postfix.

Use --D{0-100} postfix to darken a color.

SyntaxError: Unexpected token (1:8)
1 : return ()
            ^
LIVE DEMO

Use --L{0-100} to lighten a color.

SyntaxError: Unexpected token (1:8)
1 : return ()
            ^
LIVE DEMO

Use --T{0-100} to transparentize a color.

SyntaxError: Unexpected token (1:8)
1 : return ()
            ^
LIVE DEMO

Use --O{0-100} to opacify a color.

SyntaxError: Unexpected token (1:8)
1 : return ()
            ^
LIVE DEMO

For more detailed usage, please see the document: Color helper

4. Composition Postfix#

Fower proveders some postfix to handle style, like: --hover, --focus, --sm, --dark, --T{amount}...

Another cool feature of Fower is Composition Postfix. You can combine some postfix, and The order is arbitrary:

SyntaxError: Unexpected token (1:8)
1 : return ()
            ^
LIVE DEMO

The below code is equal above:

SyntaxError: Unexpected token (1:8)
1 : return ()
            ^
LIVE DEMO

In the end, Fower is a opinionated style tool, if you like it, you can give it a star in github: Fower.