重拾CSS,前端样式精读-布局(弹性盒)

前言

本文收录于CSS系列文章中,欢迎阅读指正

接着上篇布局文章继续介绍当前流行的布局方式

Flexbox布局

长久以来,CSS 布局中唯一可靠且跨浏览器兼容的创建工具只有floats和positioning。这两个工具大部分情况下都很好使,但是在某些方面它们具有一定的局限性,让人难以完成任务,于是就有了Flexbox布局

Flexbox,也称为弹性盒子布局,是一种CSS3的布局方式,它提供了一种更加有效的方式来布置、对齐和分散容器内的项,即使它们的尺寸是未知或是动态的。Flexbox布局主要目的是提供一个更加灵活的布局机制,特别是当涉及到动态或未知大小的布局时。上图可以看到Flexbox的属性分为两类,一种是设置在父元素上的container(容器)属性,另一类是设置在子元素中的item(项目)属性,其中容器属性影响所有子元素(即flex item)的布局方式;项目属性主要影响子元素本身在Flex容器(container)中的行为和排列

特点

  • 灵活性:Flex容器的子元素能够根据可用空间自动伸缩。它们可以根据需要扩展以占据可用空间,或收缩以防止溢出。
  • 简洁的对齐和分布:Flexbox提供了多种对齐选项,可以轻松地在水平和垂直方向上对齐项目,例如align-items,align-content,justify-content等属性。
  • 方向独立性:与传统布局不同,在Flexbox中,可以很容易地更改布局的方向,通过修改flex-direction属性的值,可以在行或列方向上排布子元素。
  • 源顺序独立:项目的视觉顺序可以独立于它们在源代码中的顺序。

不足

  • 浏览器的兼容性问题:虽然大多数现代浏览器都支持Flexbox,但在某些较老版本的浏览器或者特定的浏览器中可能存在兼容性问题。

  • 复杂性:对于初学者来说,Flexbox的概念和属性可能相对复杂,需要一定的时间学习掌握。

容器属性

容器属性指的是设置在父元素中的属性

display

这个属性决定了一个元素是否应该成为一个Flex容器。它有两个值:flex或者inline-flex。

  • flex:使得元素成为块级Flex容器。
  • inline-flex:使得元素成为行内Flex容器。

flex-direction

这个属性决定了主轴的方向,即:Flex项目的排列方向。

  • row(默认值):主轴为水平方向,起点在左端。
  • row-reverse:主轴为水平方向,起点在右端。
  • column:主轴为垂直方向,起点在上沿。
  • column-reverse:主轴为垂直方向,起点在下沿。

flex-wrap

当Flex项目一行放不开时,这个属性决定了项目是否换行及换行的方式。

  • nowrap(默认值):不换行,所有项目都挤在一行里。
  • wrap:换行,第一行在上方。
  • wrap-reverse:换行,第一行在下方。

justify-content

定义了项目在主轴上的对齐方式。

  • flex-start (默认值):项目位于容器的起始位置。
  • flex-end:项目位于容器的结束位置。
  • center:项目位于容器中心。
  • space-between:项目在主轴线均匀分布,第一个项目在起始位置,最后一个项目在结束位置。
  • space-around:项目平均分布在行里,周围留有空白。
  • space-evenly:所有项目和容器边缘之间的距离都相等。

align-items

这个属性定义了项目在交叉轴上如何对齐。

  • stretch (默认值):如果项目未设置高度或设置为auto,将占满整个容器的高度。
  • flex-start:项目位于交叉轴的起点。
  • flex-end:项目位于交叉轴的终点。
  • center:项目位于交叉轴的中点。
  • baseline:项目的第一行文字的基线对齐。

align-content

当存在多行时,这个属性用来对齐整个Flex容器中的Flex项目。此属性对单行Flex容器没有效果。

  • stretch (默认值):行将占满交叉轴的剩余空间。
  • flex-start:行紧靠交叉轴的起点。
  • flex-end:行紧靠交叉轴的终点。
  • center:行位于交叉轴的中心。
  • space-between:行在交叉轴上均匀分布。
  • space-around:行在交叉轴上均匀分布,两边留有空间。
  • space-evenly:行在交叉轴上均匀分布,包括与容器边缘。

