dev怎么自动排版_用后端的思维来写布局排版

57f6a4343ec227afe93cae1514911762.png

我是一名后端程序员,我学不会 css。花40美元买本 https://every-layout.dev/ 之后,我想了一种写法来表达前端的布局排版。前端大神们可以退散了

布局原语

vant 里有一个 vant-cell 的组件

eb7ffded21765241691898287de4dd6c.png

这样的布局组件很有用,但是用途非常单一。只能用于左边显示一个label,右边显示一个value,中间留白的情况。用这样的布局组件会导致开发者需要记忆大量的布局组件的名字和布局排版效果的对应关系。我希望像我这样的 css 无能者也能够通过记忆一些简单的布局组件来实现”布局不求人“的效果。虽然这样排版写得很机械,一点也不优雅,不语义化,但是 just works。

布局组件包括(均未实现,仅靠想象):

  • Flex Formatting Context
    • Row:x轴
    • Col:y轴
    • Box:参与 x,y布局时候的宽高占位
  • Block Formatting Context
    • Overlay:z轴
  • Inline Formatting Context
    • RichText/Span:流式文本布局
  • media query:不用组件实现,用 javascript 写,走 react 重渲染的模式

下面是对 every-layout 中的布局的枚举

  • Row 布局
    • list of links:Row 的 gap 属性,overflow="wrap"
    • dock to left & right:Row & spacer Box
    • row center:Row & 双 spacer Box
    • media object:minWidth Box
    • sidebar media object:Row折行控制一
    • product list:Row 折行控制二
    • product grid:Row 折行控制三
    • inline form:同 sidebar
    • input group:Row 的 overflow="shrink"
    • reel images:Row 的 overflow="scroll"
    • label with a visual cue:Row 的 inline 属性
  • Box 包装
    • padding & border:Box 突出内容
    • auto width:Box维持图片本身的宽高比
    • aspect ratio:Box按指定宽高比裁切
  • Column 布局
    • stacked inputs:Col 的 gap 属性
    • splitting the stack:Col & spacer Box
    • column center:Col & 双 spacer Box
  • Overlay 布局
    • viewport modal:无 confined
    • obscured content:confined="both"

list of links

1624d74c4ca6e29306b6ecab7d701860.png
宽度足够的时候是这个样子

bb1de7c6b9342695301a4e1bd465e9f3.png
宽度不够的时候是这个样子

理想的写法

<

Row 默认的行为就是宽度不够了之后自动换行。默认有一个 1em 的 gap。如果要调整 gap:

<

Row 有默认的 gap,就不需要在每个子元素上设置 margin 之类的东西来保持两个子元素之间的间距了。

dock to left & right

0cb354a6fd10958e1538368f77b6452c.png
宽度足够时候的样子

ca757872cc64b2a7df297d04f0fd8a38.png
宽度缩小之后

3dffbacc4f39eebfa94ac0638bcfc1ed.png
宽度不足的时候折行

这个在上面的需求的基础上添加了靠左和靠右的需求。"list of linked keywords" 里的每个link都是往左靠齐的。而这个例子里需要两个方向的靠齐。

理想写法

<

想法是 img 和 ul 是被“挤”到左右两边的。中间的 Box 会把所有剩余的横向空间都给“吃掉”。这里用 spacer 为 true 来表示这个 Box 在当前的布局方向上起到弹簧占位的效果。

row center

4c04b46dffe71dd93bc271228c141b75.png

水平居中

<

左右两个 spacer,把剩余的空间都消耗掉,使得button可以水平居中显式。

media object

523c8da4c92beb1ab0ece9b17d9ba91e.png
宽度足够的时候,文本占据所有的剩余空间

4a220fe62b80391a4508053a1da827a5.png

理想的写法

<

Box 除了可以用 spacer 属性占位,可以显式设置 minWidth 的方式来进行占位。Box 的主要作用就是调整自己所包含的内容如何参与 Row/Col 的排版,进行宽或者高的占位。如果没有 Box 包裹,则是内容用自己本身的内容宽高直接参与排版。

sidebar media object

4a220fe62b80391a4508053a1da827a5.png
未折行时的 media object

adc60c5935847dbff3b1da5ee44dd281.png
宽度不够的时候,变成上下叠放。但是图片需要 100% 宽度拉伸

在 media object 的基础上,额外的需求是实现 sidebar 效果。也就是在折行发生之后,对折行的行为进行控制。如果不加 sidebar 效果,上面的例子里的图片是不会进行100%宽度的拉伸的,而是保持图片本身的自有宽度。

理想写法

<

这里添加了一个新的Box属性,用来实现 sidebar 风格的占位。这样当一行放得下的时候,左边的 Box 是 sidebar,右边的 Box 是 spacer,那么 spacer 就会占据 100% 的剩余空间。当一行放不下的时候,两个Box都是独占一行的,sidebar 这个时候就表现出和 spacer 一样的行为,会占据 100% 的剩余空间。

product list

1f65175806eb8aca655de9f1503df8cb.png
宽度足够的时候,一行展示3个商品

d20aca1ef97c339d91b9b3a65c4ec467.png
宽度不足的时候,直接一步到位缩成一列

这个布局是为了避免下面的中间状态,因为这个中间状态会让折行的那个商品显得“过于突出”。

e49f44c4dfe17d80dfa57d9ae302811a.png

这个和 sidebar 一样,都是为了控制折行发生之后的行为。

理想写法:

<

通过设置 childMinWidth 表达了三个含义

  • 所有的 child 都是等宽的,因为只有一个宽度设置
  • child 宽度如果小于 30em,则要发生折行
  • 折行之后不需要出中间状态,直接切换成一列显式

