CSS使用Flex和Grid布局实现3D骰子


Posted in HTML / CSS onAugust 05, 2022

在前端面试中,经常会问到如何使用 CSS 实现骰子/麻将布局。今天我们就来用CSS 创建一个 3D 骰子,通过本文可以学到;

  • 使用transform来实现3D形状;
  • 给 3D 骰子实现旋转动画;
  • 使用 Flex 布局来实现骰子布局;
  • 使用 Grid 布局来实现骰子布局。

1. 使用 Flex 布局实现六个面

首先,来定义骰子六个面的 HTML 结构:

<div class="dice-box">
  <div class="dice first-face">
    <span class="dot"></span>
  </div>
  <div class="dice second-face">
    <span class="dot"></span>
    <span class="dot"></span>
  </div>
  <div class="dice third-face">
    <span class="dot"></span>
    <span class="dot"></span>
    <span class="dot"></span>
  </div>
  <div class="dice fourth-face">
    <div class="column">
      <span class="dot"></span>
      <span class="dot"></span>
    </div>
    <div class="column">
      <span class="dot"></span>
      <span class="dot"></span>
    </div>
  </div>
  <div class="fifth-face dice">
    <div class="column">
      <span class="dot"></span>
      <span class="dot"></span>
    </div>
    <div class="column">
      <span class="dot"></span>
    </div>
    <div class="column">
      <span class="dot"></span>
      <span class="dot"></span>
    </div>
  </div>
  <div class="dice sixth-face">
    <div class="column">
      <span class="dot"></span>
      <span class="dot"></span>
      <span class="dot"></span>
    </div>
    <div class="column">
      <span class="dot"></span>
      <span class="dot"></span>
      <span class="dot"></span>
    </div>
  </div>
</div>

下面来实现每个面和每个点的的基本样式:

.dice {
  width: 200px;  
  height: 200px;  
  padding: 20px;  
  background-color: tomato;
  border-radius: 10%;
}

.dot {
   display: inline-block;
   width: 50px;
   height: 50px;
   border-radius: 50%;
   background-color: white;
}

实现效果如下:

CSS使用Flex和Grid布局实现3D骰子

(1)一个点

HTML 结构如下:

<div class="dice first-face">
  <span class="dot"></span>
</div>

实现第一个面,只需要让它水平和垂直方向都居中即可:

  • justify-content:center:使点与主轴(水平)的中心对齐。
  • align-items:center:使点与交叉轴(垂直)的中心对齐。

代码实现如下:

.first-face {
  display: flex;
  justify-content: center;
  align-items: center;
}

现在第一面是这样的:

CSS使用Flex和Grid布局实现3D骰子

(2)两个点

HTML 结构如下:

<div class="dice second-face">
  <span class="dot"></span>
  <span class="dot"></span>
</div>

首先来将第二个面的父元素设置为flex布局,并添加以下属性:

justify-content: space-between:将子元素放置在 flex 容器的开头和结尾。

.second-face {
   display: flex;
   justify-content : space-between;
}

现在点的位置如下:

CSS使用Flex和Grid布局实现3D骰子

这时,第一个点在正确的位置:左上角。而第二个点需要在右下角。因此,下面来使用 align-self 属性单独调整第二个点的位置:

align-self: flex-end:将项目对齐到 Flex 容器的末尾。

.second-face .dot:nth-of-type(2) {
 align-self: flex-end;
}

现在第二面是这样的:

CSS使用Flex和Grid布局实现3D骰子

(3)三个点

HTML 结构如下:

<div class="dice third-face">
  <span class="dot"></span>
  <span class="dot"></span>
  <span class="dot"></span>
</div>

可以通过在第二面放置另一个中心点来实现第三面。

  • align-self: flex-end:将项目对齐到 Flex 容器的末尾。
  • align-self: center:将项目对齐到 Flex 容器的中间。
.third-face {
 display: flex;
  justify-content : space-between;
}