项目属性

项目属性也就是容器中子元素的属性

flex-grow

这个属性定义了Flex项目在必要的情况下能否放大来填充父容器的剩余空间。它接受一个无单位的数值,这个数值代表了放大的比例。默认值为0,意味着项目不会放大。如果所有项目的flex-grow属性值都为1,那么它们将会等分剩余空间。如果某个项目的flex-grow值大于1,那么这个项目将相对于其他项占有更多的剩余空间。

flex-shrink

与flex-grow相对,这个属性定义了当Flex容器的空间不足时,项目的缩小比例。同样,它接受一个无单位的数值,默认值为1。意味着如果空间不足,Flex项目将会相等比例地缩小。一个值为0将阻止项目在空间不足时缩小。

flex-basis

这个属性指定了Flex项目在分配多余空间之前应占据的主轴空间。它可以设为auto(自动大小),也可以设置为任何长度单位,例如px,em,%等。默认值auto基于项目内容或者宽度/高度属性的大小。

flex

这是flex-grow, flex-shrink和flex-basis的简写,默认值为0 1 auto。它是一种方便的方法,可以一次性设置三个属性。举个例子,flex: 1等同于flex: 1 1 0%,这表示项目将会以1的比例放大和缩小,并且flex-basis为0%,意味着它的起始大小是0,完全依赖于剩余空间的分配。

align-self

允许单独的Flex项目覆盖Flex容器上的align-items属性。这意味着你可以单独调节某个项目的垂直对齐方式。它可以取如下值:

  • auto: 项目继承其父容器的align-items属性,如果父容器没有设置,则表现为stretch。
  • flex-start: 项目对齐于交叉轴的起点。
  • flex-end: 项目对齐于交叉轴的终点。
  • center: 项目在交叉轴上居中对齐。
  • baseline: 项目基于文字基线对齐。
  • stretch: 项目被拉伸填充容器,如果未设置高度或设置为auto的话。

属性示例

我将上面的各类属性整合成了一个可操作的HTML页面,可以更加直观的观察弹性盒相关属性的效果

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <title>Flexbox</title>
    <style>
        ul {
            list-style: none;
        }

        .flex-container {
            background: #f7f7f7;
            padding: 10px;
            overflow-y: auto;
            height: 300px;
        }

        .flex-item {
            background: #6495ED;
            color: white;
            padding: 10px;
            margin: 5px;
            text-align: center;
        }

        .flex-item:nth-child(2n) {
            padding: 20px;
        }

        .button {
            display: flex;
        }

        .button h3 {
            text-align: center;
            background: lightgreen;
            margin: 5px;
            padding: 5px;
        }

        .button div {
            padding: 5px;
            background: #aaa;
            margin: 5px;
            text-align: center;
            cursor: pointer;
        }
    </style>
</head>

