略微有点标题党,轻拍。。

先看效果:

css怎么做立体圆(css-画一个3D地球)(1)

说到球首先想到的,就是地球经纬度那样的线框图。

  1. 18条经线,18个圆,绕Y轴方法依次旋转10度
  2. 17条纬线,从-80度开始一直到80度。
  3. 纬线半径为cos(R),纬线偏移为sin(R)
  4. 地球倾角为23度左右,加上一个旋转的动画效果

使用js来生成经纬线:

.container,.box { position: relative; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; transform-style: preserve-3d; } .container { perspective: 500px; overflow: hidden; } .box { animation: rotate 20s linear infinite; } .box>div { position: absolute; width: 320px; height: 320px; border: solid 1px #000; border-radius: 50%; } @keyframes rotate { 0% { transform: rotateZ(23deg) rotateY(0deg); } 100% { transform: rotateZ(23deg) rotateY(360deg); }}

<div class="container"> <div class="box"> </div></div>

function addLongitude() { var count = 18 var stepDeg = 180 / count var fragment = document.createDocumentFragment() for (var i = 0; i < count; i ) { var div = document.createElement('div') div.style.transform = 'rotateY(' ~~(i * stepDeg) 'deg)' fragment.appendChild(div) } document.querySelector('.box').appendChild(fragment)} function addLatitude() { var r = 160 var stepDeg = 10 var start = -80 var end = 80 var fragment = document.createDocumentFragment() for (var i = start; i <= end; i = stepDeg) { var div = document.createElement('div') var _r = ~~(Math.cos(i / 180 * Math.PI) * r * 2) 'px' div.style.width = _r div.style.height = _r div.style.transform = 'translateY(' ~~(Math.sin(i / 180 * Math.PI) * r) 'px) rotateX(90deg)' fragment.appendChild(div) } document.querySelector('.box').appendChild(fragment)} window.onload = function () { addLongitude() addLatitude() }

css怎么做立体圆(css-画一个3D地球)(2)

线框图显然是不满足作为一个球的。

我们换个思路。把一个div填充了颜色,贴在球形的表面。

  1. 画一个有背景颜色的圆
  2. 在Y轴上选择经度的角度,在X轴上旋转纬度的角度,在Z轴上向外偏移半径R
  3. 然后纬度从-90度开始到90度依次铺满这个圆
  4. 由于相同大小的填充圆,在两极用到的数量比赤道要少很多。我们根据纬线半径来调整一下填充数量

上边代码修改内部div样式

.box>div { position: absolute; width: 50px; height: 50px; border-radius: 50%; background:rgba(255,0,0,.6); }

function draw(deg) { var fragment = document.createDocumentFragment() var r = 180 // 赤道半径 r *= Math.cos(deg * Math.PI * 2 / 360) // 对应纬度 圆半径 var size = 46 // 填充圆直径 var len = r * 2 * Math.PI / size for (var i = 0; i < len; i ) { var div = document.createElement('div') div.style.transform = 'rotateY(' ~~(360 / len * i) 'deg) rotateX(' deg 'deg) translateZ(160px)' fragment.appendChild(div) } document.querySelector('.box').appendChild(fragment) } window.onload = function () { for (var i = -90; i <= 90; i = 20) { draw(i) } }

css怎么做立体圆(css-画一个3D地球)(3)

这个时候,我们调整div的大小和密度。理论上是可以得到一个比较完美的3D圆的。就是渲染起来会特别卡。

突然。我想起来,我电脑上有这么一张图:

css怎么做立体圆(css-画一个3D地球)(4)

现在,我们将这个图作为div的背景,然后调整每个div的background-position

div.style.backgroundPosition = (100 * i / len) '% -' (deg 90) / 180 * 100 '%'

css怎么做立体圆(css-画一个3D地球)(5)

当然,div颗粒越小,渲染出来的越平滑,越圆润但是也越卡。

手机上无法渲染了,要看的话下载源码使用chrome查看吧。

代码仓库地址:

https://github.com/shb190802/html5

演示地址:

https://suohb.com/demo/win/globe.html

https://suohb.com/demo/win/globe2.html(PC查看)

,