V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
forsigner
V2EX  ›  程序员

一个开发者优先 (developer-first) 的布局引擎

  •  5
     
  •   forsigner · 2021-05-08 11:37:21 +08:00 · 2593 次点击
    这是一个创建于 420 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我又来 v2 发文章了,还是 v2 社区好,有良好的社区氛围,大家能用心的交流,我以后不会在掘金、知乎、segmentfault 等社区发表技术文章,因为几乎不会有阅读量,也没有人交流。

    首先,这篇文章是个标题党,这里先给大家致歉,因为下面介绍的并不能称之为布局引擎,真正的布局引擎应该是这样的:yogalayout。不过建议你一定要读完这篇标题党文章,读完后一定会有收获。

    为什么会有这篇文章

    两周前,我发布了我的一个前端开源项目,名字为:Fower。很多用户问我,Fower 和 Tailwindcss 有什么不同,我的回答是 Fower 在 utilty-first 这一点,理念是和 Tailwindcss 一致的,实际上 utilty-first 理念的 CSS 框架很早就有,比如:ACSSTachyons

    其中,Fower 和 Tailwindcss 最大的不同点之一,就是 Fower 提供了非常易用的布局工具: Fower Layout toolkit,这样是写这篇文章的缘由。下面会详细分享开发 Fower layout 的初衷和其设计思路。

    布局发展史

    Fower Layout 要解决的问题就是布局问题,让我们简单回顾一下 Web 布局的发展史。在 Web 布局整个演进过程当中,经历了没有任何布局、表格布局、定位布局、浮动布局、Flexbox 布局、Grid 布局。

    这里不细说每种布局的特点和优缺点,我只说我的观点和结论:在当前阶段,从功能性、易用性、浏览器兼容性等方面考虑,使用 Flexbox 布局是最好的选择。当然有兴趣的同学可以阅读下面的资料。

    布局的核心

    我认为,布局的核心是处理容器和元素 (container and item)在某一方向 (x,y)的空间关系。这里有几个关键要素:容器、元素、方向、空间关系。实际上,这也是 flexbox 布局核心的东西,flexbox 布局几乎所有概念和用法都是围绕这四个要素展开的。我们在拿到一个设计稿时,如果能快速地识别出其中的容器、元素,并且理清他们的空间关系,便能很快速地去实现它。

    设计软件布局方式

    Figma 和 Sketch 是两款非常出名的设计软件,我们可以看到,在元素空间关系的处理上,它们一致使用非常形象的指令: align to top 、align to right 、align to bottom 、align to left 、align base on space. 这也是最符合人直觉的方式。

    Layout In Swift UI and Flutter

    接下来我们看看两个现代化的 UI 解决方案:Swift UI 和 Flutter,它们是怎么处理 UI 布局的。

    在 Swift UI,我们可以看到 HStack 、VStack 、aligment 、space 等关键字,我们发现 Swift UI 也是围绕 容器、元素、方向、空间关系四个要素展开的:

    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()
        }
    }
    

    在 Flutter 中,我们可以看到 Row 、Column 、aligment 、space 等关键字,我们发现 Flutter 也是围绕 容器、元素、方向、空间关系四个要素展开的:

    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'),
      ],
    );
    

    我们发现,Swift UI 和 Flutter 的布局理念和 Flexbox 布局极其类似,另外,我们发现它们的布局代码是直接依附在容器和元素中的,不像传统的 Web,需要补样式代码单独分离到一个 CSS 文件中。Fower 同样这样的理念,样式就是应该容器和元素的一部分。

    Some references:

    Flexbox 布局的缺点

    上面说了设计软件和现代化 UI 框架的布局方式,他们和 Flexbox 布局的理念非常类似,那 Flexbox 布局有什么缺点呢? Flexbox 非常优秀,但对于我来说它有一个最大的缺点就是易用性不够好。它有很多概念:主轴、交叉轴、方向、align-item 、justify-content 、flex-start 、flex-end 、flex-center 等。最大问题是,主轴的方向发生改变时,align-items, justify-content 的 UI 表现非常不符合人的直觉。特别是对于我这个不是永远都是在写 UI 的人 (我经常需要去写后端、打杂等),每隔一段时间,就很可能忘记align-items, justify-content的用法。

    我理想中的布局方式 (方案设计)

    上面聊了 Flexbox layout 的缺点:易用性不够好。我理想中布局方式的使用,应该像现代设计软件一样好用,我们只需关注布局四要素容器、元素、方向、空间关系,用法就是找到容器和元素,设置容器内元素的方向,然后设置空间关系。这里核心是如何表达空间关系,我觉得最符合人直觉的表达方式就是设计软件的方案。我把这种表达方式抽象为: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 left, 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

    不管你的容器是水平方向 (row) 还是垂直方向 (column),toRight 、toBottom 这些空间关系表达,都会符合你视觉习惯。

    这种抽象的表达方式为什么更好呢?我觉的有几点好处:

    • 更符合人的直觉,你只需记住按照方向处理空间关系,比如:toRight 、toBotom 等,没有什么比这更符合人的直觉,另外的好处的是你的记忆负担会变得非常小
    • 更少地代码,这种方式会让你代码更少,可维护性更强,开发效率更高

    我理想中的代码编写方式(伪代码):

    1.下面代码会自动把容器内的元素水平和垂直居中,容器默认是 row, 所以可以省去:

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

    效果如下:

    2.下面代码会把 A,B,C 三个个元素在容器内靠右对齐, 容器默认是 row, 所以可以省去:

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

    效果如下:

    3.下面代码会把 A,B 两个元素在容器内靠右对齐, 我们声明了 column, 所以元素是竖着排列的:

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

    效果如下:

    1. 使用组合:
    <Container toBetween toCenterY>
      <ItemA />
      <ItemB />
      <ItemC />
    </Container>
    

    效果如下:

    这里只举这四个伪代码例子,实际上你可以使用 "toLeft", "toRight" 等这些指令实现大部分 UI 布局。

    上面,我们抽象了空间关系的表达方式,并把指令作用于容器上。下面我们来看一个布局效果,你会怎么实现它:

    下面说说我理想中的方案,伪代码如下:

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

    这里我们抽象出另外一类指令:selfTop, selfRight, selfBottom, selfLeft, selfStretch. 这些指令可以作用在元素上,单独控制元素的定位对齐方式。

    所以我们有一些作用于元素的指令:

    • 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

    最后,总结一下我们布局工具设计方案:

    • [容器] 方向控制指令,使用 row, column, 如果未声明,默认为 row
    • [容器] 内元素对齐方式指令: toCenter, toCenterX, toCenterY, toTop, toRight, toBottom, toLeft, toBetween, toAround, toEvenly,使用这些指令控制子元素对齐方式,并且和 row, column 方向无关
    • [元素] 自身对齐方式指令:selfTop, selfRight, selfBottom, selfLeft, selfStretch. 这些指令单独控制元素自身对齐方式
    • 使用任何 [容器] 指令,会自动触发 flexbox 布局,无需手动设置 display: flex;

    上面 4 条规则设计,就是我个人理想中的布局方式。

    Fower Layout

    回到我们的标题:一个开发者优先(developer-first)的布局引擎。 实际上,Fower Layout 不能称之为布局引擎,那是什么? 也许我们称其为 Layout tookkit 会更合适。

    Fower Layout 的最大特点是 developer-first,它易于使用并且符合人们的直觉。

    实际上,即使你不使用 Fower Layout, 你也可以使用上面提到的设计思想去实现一套好用的布局工具,而不是使用原始的 Flex Layout 。

    关于 Fower Layout 更详细的信息,可以看看官方文档的介绍:Fower Layout Introduction

    25 条回复    2021-05-08 14:58:46 +08:00
    3dwelcome
        1
    3dwelcome  
       2021-05-08 11:48:03 +08:00
    大佬 NB 啊,每次发文都是前端工具链里的重磅炸弹。

    我是 Tailwindcss 重度粉丝,还对比了一下 fower,真的强。
    66beta
        2
    66beta  
       2021-05-08 11:52:44 +08:00
    请教楼主,文档用得是啥工具?
    king888
        3
    king888  
       2021-05-08 11:55:44 +08:00
    有没打算来个 nuxt 模块
    king888
        4
    king888  
       2021-05-08 11:58:32 +08:00
    刚出来还不太敢上项目,先 watch 一段时间,tailwindcss 粉丝+1
    forsigner
        5
    forsigner  
    OP
       2021-05-08 12:26:01 +08:00   ❤️ 2
    @3dwelcome 我也是 Tailwindcss 的粉丝,哈哈
    forsigner
        6
    forsigner  
    OP
       2021-05-08 12:26:21 +08:00
    forsigner
        7
    forsigner  
    OP
       2021-05-08 12:27:29 +08:00
    @king888 我们团队的商业项目已经用了半年了,放心用,有 bug 我给你改~
    forsigner
        8
    forsigner  
    OP
       2021-05-08 12:28:49 +08:00
    3dwelcome
        9
    3dwelcome  
       2021-05-08 12:31:32 +08:00
    我在想,游戏开发里最常见的可拉伸 UI,比如 U3D 里,layout 一般都用九宫格布局。

    就一张大图切成 9 份,是四角的图片固定,四边的图片可以单向拉伸或平铺。剩下中间一张大图可以 XY 两个方向拉伸平铺。

    好像针对这个案例,用 Flexbox layout 描述起来还挺有难度的。
    HeyWeGo
        10
    HeyWeGo  
       2021-05-08 12:38:05 +08:00
    说个题外话,我是觉得 figma 那样的工具完全有潜力做到可视化布局直接上到前端代码。

    因为 figma 里的操作逻辑已经越来越接近前端的概念了。
    iugo
        11
    iugo  
       2021-05-08 12:49:11 +08:00
    "tookkit"?
    cheese
        12
    cheese  
       2021-05-08 13:24:23 +08:00
    抓了个小虫,中文文档首页出了点小小问题
    toacnme
        13
    toacnme  
       2021-05-08 14:16:38 +08:00
    希望能在 rn 中用到
    toacnme
        14
    toacnme  
       2021-05-08 14:17:23 +08:00
    还有个小程序,现在我已经成了 tailwind 的重度患者了,再去写 css 会感觉很难受了
    king888
        15
    king888  
       2021-05-08 14:21:08 +08:00
    @forsigner 加油~ Tailwind Viewer 这个功能不错,可以参考一下 https://tailwindcss.nuxtjs.org/tailwind/viewer
    xrr2016
        16
    xrr2016  
       2021-05-08 14:32:13 +08:00
    强👍
    denghongcai
        17
    denghongcai  
       2021-05-08 14:40:29 +08:00
    思路很符合直觉,专注解决布局问题,和 tailwind 混着用应该很爽
    forsigner
        18
    forsigner  
    OP
       2021-05-08 14:46:05 +08:00
    @3dwelcome 你这个 flex layout 恐怕不支持,flex 貌似只能在一个方向拉伸
    forsigner
        19
    forsigner  
    OP
       2021-05-08 14:46:57 +08:00
    @HeyWeGo figma 确实好用,迟早会吃掉 sketch 大部分市场
    forsigner
        20
    forsigner  
    OP
       2021-05-08 14:47:16 +08:00
    @iugo 笔误 笔误
    forsigner
        21
    forsigner  
    OP
       2021-05-08 14:53:11 +08:00
    @cheese 文档已修改
    forsigner
        22
    forsigner  
    OP
       2021-05-08 14:53:57 +08:00
    @toacnme rn 可以用,我们用很久了,https://fower.vercel.app/docs/use-with-rn
    forsigner
        23
    forsigner  
    OP
       2021-05-08 14:55:51 +08:00
    @toacnme 小程序也可以用,开发 fower 的目的之一就是解决 web 、小程序、rn 样式写法一致性问题,因为我们自己的产品刚好是要跨这三端的
    forsigner
        24
    forsigner  
    OP
       2021-05-08 14:57:19 +08:00
    @king888 这个不错,相当于让每个项目的 design system 可视化,可以更好地和设计师配合
    forsigner
        25
    forsigner  
    OP
       2021-05-08 14:58:46 +08:00
    @denghongcai 是的,每次太久没写 ui,回来就被 flexbox 的主轴交叉轴弄晕
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2515 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 09:17 · PVG 17:17 · LAX 02:17 · JFK 05:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.