前端Flex布局练习之3D骰子

大家好,flex布局是大家前端页面开发时常用的布局之一,好多小伙伴在面试的时候也常被问到,类似于如何做一个骰子的四点布局的问题,今天我们通过这个小练习来熟悉一下flex布局的妙用吧!
效果图:

0002.gif
还是挺有意思的对吧!最后附上完整源码!
首先我们先复习下flex弹性盒子吧!
通常我们通过给某个元素设置display:flex;就可以将该元素转为块级弹性盒子,display:inline-flex;是行内的弹性盒子。容器默认存在两根交叉轴:水平的主轴(main axis)和垂直的交叉轴(侧轴)(cross axis),两根轴永远垂直。

image.png
flex的几个属性:
flex-direction 属性  决定主轴的方向(即项目的排列方向)

flex-direction: row(默认水平) | row-reverse | column(纵向) | column-reverse;

flex-wrap 属性  定义子元素是否换行显示

flex-wrap: nowrap(不换行) | wrap(换行) | wrap-reverse;(反向换行)

justify-content属性  定义了项目在主轴()上的对齐方式

justify-content: flex-start | flex-end | center | space-between | space-around;

align-items 属性  定义项目在侧轴(单行)上如何对齐

align-items: flex-start | flex-end | center | baseline | stretch(默认值);

align-content 属性  定义了多根轴线的对齐方式

align-content: flex-start | flex-end | center | space-between | space-around | stretch;

flex-flow

flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap;

我们都知道,骰子六个面分别刻着1到6六个小圆点。所以第一步我们得先准备一个容器,将这六个面及上面的圆点绘制出来,下面上代码:

<!--容器盒子以及六个面-->
<div class="container">
    <div class="side"></div>
    <div class="side"></div>
    <div class="side"></div>
    <div class="side"></div>
    <div class="side"></div>
    <div class="side"></div>
</div>

再来点css样式:


/*给父元素flex布局,六个面居中*/
.container {
                width: 100vw;
                height: 100vh;
                display: flex;
                justify-content: center;
                align-items: center;
           }
.container .side {
                width: 100px;
                height: 100px;
                background-color: rgb(235, 230, 230);
                border: 1px solid #000;
            }

image.png
如图,六个面容器这就准备好了。
下面开始上点,如1点:

<div class="side">
    <div class="item"></div>
</div>
/*给父盒子设置flex,两条主轴居中(center),远点就位于中心了*/
.container .side:nth-child(1) {
                display: flex;
                justify-content: center;
                align-items: center;
            }
.circle {
                width: 20px;
                height: 20px;
                border-radius: 50%;
                background-color: rgb(246, 1, 1);
                /* 圆点上下内阴影,凸显出立体感 */
                box-shadow: inset 0 3px rgb(158, 3, 3), inset 0 -2px rgb(158, 3, 3);
            }

image.png
2点:

<div class="side">
    <div class="item"></div>
    <div class="item"></div>
</div>
.container .side:nth-child(2) {
/* 让两个圆点分布在左右两侧 */
                justify-content: space-between;
            }
.container .side:nth-child(2) .circle:nth-child(2) {
/* 让第二个圆点侧轴方向倒序开始 */
                align-self: flex-end;
            }

image.png
感觉小圆点太靠边缘了,我们直接给每个面(side)加上padding: 10px;就好了

image.png
3点:

<div class="side">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
</div>
.container .side:nth-child(3) .circle:nth-child(1) {
                align-self: flex-start;
            }
            /*中间圆点居中*/
.container .side:nth-child(3) .circle:nth-child(2) {
                align-self: center;
            }
.container .side:nth-child(3) .circle:nth-child(3) {
                align-self: flex-end;
            }

image.png
456三个点我们得将其再次划分,4和6点分为两部分,4点每部分占两个圆点,6点每部分占3个,5点则需分三部分,左右占2中间占1
如四点:

            <div class="side">
                <div class="item">
                    <div class="circle"></div>
                    <div class="circle"></div>
                </div>
                <div class="item">
                    <div class="circle"></div>
                    <div class="circle"></div>
                </div>
            </div>
.container .side:nth-child(4) .item {
                display: flex;
                flex-direction: column;
                justify-content: space-between;
            }
.container .side:nth-child(4) {
                justify-content: space-between;
            }

image.png
5点:

            <div class="side">
                <div class="item">
                    <div class="circle"></div>
                    <div class="circle"></div>
                </div>
                <div class="item">
                    <div class="circle"></div>
                </div>
                <div class="item">
                    <div class="circle"></div>
                    <div class="circle"></div>
                </div>
            </div>
.container .side:nth-child(5) .item {
                display: flex;
                flex-direction: column;
                justify-content: space-between;
            }
.container .side:nth-child(5) .item:nth-child(2) {
                justify-content: center;
            }
.container .side:nth-child(5) {
                justify-content: space-between;
            }

image.png
6点:

            <div class="side">
                <div class="item">
                    <div class="circle"></div>
                    <div class="circle"></div>
                    <div class="circle"></div>
                </div>
                <div class="item">
                    <div class="circle"></div>
                    <div class="circle"></div>
                    <div class="circle"></div>
                </div>
            </div>
.container .side:nth-child(6) .item {
                display: flex;
                flex-direction: column;
                justify-content: space-between;
            }
.container .side:nth-child(6) {
                justify-content: space-between;
            }

image.png
此时页面完整效果如下:

image.png

