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

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

  •  5
     
  •   forsigner · 212 天前 · 2166 次点击
    这是一个创建于 212 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我又来 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  
       212 天前
    大佬 NB 啊,每次发文都是前端工具链里的重磅炸弹。

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

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

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

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