.third-face .dot:nth-of-type(2) {
 align-self: center;
}

.third-face .dot:nth-of-type(3) {
 align-self: flex-end;
}

现在第三面是这样的:

CSS使用Flex和Grid布局实现3D骰子

如果想要第一个点在右上角,第三个点在左下角,可以将第一个点的 align-self 更改为 flex-end,第二个点不变,第三个点无需设置,默认在最左侧:

.third-face {
 display: flex;
  justify-content : space-between;
}

.third-face .dot:nth-of-type(1) {
 align-self :flex-end;
}

.third-face .dot:nth-of-type(2) {
 align-self :center;
}

现在第三面是这样的:

CSS使用Flex和Grid布局实现3D骰子

(4)四个点

HTML 结构如下:

<div class="dice fourth-face">
  <div class="column">
    <span class="dot"></span>
    <span class="dot"></span>
  </div>
  <div class="column">
    <span class="dot"></span>
    <span class="dot"></span>
  </div>
</div>

在四个点的面中,可以将其分为两行,每行包含两列。一行将在 flex-start ,另一行将在 flex-end 。并添加 justify-content: space-between 以便将其放置在骰子的左侧和右侧。

.fourth-face {
 display: flex;
 justify-content: space-between
}

接下来需要对两列点分别进行布局:

  • 将列设置为flex布局;
  • 将flex-direction​设置为column,以便将点放置在垂直方向上
  • 将justify-content​设置为space-between,它将使第一个点在顶部,第二个点在底部。
.fourth-face .column {
 display: flex;
  flex-direction: column;
  justify-content: space-between;
}

现在第四面是这样的:

CSS使用Flex和Grid布局实现3D骰子

(5)五个点

HTML 结构如下:

<div class="fifth-face dice">
  <div class="column">
    <span class="dot"></span>
    <span class="dot"></span>
  </div>
  <div class="column">
    <span class="dot"></span>
  </div>
  <div class="column">
    <span class="dot"></span>
    <span class="dot"></span>
  </div>
</div>

第五面和第四面的差异在于多了中间的那个点。所以,可以基于第四面,来在中间增加一列,样式如下:

.fifth-face {
 display: flex;
 justify-content: space-between
}

.fifth-face .column {
 display: flex;
  flex-direction: column;
  justify-content: space-between;
}

现在第五面是这样的:

CSS使用Flex和Grid布局实现3D骰子

还需要对中间的点进行调整,可以设置 justify-content 为 center 让它垂直居中:

.fifth-face .column:nth-of-type(2) {
 justify-content: center;
}

现在第五面是这样的:

CSS使用Flex和Grid布局实现3D骰子

(6)六个点

HTML 结构如下:

<div class="dice sixth-face">
  <div class="column">
    <span class="dot"></span>
    <span class="dot"></span>
    <span class="dot"></span>
  </div>
  <div class="column">
    <span class="dot"></span>
    <span class="dot"></span>
    <span class="dot"></span>
  </div>
</div>

第六个面的布局和第四个几乎完全一样,只不过每一列多了一个元素,布局实现如下:

.sixth-face {
 display: flex;
 justify-content: space-between
}
 
.sixth-face .column {
 display: flex;
  flex-direction: column;
  justify-content: space-between;
}

现在第六面是这样的:

CSS使用Flex和Grid布局实现3D骰子

2. 使用 Grid 布局实现六个面

骰子每个面其实可以想象成一个 3 x 3 的网格,其中每个单元格代表一个点的位置:

+---+---+---+
| a | b | c |
+---+---+---+
| d | e | f |
+---+---+---+
| g | h | i |
+---+---+---+

要创建一个 3 x 3 的网格,只需要设置一个容器元素,并且设置三个大小相同的行和列:

.dice {
    display: grid;
    grid-template-rows: 1fr 1fr 1fr;
    grid-template-columns: 1fr 1fr 1fr;
}