product grid

98a340e65f8efe7f8cec42e390d225c5.png
宽度足够的时候,当成 list 展示

78fc182b1e7b90b482c0694d495b11e7.png
需要折行的时候,用 grid 的方式展示

10829e4fe15d058b846529b34c15c8b1.png
极端窄的时候,会变成一列显式

product grid 和 product list 的区别是多了中间的 grid 的状态。product list 始终是成一行或者一列排列的,product grid 则会折成多行展示。

理想的写法

<

和 product list 的写法是类似的,多了一个 grid 为 true 的属性。表示接受 grid 这个中间的折行状态。

总结一下,三种折行之后的行为

  • sidebar media object:折行之后,sidebar变成占满全屏的宽度
  • product list:折行之后直接变成一列展示
  • product grid:折行之后比 product list 多一个 grid 的中间状态

inline form

这个例子和 sidebar media object 是一样的,复习一遍

4a1dc31ed28112cd75b84759d774ae3d.png
当表单比较小的时候,我们可以尽量排成一行

4298eba7f8ff770cf3ee1ff605862678.png
如果宽度不够,折行成竖排的

理想的写法

<

input group

75f44b3150a5bbf62364f4da73f35727.png

如上图所示的 input group 粗看和 inline form 是一样的。但是 input group 不应该发生换行。这就需要我们给 Row 添加一个属性来控制是否折行

理想的写法

<

默认的 overflow 行为是 wrap。如果指定为 shrink 则会对每个子元素均等比例 shrink 以适应宽度。

sausage links

cf1a320c11fd411a9e8978b10f7ae65b.png
宽度足够的时候显式所有的 links

b2c087ad4c71b398b22b3f2d7c4f814c.png
宽度不足的时候,一部分“香肠”被切掉了

这个显然也是由 overflow 引起的,宽度不足的行为需要被控制。

理想的写法

<

和 shrink 不同,hidden 就是直接“切掉”显式不下的内容。

reel images

582560759fcaebec67cdd7317e53c39a.png
宽度不够出滚动条

理想的写法

<

宽度来自于 img 自身的内容宽度。累积宽度超过了之后触发滚动条。

label with a visual cue

02f74db38763c0ce3434083a402d9b3f.png
在icon旁边放一个文本描述

理想的写法

<

通过 inline 属性,把两条 inline 的内容合并成一行显式,在两条内容之间添加默认的 gap,并用 baseline 进行对齐。

padding & border

5c306e0dede290eb34eef2222905a795.png

Box 除了参与宽高占位之外,还可以让内容显得更加突出。包括添加 padding 和 border 两种方式。上面的布局的理想写法

<Box border>
  <Box invert padding="1em">head</Box>
  <Box padding="1em">body</Box>
</Box>

Box 默认没有 padding 也没有 border,需要显式指定。border 如果设置为 true,则使用全局设置的细边框宽度。

auto width

当高度固定的时候,用高度来反推宽度

6b2cef283c26f6b4fd1f596f7eee220a.png

37f4433ea39008a9077c6a8ec5385799.png

高度变化了,对应的宽度也变化了。

理想的写法

<

我们用外包 Box 的 width/height 方式来 override 内容本身的高度和宽度。也就是 top => bottom 的尺寸确定过程。如果不指定 width/height spacer/sidebar 这些,Box 的尺寸是 bottom => top 的方式来确定的,由内容来决定。

aspect ratio

3672b8cafc195a19c0c3a85201749785.png

无论图片是什么样的宽高比,都按照 Box 指定的宽高比进行裁切

理想写法

<

宽度来自于内容,或者来自于父容器的指定。但是高度始终是宽度按照aspectRatio折算而来。

Box 本质上仍然是一个可被布局的原子 content,参与到 Row/Column 布局里。

  • 指定了一份 content 如何参与 Row/Column 的布局算法,通过 minWidth/minHeight/spacer/sidebar 等属性控制
  • 对 content 进行二次加工,成为一份新的 content,添加 padding/border,裁切边框等

stacked inputs

03680cb0c3a753a3ff45344aa385abed.png

这个表单有两层 stack。字段与字段之间用大间距 stack,表达这是两个独立的字段。字段内的 label/input/error message 用小间距的 stack,表达这些元素是内聚的。

理想的写法

<

splitting the stack

2ac30cf8b26eae83cb15c9f3de87e6b2.png

左侧的 slide 框和 Add slide 按钮中间需要一个留白

理想的写法

<

column center

f39a36b604b7d78af8768bd6cd8a80e1.png
高度够的时候,header/footer都在,principle居中

875112867e0012dba8588ad0002ebefe.png
高度不够的时候,footer 被挤掉了

Col 不像 Row,Row 的 overflow 默认是 wrap,Col 的 overflow 行为就是 hidden。

当高度不够的时候,footer 仍然是被撑到底部的,这个也被称作 sticky footer。

理想的写法

<

viewport modal

d70c96ebdaaa4d066f461a502c2f9846.png

以 viewport 来计算位置,并不限制高和宽

理想的写法

<

obscured content

8194a98df20b725f766ac1a0a5c19d68.png

以父元素的位置来计算 overlay 的位置,并且限制高和宽

<

confined="both" 表示高和宽,都不能超过父一级 overlay 的边界。如果没有 confined 则 overlay base 仅仅只是改变了上一层 overlay 的 xy 坐标位置,并不控制边界。

base 表示这个是最底层的 overlay 了,不要从文档流里移除。base 是用来 confine 其他 overlay 用的。如果没有这一层 base,默认的“base”就是 viewport 本身。

that is all

大概的需求就想到这些,想到了再补

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值