---
title: 一套通用的响应式布局
tags:
  - 前端
  - CSS
  - Less
  - 响应式布局
  - Responsive
  - Flex
categories:
  - - 前端
    - CSS
date: 2021-04-27 14:49:29
---

响应式布局通常都是使用`@media`媒体查询来完成，但是要实现每一套查询都需要编写大量重复的CSS代码，借用Less预处理器提供的函数功能，可以非常有效的将它们抽象出来。<!--more-->

## 公共函数代码

```less 公共布局函数
.flex(@media) {
    display: flex;
    &.row-@{media} {
        flex-direction: row;
    }
    &.row-@{media}-inv {
        flex-direction: row-reverse;
    }
    &.col-@{media} {
        flex-direction: column;
    }
    &.col-@{media}-inv {
        flex-direction: column-reverse;
    }
    @main-axis-align: {
        start: flex-start;
        center: center;
        end: flex-end;
        space: space-around;
        even: space-evenly;
        between: space-between;
        baseline: baseline;
    }
    each(@main-axis-align, {
        &.rm-@{key}-@{media} {
            justify-content: @value;
        }
        &.cm-@{key}-@{media} {
            align-content: @value;
        }
    });
    @cross-axis-align: {
        start: flex-start;
        center: center;
        end: flex-end;
        stretch: stretch;
        baseline: baseline;
    }
    each(@cross-axis-align, {
        &.rc-@{key}-@{media} {
            align-items: @value;
        }
        .as-@{key}-@{media} {
            align-self: @value;
        }
    });
    each(range(1, 10), .(@i) {
        .extend-@{i}-@{media} {
            flex-grow: @i;
        }
        .shrink-@{i}-@{media} {
            flex-shrink: @i;
        }
    });
    @special-width: {
        min: min-content;
        max: max-content;
        fit: fit-content;
    };
    each(@special-width, {
        .w-@{key}-@{media} {
            width: @value;
        }
    });
    @basis-percent: 2, 3, 4, 5, 8, 10, 12, 16, 20, 24;
    each(@basis-percent, .(@max) {
        each(range(1, @max), .(@i) {
            .b-@{i}-@{max}-@{media} {
                flex-basis: percentage(@i / @max);
            }
            .w-@{i}-@{max}-@{media} {
                width: percentage(@i / @max);
            }
        });
    });
    @wrap-modes: {
        none: nowrap;
        wrap: wrap;
        inv: wrap-reverse; 
    }
    each(@wrap-modes, {
        &.w-@{key}-@{media} {
            flex-wrap: @value;
        }
    });
}
```

## 使用方法

假设上面这段Less代码存放在`common.less`文件里，那么可以构建出以下响应式样式定义。

```less 响应式样式定义
@import "common.less";

/* 全局样式部分 */
.flex {
    .flex(a);
}

/* 小尺寸屏幕样式 */
@media screen and (max-width: 639px) {
    .flex {
        .flex(s);
    }
}

/* 中等尺寸屏幕样式 */
@media screen and (min-width: 640px) and (max-width: 959px) {
    .flex {
        .flex(m);
    }
}

/* 大尺寸屏幕样式 */
@media screen and (min-width: 960px) {
    .flex {
        .flex(l);
    }
}
```

## HTML示例

下面通过一个简单的HTML示例，来说明这段响应式布局的使用。这个HTML示例可以达到小屏幕采用纵向排列，中等屏幕采用水平可换行排列，大屏幕采用水平不换行排列，所有元素均采用两端对齐。

```html 响应式布局示例
<div class="flex col-n row-a w-wrap-m rm-between-a rc-center-a">
    <div class="squre w-2-2-n w-1-3-m w-2-12-l">Squre 1</div>
    <div class="squre w-2-2-n w-1-3-m w-2-12-l">Squre 2</div>
    <div class="squre w-2-2-n w-1-3-m w-2-12-l">Squre 3</div>
    <div class="squre w-2-2-n w-1-3-m w-2-12-l">Squre 4</div>
    <div class="squre w-2-2-n w-1-3-m w-2-12-l">Squre 5</div>
    <div class="squre w-2-2-n w-1-3-m w-2-12-l">Squre 6</div>
</div>
```