这里的 fr 单位允许将行或列的大小设置为网格容器可用空间的一部分,这上面的例子中,我们需要三分之一的可用空间,所以设置了 1fr 三次。

我们还可以使用 repeat(3, 1fr) 将 1fr 重复 3 次,来代替 1fr 1fr 1fr。还可以使用定义行/列的grid-template速记属性将上述代码进行简化:

.dice {
    display: grid;
    grid-template: repeat(3, 1fr) / repeat(3, 1fr);
}

每个面所需要定义的 HTML 就像是这样:

<div class="dice">
  <span class="dot"></span>
  <span class="dot"></span>
  <span class="dot"></span>
  <span class="dot"></span>
</div>

所有的点将自动放置在每个单元格中,从左到右:

CSS使用Flex和Grid布局实现3D骰子

现在我们需要为每个骰子值定位点数。开始时我们提到,可以将每个面分成 3 x 3 的表格,但是这些表格并不是每一个都是我们需要的,分析骰子的六个面,可以发现,我们只需要以下七个位置的点:

+---+---+---+
| a |   | c |
+---+---+---+
| e | g | f |
+---+---+---+
| d |   | b |
+---+---+---+

我们可以使用grid-template-areas属性将此布局转换为 CSS:

.dice {
  display: grid;
  grid-template-areas:
    "a . c"
    "e g f"
    "d . b";
}

因此,我们可以不使用传统的单位来调整行和列的大小,而只需使用名称来引用每个单元格。其语法本身提供了网格结构的可视化,名称由网格项的网格区域属性定义。中间列中的点表示一个空单元格。

下面来使用grid-area属性为网格项命名,然后,网格模板可以通过其名称引用该项目,以将其放置在网格中的特定区域中。:nth-child()伪选择器允许单独定位每个点。

.dot:nth-child(2) {
    grid-area: b;
}

.dot:nth-child(3) {
    grid-area: c;
}

.dot:nth-child(4) {
    grid-area: d;
}

.dot:nth-child(5) {
    grid-area: e;
}

.dot:nth-child(6) {
    grid-area: f;
}

现在六个面的样式如下:

CSS使用Flex和Grid布局实现3D骰子

可以看到,1、3、5的布局仍然是不正确的,只需要重新定位每个骰子的最后一个点即可:

.dot:nth-child(odd):last-child {
    grid-area: g;
}

这时所有点的位置都正确了:

CSS使用Flex和Grid布局实现3D骰子

对于上面的 CSS,对应的 HTML分别是父级为一个div标签,该面有几个点,子级就有几个span标签。代码如下:

<div class="dice-box">
  <div class="dice first-face">
    <span class="dot"></span>
  </div>
  <div class="dice second-face">
    <span class="dot"></span>
    <span class="dot"></span>
  </div>
  <div class="dice third-face">
    <span class="dot"></span>
    <span class="dot"></span>
    <span class="dot"></span>
  </div>
  <div class="dice fourth-face">
    <span class="dot"></span>
    <span class="dot"></span>
    <span class="dot"></span>
    <span class="dot"></span>
  </div>
  <div class="fifth-face dice">
    <span class="dot"></span>
    <span class="dot"></span>
    <span class="dot"></span>
    <span class="dot"></span>
    <span class="dot"></span>
  </div>
  <div class="dice sixth-face">
    <span class="dot"></span>
    <span class="dot"></span>
    <span class="dot"></span>
    <span class="dot"></span>
    <span class="dot"></span>
    <span class="dot"></span>
  </div>
</div>

整体的 CSS 代码如下:

.dice {
  width: 200px;  
  height: 200px;  
  padding: 20px;  
  background-color: tomato;
  border-radius: 10%;
  display: grid;
  grid-template: repeat(3, 1fr) / repeat(3, 1fr);
  grid-template-areas:
    "a . c"
    "e g f"
    "d . b";
}

.dot {
  display: inline-block;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background-color: white;
}

.dot:nth-child(2) {
  grid-area: b;
}

