文内项目地址:github.com/NervJS/taro…css
Taro 是一套遵循 React 语法规范的跨平台开发解决方案,可是目前当咱们使用 Taro 的时候,在不一样平台上的开发体验还有不一致的地方,因此咱们也都期待有一套跨平台统一的解决方案,可以以最小差别的方式向开发者提供更好的开发体验。前端
在跨平台开发的过程当中,不一样平台之间的差别尤为体如今样式的统一上,因为不一样平台对样式的支持程度并不一致,Taro 很难可以经过编译的手段来对跨平台样式进行统一,因此,咱们须要一个支持跨平台的样式解决方案来对其进行统一。react
考虑页面布局和样式 H5 是最为灵活的,小程序次之,React Native 和快应用最弱,统一跨平台样式应当优先对齐短板,也就是要以 React Native 和快应用的约束来管理样式,同时兼顾小程序的限制,而 Flexbox 就是一个很好的样式解决方案。git
在构建页面的时候,咱们能够经过 Flexbox 高效地完成页面代码,虽然并非全部属性均可以全平台适应的,可是它在全平台都可以获得足够的支持,并且全部平台能够很容易经过它来绘制通用性很高的页面,这也就是为何咱们选择使用 Flexbox 方案来完成这个跨平台演示项目。github
预览地址web
Flexbox 是弹性布局模块(CSS Flexible Box Layout Module)经常使用的简称,是一种用于在单个维度中显示项目行或列的布局模型。在规范中, Flexbox 被描述为用户界面设计的布局模型。 Flexbox 的关键特性是 flex 布局中的项目能够增加和缩小。能够将空间分配给项目自己,或者在项目之间或周围分配空间。小程序
在 Flexbox 中,采用 flex 布局 的元素,称为 flex 容器(flex container), flex 容器全部的子元素自动成为容器成员,称为 flex 元素(flex item)。Flex 容器 默认存在两根轴:水平的主轴(main-axis)和垂直的交叉轴(cross-axis)。flex 元素 默认沿主轴排列。主轴的开始位置(与边框的交叉点)叫作 main-start ,结束位置叫作 main end ;交叉轴的开始位置叫作 cross-start ,结束位置叫作 cross-end ;单个项目占据的主轴空间叫作 main-size ,占据的交叉轴空间叫作 cross-size 。微信小程序
Flexbox 能够对齐主轴或横轴上的项目,从而提供对一组项目的大小和对齐的高级控制,大多数场景下,使用 flex-direction、align-items 和 justify-content 三个样式属性就已经能知足大多数布局需求,换而言之若是熟悉 Flexbox 就能够应对大多数场景下的布局需求。react-native
注意,设为 Flex 布局之后,子元素的 float 、 clear 和 vertical-align 属性将失效。浏览器
在规范中, Flex Container 上,一共有七个属性能够设置,可是 flex-flow 在 React Native 上是不支持的。
flex-direction 属性指定了flex 元素是如何在 flex 容器中布局的,定义了主轴的方向(正方向或反方向)。
支持的值以下:
值 | 意义 |
---|---|
row | flex 容器的主轴被定义为与文本方向相同。 主轴起点和主轴终点与内容方向相同。 |
row-reverse | 表现和 row 相同,可是置换了主轴起点和主轴终点。 |
column | flex 容器的主轴和块轴相同。主轴起点与主轴终点和书写模式的先后点相同。 |
column-reverse | 表现和 column 相同,可是置换了主轴起点和主轴终点。 |
须要注意的是,规范下 flex-direction 的默认值是 row ,而在 React Native 中则为 column,这也就是为何咱们会添加了这个的样式
.flex { display: flex; flex-direction: row; } 复制代码
flex-wrap 指定 flex 元素单行显示仍是多行显示。若是容许换行,这个属性容许控制行的堆叠方向。默认值为 nowrap。
支持的值以下:
值 | 意义 |
---|---|
nowrap | 不换行。flex 元素被摆放到到一行,这可能致使溢出 flex 容器。交叉轴的起点会根据 flex-direction 的值至关于 start 或 before。 |
wrap | flex 元素被打断到多个行中。交叉轴的起点会根据 flex-direction 的值选择等于start 或before。交叉轴的终点为肯定的交叉轴的起点的另外一端。 |
wrap-reverse | 和 wrap 的行为同样,可是交叉轴的起点和交叉轴的终点互换。 |
使用 flex-wrap 属性的时候,咱们须要注意 wrap-reverse 值在 React Native 上是不支持的。
flex-flow 属性是 flex-direction 和 flex-wrap 的简写。默认值为 row nowrap。
语法格式
<'flex-direction'> || <'flex-wrap'>
复制代码
flex-flow 属性不被 React Native 和快应用支持
align-items 属性将全部直接子节点上的 align-self 值设置为一个组。 align-self 属性设置项目在其包含块中在交叉轴方向上的对齐方式。默认值为 stretch。
值 | 意义 |
---|---|
stretch | flex 元素在交叉轴方向拉伸到与容器相同的高度或宽度(flex 元素不能固定尺寸) |
flex-start | 交叉轴的起点对齐 |
flex-end | 交叉轴的终点对齐 |
center | 交叉轴的中点对齐 |
baseline | 元素第一行文字的基线对齐 |
语法格式
normal | stretch | <baseline-position> | [ <overflow-position>? <self-position> ]
where
<baseline-position> = [ first | last ]? baseline
<overflow-position> = unsafe | safe
<self-position> = center | start | end | self-start | self-end | flex-start | flex-end
复制代码
baseline 值不被 React Native 和快应用支持
space-evenly、start、end、self-start、self-end、left、right、first baseline、last baseline、safe、unsafe 在 flex 布局中通用性低
align-content 属性设置了如何沿着 flex 容器的交叉轴和在 flex 元素之间和周围分配空间。默认值为 stretch。
该属性对单行弹性盒子模型无效。(即:带有 flex-wrap: nowrap 的 flex 容器)。
值 | 意义 |
---|---|
stretch | 拉伸全部 flex 元素来填满剩余空间。剩余空间平均的分配给每个 flex 元素 |
flex-start | 全部 flex 元素从垂直轴起点开始填充。第一个 flex 元素的垂直轴起点边和 flex 容器的垂直轴起点边对齐。接下来的每个 flex 元素紧跟前一个 flex 元素。 |
flex-end | 全部 flex 元素从垂直轴末尾开始填充。最后一个 flex 元素的垂直轴终点和容器的垂直轴终点对齐。同时全部后续 flex 元素与前一个对齐。 |
center | 全部 flex 元素朝向容器的中心填充。每 flex 元素互相紧挨,相对于容器居中对齐。容器的垂直轴起点边和第一个 flex 元素的距离相等于容器的垂直轴终点边和最后一个 flex 元素的距离。 |
space-between | 全部 flex 元素在容器中平均分布。相邻两 flex 元素间距相等。容器的垂直轴起点边和终点边分别与第一个 flex 元素和最后一个 flex 元素的边对齐。 |
space-around | 全部 flex 元素在 flex 容器中平均分布,相邻两 flex 元素间距相等。容器的垂直轴起点边和终点边分别与第一个 flex 元素和最后一个 flex 元素的距离是相邻两 flex 元素间距的一半。 |
space-evenly | flex 元素都沿着主轴均匀分布在指定的 flex 元素中。相邻 flex 元素之间的间距,主轴起始位置到第一个 flex 元素的间距,,主轴结束位置到最后一个 flex 元素的间距,都彻底同样。 |
语法格式
normal | <baseline-position> | <content-distribution> | <overflow-position>? <content-position>
where
<baseline-position> = [ first | last ]? baseline
<content-distribution> = space-between | space-around | space-evenly | stretch
<overflow-position> = unsafe | safe
<content-position> = center | start | end | flex-start | flex-end
复制代码
React Native 中须要版本号在 0.58 以上
且 flex-wrap 属性值须要为 wrap
同时只对横轴生效(即 flex-direction 属性为 column 或 column-reverse)
baseline 值不被 React Native 支持
space-evenly、start、end、left、right、first baseline、last baseline、safe、unsafe 在 flex 布局中通用性低
justify-content 属性定义了浏览器如何分配顺着 flex 容器主轴的 flex 元素之间及其周围的空间。
值 | 意义 |
---|---|
flex-start | 从行首开始排列。每行第一个 flex 元素与行首对齐,同时全部后续的 flex 元素与前一个对齐。 |
flex-end | 从行尾开始排列。每行最后一个 flex 元素与行尾对齐,其余元素将与后一个对齐。 |
center | 伸缩元素向每行中点排列。每行第一个元素到行首的距离将与每行最后一个元素到行尾的距离相同。 |
space-between | 在每行上均匀分配 flex 元素。相邻元素间距离相同。每行第一个元素与行首对齐,每行最后一个元素与行尾对齐。 |
space-around | 在每行上均匀分配 flex 元素。相邻元素间距离相同。每行第一个元素到行首的距离和每行最后一个元素到行尾的距离将会是相邻元素之间距离的一半。 |
space-evenly | flex 元素都沿着主轴均匀分布在指定的 flex 元素中。相邻 flex 元素之间的间距,主轴起始位置到第一个 flex 元素的间距,,主轴结束位置到最后一个 flex 元素的间距,都彻底同样。 |
语法格式
normal | <content-distribution> | <overflow-position>? [ <content-position> | left | right ]
where
<content-distribution> = space-between | space-around | space-evenly | stretch
<overflow-position> = unsafe | safe
<content-position> = center | start | end | flex-start | flex-end
复制代码
baseline 值不被 React Native 支持
stretch、space-evenly、start、end、left、right、first baseline、last baseline、safe、unsafe 在 flex 布局中通用性低
place-content 属性是 align-content 和 justify-content 的简写。
语法格式
<'align-content'> <'justify-content'>?
复制代码
place-content 属性不被 React Native 支持
在 Flex Item 上,一样也有六个属性,而 order 属性在 React Native 上不支持。
order 属性规定了 flex 容器中的 flex 元素在布局时的顺序。flex 元素按照 order 属性的值的增序进行布局。拥有相同 order 属性值的 flex 元素按照它们在源代码中出现的顺序进行布局。默认值为 0。
语法格式
<integer>
复制代码
order 属性不被 React Native 支持
flex-grow 属性定义 flex 元素的拉伸因子。
语法格式
<number> | inherit
复制代码
负值无效
React Native 上默认值为 0
flex-shrink 属性指定了 flex 元素的收缩规则。flex 元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值。默认值为 1。
语法格式
<number> | inherit
复制代码
负值是不被容许的。
React Native 上默认值为 1
flex-basis 指定了 flex 元素在主轴方向上的初始大小。若是不使用 box-sizing 改变盒模型的话,那么这个属性就决定了 flex 元素的内容盒(content-box)的尺寸。
注意:若是一个 flex 元素同时设置了 flex-basis (auto 除外)和 width (或者 flex-direction: column 时设置了 height ),flex-basis 权级更高。
语法规范
content | <'width'>
复制代码
<length>
;React Native 上使用 ScrollView 组件会致使属性失效
若是没有足够空间,组件不会发生收缩 (应该是设置了 flex-shrink 属性值默认为 0)
flex 规定了 flex 元素如何伸长或缩短以适应 flex 容器中的可用空间。这是一个简写属性,用来设置 flex-grow, flex-shrink 与 flex-basis。
语法格式
none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
复制代码
在 React Native 中只能为 number 类型
- 当 flex > 0 时,组件大小将与其弹性值成比例。所以,flex 设置为 2 的组件将占用空间的两倍做为 flex 设置为 1 的组件
- 当 flex = 0 时,组件根据 width 和 height 肯定大小,且不会发生变化。
- 当 flex = -1 时,组件一般根据 width 和 height 肯定大小。可是,若是没有足够的空间,组件将收缩到 minWidth 和 minHeight。
在快应用中,flex 的快捷值设置均是无效值
align-self 会对齐当前 flex 行中的 flex 元素,并覆盖 align-items 的值. 若是任何 flex 元素的侧轴方向 margin 值设置为 auto,则会忽略 align-self。
语法格式
auto | normal | stretch | <baseline-position> | <overflow-position>? <self-position>
where
<baseline-position> = [ first | last ]? baseline
<overflow-position> = unsafe | safe
<self-position> = center | start | end | self-start | self-end | flex-start | flex-end
复制代码
baseline 值不被 React Native 和快应用支持
start、end、self-start、self-end、first baseline、last baseline、safe、unsafe 在 flex 布局中通用性低
不一样的平台如 Web、React-Native、微信小程序等各有特点,平台之间的差别很大,会致使不少额外的开发成本。那么若是咱们想要完成一个跨平台项目该怎么作呢?
咱们开始从比较容易入手的方向考虑,若是采用模块化组件或是 css-in-js 的方案去完成样式的构建会是一个好的方案么?
在目前的前端生态中,模块化组件开发会是个很棒的方案,覆盖模式下构建开箱即用的组件同时能够提供方法来覆盖样式再好不过了,可是若是放到小程序开发的模式中,这就会有个很严重的问题,那就是若是咱们在层级样式表中写到的样式,是不能直接传给组件来覆盖样式的,组件和组件的隔离在不一样小程序中很难被打破。
/* CustomComp.js */
export default class CustomComp extends Component {
static defaultProps = {
className: ''
}
render () {
return <View className={this.props.className}>这段文本的颜色不会由组件外的 class 决定</View>
}
}
/* MyPage.js */
export default class MyPage extends Component {
render () {
return <CustomComp className="red-text" /> } } 复制代码
/* MyPage.scss */
.red-text {
color: red;
}
复制代码
若是你们尝试上述的写法,会发现 red-text 类中的样式并无生效,那么在这种状况下咱们若是考虑是使用 css-in-js 会好么?很遗憾,若是你使用它,咱们将不会为这些须要运行时处理的样式补全前缀。
这两个方案都不是合适的方案,那么咱们该怎么作呢?试着去打破小程序的组件限制么?咱们在微信小程序官方的文档中找到 externalClasses 这个方法,能够先来尝试。
/* CustomComp.js */
export default class CustomComp extends Component {
static externalClasses = ['my-class']
render () {
return <View className="my-class">这段文本的颜色由组件外的 class 决定</View>
}
}
/* MyPage.js */
export default class MyPage extends Component {
render () {
return <CustomComp className="red-text" /> } } 复制代码
/* MyPage.scss */
.red-text {
color: red;
}
复制代码
可是这也并不是全部的开发平台都可以提供给开发者相关的方法,因此咱们只能转换目光到另外一个 addGlobalClass 方法上,这个方法不只在全部小程序都可以支持,Taro 在 React Native 端上也提供了一样的方法给你们,这样咱们也能够避开 css modules 这个体验稍差的方法。
/* CustomComp.js */
export default class CustomComp extends Component {
static options = {
addGlobalClass: true
}
render () {
return <View className="red-text">这段文本的颜色由组件外的 class 决定</View>
}
}
复制代码
/* 组件外的样式定义 */
.red-text {
color: red;
}
复制代码
在项目中,咱们已经将全部通用支持的方法写到 scss 文件中,若是你们须要能够直接使用咱们已经提供的 flexbox 样式,按以下方法在本身全局的层级样式表中引入咱们已经提供的样式。
@import 'https://raw.githubusercontent.com/NervJS/taro-flexbox/master/flexbox-demo/src/asset/flex.scss';
复制代码
那么关于 Flex 布局的知识,若是文中有遗漏的,你们能够跟着咱们的项目来梳理知识,也能够到 MDN 上查看相关的文档,值得注意的是在 Flexbox 布局中 gap、row-gap、column-gap 属性在 Grid 布局中广泛支持,可是在 Flex 布局中却只有 Firefox 完成了适配,因此暂且不表,
一样 justify-content 属性的 space-evenly 值在 web 端通用性很低,不建议使用。
gap、row-gap、column-gap in flex
space-evently on desktop
space-evently on mobile
但愿这篇文章能够为你提供一些帮助。
属性 | Chrome | Firefox | Android webview | Safari on iOS | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ小程序 | React Native |
---|---|---|---|---|---|---|---|---|---|---|
flex-direction | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | 部分差别 |
flex-wrap | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | wrap-reverse 不支持 |
flex-flow | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | 不支持 |
align-items | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | baseline 不支持 |
align-content | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | 0.58+ (部分差别) |
justify-content | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | baseline 不支持 |
place-content | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | 不支持 |
order | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | 不支持 |
flex-grow | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
flex-shrink | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
flex-basis | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | 部分差别 |
flex | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | 语法不一样 |
align-self | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | baseline 不支持 |