<body>
    <div class="flex-container" id="flex-container"></div>
    <ul class="button" id="button-container"></ul>
    <ul class="button" id="button-item"></ul>
    <script>
        // 创建标签
        const createElement = ({ ele, style, attr, parent }) => {
            const element =
                ele instanceof HTMLElement ? ele : document.createElement(ele ?? "div");
            style &&
                Object.keys(style)?.forEach((key) => (element.style[key] = style[key]));
            attr && Object.keys(attr)?.forEach((key) => (element[key] = attr[key]));
            parent && parent.appendChild(element);
            return element;
        };
        const containerConfig = [{
            name: "display",
            attr: ["flex", "block", "inline-flex"]
        },
        {
            name: "flex-direction",
            attr: ["row", "row-reverse", "column", "column-reverse"]
        },
        {
            name: "flex-wrap",
            attr: ["nowrap", "wrap", "wrap-reverse"]
        },
        {
            name: "flex-flow",
            attr: ["flex-direction", "flex-wrap"]
        },
        {
            name: "justify-content",
            attr: ["flex-start", "flex-end", "center", "space-between", "space-around", "space-evenly"]
        },
        {
            name: "align-items",
            attr: ["stretch", "flex-start", "flex-end", "center", "baseline"]
        },
        {
            name: "align-content",
            attr: ["stretch", "flex-start", "flex-end", "center", "space-between", "space-around", "space-evenly"]
        }]
        const itemConfig = [
            {
                "name": "order",
                "attr": [0, 1, -1, 2] // 整数值,可以是任意整数,包括负数
            },
            {
                "name": "flex-grow",
                "attr": [0, 1, 2, 3] // 无单位数,定义项目的放大比例
            },
            {
                "name": "flex-shrink",
                "attr": [1, 2, 3, 0] // 无单位数,定义项目的缩小比例
            },
            {
                "name": "flex-basis",
                "attr": ["50px", "20%", "auto", "0"] // 长度值或“auto”,定义项目在分配多余空间之前的默认大小
            },
            {
                "name": "flex",
                "attr": ["0 1 auto", "1 0 50px", "3 2 25%", "none"] // 是flex-grow, flex-shrink 和 flex-basis的组合
            },
            {
                "name": "align-self",
                "attr": ["auto", "flex-start", "flex-end", "center", "baseline", "stretch"] // 允许单独的项目与其他项目有不同的对齐方式
            }
        ]
        const itemLength = 8
        const itemSplit = 3//分割项目属性标签,只有前面几个生效,更好看出效果
        const flexContainer = document.querySelector("#flex-container")
        const createContainer = (length) => {
            Array(length).fill("").forEach((_, i) => {
                let className = "flex-item"
                const it = createElement({
                    parent: flexContainer, attr: {
                        textContent: `第${i}项`
                    }
                })
                if (i <= itemSplit) {
                    className += " active"
                }
                it.setAttribute("class", className)
            })
        }
        createContainer(itemLength)
        const buttonContainer = document.querySelector("#button-container")
        const buttonItem = document.querySelector("#button-item")
        const flexItem = document.querySelectorAll(".flex-item.active")


        const styleBtnTemp = (target, config, parent) => {
            config.forEach(conf => {
                const { name, attr } = conf
                const li = createElement({
                    ele: "li", parent
                })
                createElement({
                    ele: "h3", parent: li, attr: {
                        textContent: name
                    }
                })
                attr.forEach(it => {
                    createElement({
                        parent: li, attr: {
                            textContent: it
                        }
                    }).addEventListener("click", () => {
                        console.log(target);
                        target.forEach(elem => {
                            elem.style[name] = it
                        })
                    })
                })

            })
        }
        styleBtnTemp([flexContainer], containerConfig, buttonContainer)
        styleBtnTemp(flexItem, itemConfig, buttonItem)

    </script>

</body>


</html>

demo效果如下,这个页面可玩性还是很高的

总结

Flexbox的设计初衷是为了应对传统布局方式(如浮动布局、定位布局)难以处理的一些场景,尤其是在动态变化的视口大小和不确定长度的内容中实现灵活的布局。

感谢你看到这里,以上就是文章全部内容了,如果觉得文章不错的话,还请三连鼓励一下,你的支持就是我创作的最大动力,谢谢!

相关代码

myCode: 基于js的一些小案例或者项目 - Gitee.com

参考

A Complete Guide to Flexbox | CSS-Tricks - CSS-Tricks

A CSS Flexbox Cheatsheet | DigitalOcean

弹性盒子 - 学习 Web 开发 | MDN

CSS 弹性盒子布局 - CSS:层叠样式表 | MDN


重拾CSS,前端样式精读-布局(弹性盒)
http://website.diehunter1024.work/2024/10/24/重拾CSS,前端样式精读-布局(弹性盒)/
作者
阿宇的编程之旅
发布于
2024年10月24日
许可协议