.dot:nth-child(3) {
  grid-area: c;
}

.dot:nth-child(4) {
  grid-area: d;
}

.dot:nth-child(5) {
  grid-area: e;
}

.dot:nth-child(6) {
  grid-area: f;
}

.dot:nth-child(odd):last-child {
  grid-area: g;
}

​3. 实现 3D 骰子

上面我们分别使用 Flex 和 Grid 布局实现了骰子的六个面,下面来这将六个面组合成一个正方体。

首先对六个面进行一些样式修改:

.dice {
  width: 200px;  
  height: 200px;  
  padding: 20px;
  box-sizing: border-box;
  opacity: 0.7;
  background-color: tomato;
  position: absolute;
}

定义它们的父元素:

.dice-box {
  width: 200px;
  height: 200px;
  position: relative;
  transform-style: preserve-3d;
  transform: rotateY(185deg) rotateX(150deg) rotateZ(315deg);
}

其中,transform-style: preserve-3d;表示所有子元素在3D空间中呈现。这里的transform 的角度不重要,主要是便于后面查看。

此时六个面的这样的:

CSS使用Flex和Grid布局实现3D骰子

看起来有点奇怪,所有面都叠加在一起。不要急,我们来一个个调整位置。

首先将第一个面在 Z 轴移动 100px:

.first-face {
  transform: translateZ(100px);
}

第一面就到了所有面的上方:

CSS使用Flex和Grid布局实现3D骰子

因为每个面的宽高都是 200px,所以将第六面沿 Z 轴向下调整 100px:

.sixth-face {
  transform: translateZ(-100px);
}

第六面就到了所有面的下方:

CSS使用Flex和Grid布局实现3D骰子

下面来调整第二面,将其在X轴向后移动 100px,并沿着 Y 轴旋转 -90 度:

.second-face {
  transform: translateX(-100px) rotateY(-90deg);
}

此时六个面是这样的:

CSS使用Flex和Grid布局实现3D骰子

下面来调整第二面的对面:第五面,将其沿 X 轴的正方向移动 100px,并沿着 Y 轴方向选择 90 度:

.fifth-face {
  transform: translateX(100px) rotateY(90deg);
}

此时六个面是这样的:

CSS使用Flex和Grid布局实现3D骰子

下面来调整第三面,道理同上:

.third-face {
  transform: translateY(100px) rotateX(90deg);
}

此时六个面是这样的:

CSS使用Flex和Grid布局实现3D骰子

最后来调整第五面:

.fourth-face {
  transform: translateY(-100px) rotateX(90deg);
}

此时六个面就组成了一个完整的正方体:

CSS使用Flex和Grid布局实现3D骰子

下面来为这个骰子设置一个动画,让它转起来:

@keyframes rotate {
  from {
    transform: rotateY(0) rotateX(45deg) rotateZ(45deg);
  }
  to {
    transform: rotateY(360deg) rotateX(45deg) rotateZ(45deg);
  }
}

.dice-box {
  animation: rotate 5s linear infinite;
}

最终的效果如下:

CSS使用Flex和Grid布局实现3D骰子

在线体验:

3D 骰子-Flex:https://codepen.io/cugergz/pen/jOzYGyV

3D 骰子-Grid:https://codepen.io/cugergz/pen/GROMgEe