最后,我们通过给容器盒子(container)添加transform-style: preserve-3d;开启3d模式,再通过transform: translate()调整各个面的位置,以及加个小动画就OK了!
完整源码如下:

        <div class="container">
            <div class="side"></div>
            <div class="side"></div>
            <div class="side"></div>
            <div class="side">
                <div class="item"></div>
                <div class="item"></div>
            </div>
            <div class="side">
                <div class="item"></div>
                <div class="item"></div>
                <div class="item"></div>
            </div>
            <div class="side">
                <div class="item"></div>
                <div class="item"></div>
            </div>
        </div>
        <button class="btn">停止旋转</button>
* {
                margin: 0;
                padding: 0;
            }
body {
                width: 100vw;
                height: 100vh;
                background-image: linear-gradient(45deg, rgb(244, 199, 207), rgb(115, 190, 237));
                perspective: 700px;
            }
.container {
                width: 100vw;
                height: 100vh;
                display: flex;
                justify-content: center;
                align-items: center;
                transform-style: preserve-3d;
                animation: rot 0.5s linear infinite;
            }
.container .side {
                position: absolute;
                width: 100px;
                height: 100px;
                background-color: rgb(235, 230, 230);
                box-shadow: 0 0 10px rgb(196, 192, 192);
                display: flex;
                padding: 10px;
                box-sizing: border-box;
            }
.circle {
                width: 20px;
                height: 20px;
                border-radius: 50%;
                background-color: rgb(246, 1, 1);
                /* 圆点上下内阴影,凸显出立体感 */
                box-shadow: inset 0 3px rgb(158, 3, 3), inset 0 -2px rgb(158, 3, 3);
            }
.container .side:nth-child(1) {
                justify-content: center;
                align-items: center;
            }
.container .side:nth-child(2),
.side:nth-child(3),
.side:nth-child(4),
.side:nth-child(5),
.side:nth-child(6) {
                justify-content: space-between;
            }
.container .side:nth-child(2) .circle:nth-child(1),
.side:nth-child(3) .circle:nth-child(1) {
                align-self: flex-start;
            }
.container .side:nth-child(2) .circle:nth-child(2),
.side:nth-child(3) .circle:nth-child(3) {
                align-self: flex-end;
            }
.container .side:nth-child(3) .circle:nth-child(2) {
                align-self: center;
            }
.container .side:nth-child(4) .item,
.side:nth-child(5) .item,
.side:nth-child(6) .item {
                display: flex;
                flex-direction: column;
                justify-content: space-between;
            }
.container .side:nth-child(5) .item:nth-child(2) {
                justify-content: center;
            }
.container .side:nth-child(1) {
                transform: translateZ(-50px);
            }
.container .side:nth-child(2) {
                transform: rotateX(90deg) translateZ(-50px);
            }
.container .side:nth-child(3) {
                transform: rotateY(90deg) translateZ(-50px);
            }
.container .side:nth-child(4) {
                transform: rotateX(90deg) translateZ(50px);
            }
.container .side:nth-child(5) {
                transform: rotateY(90deg) translateZ(50px);
            }
.container .side:nth-child(6) {
                transform: translateZ(50px);
            }
.btn {
                position: absolute;
                right: 50px;
                top: 50px;
                width: 100px;
                height: 50px;
                background-image: linear-gradient(90deg, rgb(236, 162, 133), rgb(237, 127, 143));
                border: 0px;
                border-radius: 5px;
            }
.btn:hover {
                box-shadow: 0 0 20px rgb(211, 180, 133);
                border: 1px solid rgb(92, 142, 234);
            }
/*旋转动画*/
@keyframes rot {
    from {
                    transform: rotateY(0deg) rotateZ(0deg);
          }
    to {
                    transform: rotateY(360deg) rotateZ(360deg);
          }
            }
let containerBox = document.querySelector('.container')
let btn = document.querySelector('.btn')
let childBoxLen = containerBox.children.length
let flag = true
for (let i = 0; i < childBoxLen; i++) {
                addChildNode(containerBox, i)
            }
//添加小圆点
function addChildNode(node, len) {
    let cLen = node.children[len].children.length
    if (len >= 3) {
        if (len === 4) {
            for (let i = 0; i < 3; i++) {
                if (i !== 1) {
                    createCircle(node.children[len].children[i])
                       }
                    createCircle(node.children[len].children[i])
                        }
                    } else {
                        let c = Math.floor((len + 1) / cLen)
                        for (let i = 0; i < 2; i++) {
                            for (let j = 0; j < c; j++) {
                                createCircle(node.children[len].children[i])
                            }
                        }
                    }
                } else {
                    for (let i = 0; i < len + 1; i++) {
                        createCircle(node.children[len])
                    }
                }
            }
//生成小圆点
function createCircle(node) {
                let circle = document.createElement('div')
                circle.classList.add('circle')
                node.appendChild(circle)
            }
//控制动画暂停播放
btn.addEventListener('click', (e) => {
                flag = !flag
                console.log(e.target)
                btn.innerHTML = flag ? '停止旋转' : '开始旋转'
                containerBox.style.animationPlayState = flag ? '' : 'paused'
            })

我这里是用一些比较粗糙的js代码生成的小圆点,大家也可以像开始介绍步骤那样直接在html里面插入小圆点代码,不用js生成.
以上就是完整内容,感谢大家观看,有什么建议小伙伴们可以评论留言哦!

4396D0C0.gif

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容