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

本文通过一个前端小练习介绍了如何利用Flex布局来实现3D骰子的效果。首先回顾了Flex布局的基础知识,包括主轴、交叉轴以及相关的布局属性。接着详细展示了创建骰子各面和点数的CSS代码,以及如何调整面的位置和应用3D效果和动画,最终呈现了一个完整的3D骰子。完整源码和改进意见欢迎交流。

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

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

 

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;
            }
复制代码

 

如图,六个面容器这就准备好了。
下面开始上点,如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);
            }

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;
            }

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

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;
            }

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;
            }

 

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;
            }

 

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;
            }

 此时页面完整效果如下:

最后,我们通过给容器盒子(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生成. 以上就是完整内容,感谢大家观看,有什么建议小伙伴们可以评论留言哦!

 

 

 

 

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值