到此这篇关于CSS使用Flex和Grid布局实现3D骰子的文章就介绍到这了,更多相关CSS 3D骰子内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章,希望大家以后多多支持三水点靠木!

 
HTML / CSS 相关文章推荐
CSS3使用多列制作瀑布流
May 10 HTML / CSS
IE滤镜与CSS3效果(详细整理分享)
Jan 25 HTML / CSS
html5+css3气泡组件的实现
Nov 21 HTML / CSS
CSS3对背景图片的裁剪及尺寸和位置的设定方法
Mar 07 HTML / CSS
利用CSS3的border-radius绘制太极及爱心图案示例
May 17 HTML / CSS
html5是什么_动力节点Java学院整理
Jul 07 HTML / CSS
利用canvas实现图片压缩的示例代码
Jul 17 HTML / CSS
AmazeUI框架搭建的方法步骤(图文)
Aug 17 HTML / CSS
HTML5在微信内置浏览器下右上角菜单的调整字体导致页面显示错乱的问题
Jan 19 HTML / CSS
浅析HTML5页面元素及属性
Jan 20 HTML / CSS
CSS变量实现主题切换的方法
Jun 23 HTML / CSS
HTML CSS 一个标签实现带动画的抖音LOGO
Apr 26 HTML / CSS
css中:last-child不生效的解决方法
Aug 05 #HTML / CSS
CSS浮动引起的高度塌陷问题
Aug 05 #HTML / CSS
使用CSS实现六边形的图片效果
Aug 05 #HTML / CSS
el-form每行显示两列底部按钮居中效果的实现
Aug 05 #HTML / CSS
纯CSS打字动画的实现示例
Aug 05 #HTML / CSS
新的CSS 伪类函数 :is() 和 :where()示例详解
前端使用svg图片改色实现示例
Jul 23 #HTML / CSS
You might like
mysql 中InnoDB和MyISAM的区别分析小结
2008/04/15 PHP
jQuery+php简单实现全选删除的方法
2016/11/28 PHP
php异步:在php中使用fsockopen curl实现类似异步处理的功能方法
2016/12/10 PHP
ThinkPHP5.1框架数据库链接和增删改查操作示例
2019/08/03 PHP
推荐自用 Javascript 缩图函数 (onDOMLoaded)……
2007/10/23 Javascript
jsTree树控件(基于jQuery, 超强悍)[推荐]
2009/09/01 Javascript
返回顶部按钮响应滚动且动态显示与隐藏
2014/10/14 Javascript
深入理解JavaScript系列(30):设计模式之外观模式详解
2015/03/03 Javascript
JavaScript的jQuery库中ready方法的学习教程
2015/08/14 Javascript
Bootstrap实现默认导航栏效果
2020/09/21 Javascript
JS限制条件补全问题实例分析
2016/12/16 Javascript
前端开发之CSS原理详解
2017/03/11 Javascript
用最简单的方法判断JavaScript中this的指向(推荐)
2017/09/04 Javascript
js实现每日签到功能
2018/11/29 Javascript
Python文件夹与文件的操作实现代码
2014/07/13 Python
Python的批量远程管理和部署工具Fabric用法实例
2015/01/23 Python
解决paramiko执行命令超时的问题
2020/04/16 Python
关于Theano和Tensorflow多GPU使用问题
2020/06/19 Python
python爬虫请求头设置代码
2020/07/28 Python
HTML5的postMessage的使用手册
2018/12/19 HTML / CSS
HTML实现代码雨源码及效果示例
2020/02/25 HTML / CSS
如何使用amaze ui的分页样式封装一个通用的JS分页控件
2020/08/21 HTML / CSS
Java程序员面试90题
2013/10/19 面试题
家长会学生家长演讲稿
2013/12/29 职场文书
养殖行业的创业计划书
2014/01/05 职场文书
基层工作经历证明
2014/01/13 职场文书
韩语专业职业生涯规划范文:成功之路就在我们脚下
2014/09/11 职场文书
司法局群众路线教育实践活动整改措施思想汇报
2014/10/13 职场文书
先进教育工作者事迹材料
2014/12/23 职场文书
2015年团支部工作总结
2015/04/03 职场文书
督导岗位职责范本
2015/04/10 职场文书
运动会开幕式致辞
2015/07/29 职场文书
工作感想范文
2015/08/07 职场文书
Python实现机器学习算法的分类
2021/06/03 Python
MongoDB 常用的crud操作语句
2021/06/20 MongoDB
教你nginx跳转配置的四种方式
2022/07/07 Servers