How can I create pure three-dimensional CSS spheres?

tl; dr: I would like to create a real 3D sphere with CSS - not just an illusion

Note. Some examples of fragments do not respond. Please use full screen.




With pure CSS, you can create and animate a 3d cube, as shown below:

#cube-wrapper { position: absolute; left: 50%; top: 50%; perspective: 1500px; } .cube { position: relative; transform-style: preserve-3d; animation-name: rotate; animation-duration: 30s; animation-timing-function: linear; animation-iteration-count: infinite; } @keyframes rotate { 0% { transform: rotate3d(0, 0, 0, 0); } 100% { transform: rotate3d(0, 1, 0, 360deg); ; } } .face { position: absolute; width: 200px; height: 200px; border: solid green 3px; } #front_face { transform: translateX(-100px) translateY(-100px) translateZ(100px); background: rgba(255, 0, 0, 0.5); } #back_face { transform: translateX(-100px) translateY(-100px) translateZ(-100px); background: rgba(255, 0, 255, 0.5); } #right_face { transform: translateY(-100px) rotateY(90deg); background: rgba(255, 255, 0, 0.5); } #left_face { transform: translateY(-100px) translateX(-200px) rotateY(90deg); background: rgba(0, 255, 0, 0.5); } #top_face { transform: translateX(-100px) translateY(-200px) rotateX(90deg); background: rgba(0, 255, 255, 0.5); } #bottom_face { transform: translateX(-100px) rotateX(90deg); background: rgba(255, 255, 255, 0.5); } .cube { transform: rotateX(90deg) rotateY(90deg); } 
 <div id="cube-wrapper"> <div class="cube"> <div id="front_face" class="face"></div> <div id="right_face" class="face"></div> <div id="back_face" class="face"></div> <div id="left_face" class="face"></div> <div id="top_face" class="face"></div> <div id="bottom_face" class="face"></div> </div> </div> 

I want to create and animate a 3D sphere in the same way.

So ... the first idea I get is to use border-radius and ... well ... this does not work.

 #cube-wrapper { position: absolute; left: 50%; top: 50%; perspective: 1500px; } .cube { position: relative; transform-style: preserve-3d; animation-name: rotate; animation-duration: 30s; animation-timing-function: linear; animation-iteration-count: infinite; } @keyframes rotate { 0% { transform: rotate3d(0, 0, 0, 0); } 100% { transform: rotate3d(0, 1, 0, 360deg); ; } } .face { position: absolute; width: 200px; height: 200px; border: solid green 3px; border-radius: 100vw } #front_face { transform: translateX(-100px) translateY(-100px) translateZ(100px); background: rgba(255, 0, 0, 0.5); } #back_face { transform: translateX(-100px) translateY(-100px) translateZ(-100px); background: rgba(255, 0, 255, 0.5); } #right_face { transform: translateY(-100px) rotateY(90deg); background: rgba(255, 255, 0, 0.5); } #left_face { transform: translateY(-100px) translateX(-200px) rotateY(90deg); background: rgba(0, 255, 0, 0.5); } #top_face { transform: translateX(-100px) translateY(-200px) rotateX(90deg); background: rgba(0, 255, 255, 0.5); } #bottom_face { transform: translateX(-100px) rotateX(90deg); background: rgba(255, 255, 255, 0.5); } .cube { transform: rotateX(90deg) rotateY(90deg); } 
 <div id="cube-wrapper"> <div class="cube"> <div id="front_face" class="face"></div> <div id="right_face" class="face"></div> <div id="back_face" class="face"></div> <div id="left_face" class="face"></div> <div id="top_face" class="face"></div> <div id="bottom_face" class="face"></div> </div> </div> 

So, I redefined my approach and looked for another method.

I watched:

Then I tried again ... the best I got was an overly complex 3D illusion object.

Like this:

 body { overflow: hidden; background: #333; } .wrapper { margin: 1em; animation-duration: 20s; } .planet, .planet:before, .planet:after { height: 300px; width: 300px; border-radius: 100vw; will-change: transform; margin: 0 auto; } .planet { box-shadow: inset 0px 0px 10px 10px rgba(0, 0, 0, 0.4); position: relative; } .wrapper, .planet, .planet:before { animation-name: myrotate; animation-duration: 20s; } .wrapper, .planet, .planet:before, .planet:after { animation-timing-function: linear; animation-iteration-count: infinite; } .planet:before, .planet:after { content: ''; position: absolute; top: 0; left: 0; } .planet:before { box-shadow: inset 20px 20px 100px 00px rgba(0, 0, 0, .5), 0px 0px 5px 3px rgba(0, 0, 0, .1); } .planet:after { filter: saturate(2.5); background: linear-gradient(rgba(0, 0, 0, 1), transparent), url("https://i.stack.imgur.com/eDYPN.jpg"); opacity: 0.3; box-shadow: inset -20px -20px 14px 2px rgba(0, 0, 0, .2); animation-name: myopacity; animation-duration: 5000000s; } @keyframes myrotate { 0% { transform: rotatez(0deg); } 100% { transform: rotatez(360deg); } } @keyframes myopacity { 0% { background-position: 0px; transform: rotatez(0deg); } 50% { background-position: 100000000px; } 100% { background-position: 0; transform: rotatez(-360deg); } } 
 <div class="wrapper"> <div class="planet"></div> </div> 

And this:

 body { background: #131418; } .wrapper { margin: 1em; max-width: 100%; position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); } .planet, .planet:before, .planet:after { height: 500px; width: 500px; max-height: 30vw; max-width: 30vw; border-radius: 100vw; will-change: transform; } .planet { box-shadow: inset 0px 0px 100px 10px rgba(0, 0, 0, .5); position: relative; float: left; margin: 0 2em; } .planet, .planet:before, .planet:after { animation-name: myrotate; animation-duration: 10s; } .wrapper, .planet, .planet:before, .planet:after { animation-timing-function: linear; animation-iteration-count: infinite; } .planet:before, .planet:after { content: ''; position: absolute; top: 0; left: 0; } .planet:before { box-shadow: inset 50px 100px 50px 0 rgba(0, 0, 0, .5), 0 0 50px 3px rgba(0, 0, 0, .25); background-image: -webkit-radial-gradient( top, circle cover, #ffffff 0%, #000000 80%); opacity: .5; } .planet:after { opacity: .3; background-image: -webkit-radial-gradient( bottom, circle, #ffffff 0%, #000000 -200%); box-shadow: inset 0px 0px 100px 50px rgba(0, 0, 0, .5); } @keyframes myrotate { 0% { transform: rotatez(0deg); } 100% { transform: rotatez(-360deg); } } .bg { background: wheat; } 
 <div class="wrapper"> <div class="planet bg"></div> </div> 

Which fit until you try to rotate them on the x - axis or y-axis , like a cube in my first example ... here's what happens then: (simplified example)

 .sphere { background: black; width: 300px; height: 300px; border-radius: 100vw; animation: myrotate 10s linear infinite } @keyframes myrotate { 0% { transform: rotate3d(0, 0, 0, 0); } 100% { transform: rotate3d(0, 1, 0, 360deg); } } 
 <div class="sphere"></div> 

All you get is a 2d flat object that expires given that it is an element




The closest thing I found is the following form created in the Timo Korinth tutorial

 @-webkit-keyframes animateWorld { 0% { -webkit-transform: rotateY(0deg) rotateX(0deg) rotateZ(0deg); } 50% { -webkit-transform: rotateY(360deg) rotateX(180deg) rotateZ(180deg); } 100% { -webkit-transform: rotateY(720deg) rotateX(360deg) rotateZ(360deg); } } html { background: #FFFFFF; } . world { -webkit-perspective: 1000px; } .cube { margin-left: auto; margin-right: auto; position: relative; width: 200px; height: 200px; -webkit-transform-style: preserve-3d; -webkit-animation-name: animateWorld; -webkit-animation-duration: 10s; -webkit-animation-iteration-count: infinite; -webkit-animation-timing-function: linear; } .circle { position: absolute; width: 100%; height: 100%; border: 2px dashed #009BC2; border-radius: 50%; opacity: 0.8; background: rgba(255, 255, 255, 0); } .zero { -webkit-transform: rotateX(90deg); } .two { -webkit-transform: rotateY(45deg); } .three { -webkit-transform: rotateY(90deg); } .four { -webkit-transform: rotateY(135deg); } .five { width: 173px; height: 173px; margin: 14px; -webkit-transform: rotateX(90deg) translateZ(50px); } .six { width: 173px; height: 173px; margin: 14px; -webkit-transform: rotateX(90deg) translateZ(-50px); } 
 <div class="world"> <div class="cube"> <div class="circle zero"></div> <div class="circle one"></div> <div class="circle two"></div> <div class="circle three"></div> <div class="circle four"></div> <div class="circle five"></div> <div class="circle six"></div> </div> </div> 



So here is my

Question:

How to create a real three-dimensional sphere with pure CSS? More specifically, the one in question, not just the frame, does not contain hundreds of html elements.




Notes:

  • Three-dimensional spheres have height, width and depth - just like a cube in my first sample fragment
  • I do not need physics, and there is no need for any user interaction. Just an animated spinning sphere.



Additional resources:

+60
css css3 css-shapes css-transforms css-animations
Jul 21 '17 at 12:52 on
source share
7 answers

Strictly speaking, any “3D” shape on a flat screen is more likely an illusion of a 3D object. All that we see is a two-dimensional projection of this form onto the plane of the screen, and our brain does everything possible to guess which shape can give the projection that we see. If the projection changes, our brain interprets it as a three-dimensional object, changing its orientation, which helps it better determine the shape of this object.

It works well with asymmetric objects and objects made of polygons (for example, cubes), but a sphere is a very special case: its projection onto a plane always gives only a circle. The static sphere and the rotating have the same projection, the same circle. Even in real life, if we look at a sphere with a uniform surface without any marks on it (for example, a polished metal ball), it is difficult to determine whether it is stationary or rotating. Our eyes need some hints, some details that move along the surface of a sphere in accordance with its geometry. The more such details move as you expect from points on a spherical surface to move, the clearer the perception (well, illusion) of a rotating sphere.

And here is the key to the problem of creating a CSS scene that would give such a perception: to make this illusion strong enough, we need a lot of signs moving along paths lying on different planes. And the only way to get this in CSS is for each character to be a separate CSS field (element or pseudo-element). If our sphere consists only of moving labels, we really need many of them to see it as a sphere - thus, “hundreds of elements” in most of the demos that you saw.

So, if you want the sphere to look realistic with a fairly small number of elements, you probably would need to combine effects that create the “illusion” of a static main spherical shape (circle with radial gradients, inner shadows, etc.) with some relatively small elements (to make them less obvious that they are actually flat) oriented along the surface of a sphere with 3D transforms and animated - basically the same as the cube faces in the first demo.

Below is my own attempt to put this approach into practice. I used 20 circular elements oriented roughly like the face of a regular icosahedron (for example, white hexagons on a classic soccer ball). I grouped them into two groups, each of which made one hemisphere for convenience (this was not necessary, but it simplified the styling). The entire three-dimensional scene consists of the sphere itself and the background frame (pseudo-element), which intersects the sphere near its center (slightly closer to reduce the “flicker” of the circles when they go from the near side to the far side and back) and always refers to the screen. So there are only 24 elements (not literally "hundreds", at least :). To make the circles look more "convex" (for example, spherical segments), I added two pseudo-elements to each of them and slightly raised them above the other. Works best on Chrome and Firefox 57+ (Firefox 56- and iOS Safari still have a “flicker” near the edges). If you circle, you can see the scene without a background frame (and also without flickering). A slightly modified version is also available on Codepen .

 .scene { perspective: 400vmin; transform-style: preserve-3d; position: absolute; width: 80vmin; height: 80vmin; top: 10vmin; left: 10vmin; } .sphere { transform-style: preserve-3d; position: absolute; animation: rotate 20s infinite linear; width: 100%; height: 100%; transform-origin: 50% 50%; top: 0; left: 0; } .scene::before { content: ''; position: absolute; width: 100%; height: 100%; top: 0%; left: 0%; background: radial-gradient(circle farthest-corner at 33% 33%, rgba(240, 240, 220, 0.85) 0%, rgba(30, 30, 40, 0.85) 80%), radial-gradient(circle farthest-corner at 45% 45%, rgba(0, 0, 0, 0) 50%, #000000 80%); border-radius: 50%; transform: translateZ(2vmin); } .scene:hover::before { display: none; } .hemisphere { position: absolute; top: 0; left: 0; width: 100%; height: 100%; transform-style: preserve-3d; transform-origin: 50% 50%; transform: rotateX(90deg); } .hemisphere:nth-child(2) { transform: rotateX(-90deg); } .face { position: absolute; width: 40vmin; height: 40vmin; background: radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.1) 48%, #ff0000 49%, #ff0000 50%, rgba(0, 0, 0, 0) 51%); transform-style: preserve-3d; transform-origin: 50% 0; top: 50%; left: 20vmin; } .face::before, .face::after { content: ''; position: absolute; border-radius: 50%; box-sizing: border-box; } .face::before { width: 50%; height: 50%; top: 25%; left: 25%; border: 2px solid #333; background: rgba(255, 255, 255, 0.3); transform: translateZ(1.6vmin); } .face::after { width: 20%; height: 20%; top: 40%; left: 40%; background: rgba(0, 0, 0, 0.2); transform: translateZ(2.8vmin); } .face:nth-child(1) { transform: translateZ(-41.6vmin) rotateZ(36deg) translateY(-6.8vmin) rotateX(143deg); } .face:nth-child(2) { transform: translateZ(-41.6vmin) rotateZ(108deg) translateY(-6.8vmin) rotateX(143deg); } .face:nth-child(3) { transform: translateZ(-41.6vmin) rotateZ(180deg) translateY(-6.8vmin) rotateX(143deg); } .face:nth-child(4) { transform: translateZ(-41.6vmin) rotateZ(252deg) translateY(-6.8vmin) rotateX(143deg); } .face:nth-child(5) { transform: translateZ(-41.6vmin) rotateZ(-36deg) translateY(-6.8vmin) rotateX(143deg); } .face:nth-child(6) { transform: translateZ(-26.8vmin) rotateZ(36deg) translateY(-33.2vmin) rotateX(100deg); } .face:nth-child(7) { transform: translateZ(-26.8vmin) rotateZ(108deg) translateY(-33.2vmin) rotateX(100deg); } .face:nth-child(8) { transform: translateZ(-26.8vmin) rotateZ(180deg) translateY(-33.2vmin) rotateX(100deg); } .face:nth-child(9) { transform: translateZ(-26.8vmin) rotateZ(252deg) translateY(-33.2vmin) rotateX(100deg); } .face:nth-child(10) { transform: translateZ(-26.8vmin) rotateZ(-36deg) translateY(-33.2vmin) rotateX(100deg); } .face:nth-child(11) { transform: translateZ(-26.8vmin) rotateZ(36deg) translateY(-33.2vmin) rotateX(100deg); } @keyframes rotate { 0% { transform: rotateZ(25deg) rotateX(20deg) rotateY(0deg); } 50% { transform: rotateZ(-25deg) rotateX(-20deg) rotateY(180deg); } 100% { transform: rotateZ(25deg) rotateX(20deg) rotateY(360deg); } } body { background: #555; overflow: hidden; } 
 <div class="scene"> <div class="sphere"> <div class="hemisphere"> <div class="face"></div> <div class="face"></div> <div class="face"></div> <div class="face"></div> <div class="face"></div> <div class="face"></div> <div class="face"></div> <div class="face"></div> <div class="face"></div> <div class="face"></div> </div> <div class="hemisphere"> <div class="face"></div> <div class="face"></div> <div class="face"></div> <div class="face"></div> <div class="face"></div> <div class="face"></div> <div class="face"></div> <div class="face"></div> <div class="face"></div> <div class="face"></div> </div> </div> </div> 
+89
Jul 26 '17 at 1:57
source share

How to create a real three-dimensional sphere with pure CSS?

Well, as many of them stated in the answers and comments, it is simply impossible to create a single three-dimensional object in a browser with html and css only at this point in time, but you can create the illusion of a 3D object. Below is my approach to solving the problem.

To give the human eye the ability to see a spherical object, reference points are necessary for observing the eye. In my case, these are the lines that define the shape of the sphere. Lines are achieved by providing a border to 5 elements that are in the set along the X axis, and 5 elements that are in the set along the Y axis. Only X / Y sets are assigned a border because this alone provides enough reference to create an illusion spheres. Additional lines on the Z axis are simply messy and not needed. If all lines are turned off, the whole thing looks like a solid "perfect" sphere (looks like a circle, but all its parts move and are present on the 3D plane in the browser!).




What I've done:
  • 15 html elements were created, each of which will be a broken circle in 3 sets of 5

    The reason for all of these sets is that when the entire fixture rotates on the x, y, z axis, the backgrounds of each of the elements in the x, y, z sets fill the empty spaces for each other.

  • Each set of 5 elements rotates on the axis X, Y, Z, respectively, in increments of 36 degrees. enter image description here
  • All elements are rounded with border-radius:50%; 3 sets of 5 rounded elements for the X Y Z axis
  • Set background of circle elements to solid color. Filled sets if 5 rounded items
  • Put the fees together so that they overlap enter image description here
  • Trimmed minor spaces that arose due to the insufficient number of elements covering the empty spaces between the circles x, y, z, using clip-path: circle(96px at center); on the container, and applied a cool shadow / light effect to the print transaction
    enter image description here vs enter image description here

    More circles will lead to a less “sharp” sphere, but since performance is emphasized in this matter, a quick clip of the whole thing looked like a thing to do




As a final thought, I wanted to express my appreciation for the question asked, it really made me think and was a great project that led me to learn a lot about the 3D capabilities of html / css.

Also thanks to all the people who took the time to open this open, and came up with amazing approaches to the problem.

I hope the results of my research will be useful. Hurrah!

This pen is also based on the example of Timo Corinth.

 * { margin: 0; padding: 0; } /* Rotate Sphere animation */ @-webkit-keyframes animateSphere { 0% { transform: rotateY(0deg) rotateX(0deg) rotateZ(0deg); } 50% { transform: rotateY(360deg) rotateX(360deg) rotateZ(0deg); } 100% { transform: rotateY(720deg) rotateX(720deg) rotateZ(0deg); } } html { background: black; } .scene { perspective: 1000px; } .container { margin-top: 5vh; margin-left: auto; margin-right: auto; position: relative; width: 200px; height: 200px; transform-style: preserve-3d; animation-name: animateSphere; animation-duration: 30s; animation-iteration-count: infinite; animation-timing-function: linear; } .border { border: 1px solid white; } .circle { position: absolute; width: 100%; height: 100%; border-radius: 50%; background: rgba(204, 0, 102, 1); } .circle:nth-child(1) { transform: rotate3d(1, 0, 0, 0deg); } .circle:nth-child(2) { transform: rotate3d(1, 0, 0, 36deg); } .circle:nth-child(3) { transform: rotate3d(1, 0, 0, 72deg); } .circle:nth-child(4) { transform: rotate3d(1, 0, 0, 108deg); } .circle:nth-child(5) { transform: rotate3d(1, 0, 0, 144deg); } /* 18! difference to align*/ .circle:nth-child(6) { transform: rotate3d(0, 1, 0, 0deg); } .circle:nth-child(7) { transform: rotate3d(0, 1, 0, 36deg); } /* Upper and Lower circle */ .circle:nth-child(8) { transform: rotate3d(0, 1, 0, 72deg); } .circle:nth-child(9) { transform: rotate3d(0, 1, 0, 108deg); } .circle:nth-child(10) { transform: rotate3d(0, 1, 0, 144deg); } .circle:nth-child(11) { transform: rotate3d(0, 1, 0, 90deg) rotate3d(1, 0, 0, 0deg); } .circle:nth-child(12) { transform: rotate3d(0, 1, 0, 90deg) rotate3d(1, 0, 0, 36deg); } /* Upper and Lower circle */ .circle:nth-child(13) { transform: rotate3d(0, 1, 0, 90deg) rotate3d(1, 0, 0, 72deg); } .circle:nth-child(14) { transform: rotate3d(0, 1, 0, 90deg) rotate3d(1, 0, 0, 108deg); } .circle:nth-child(15) { transform: rotate3d(0, 1, 0, 90deg) rotate3d(1, 0, 0, 144deg); } .shadow { margin: auto; border-radius: 50%; width: 200px; height: 200px; box-shadow: 10px 1px 30px white; } /* Clip the sphere a bit*/ .clip { clip-path: circle(96px at center); } 
 <div class="scene"> <div class="shadow"> <div class="clip"> <div class="container"> <div class="circle border"></div> <div class="circle border"></div> <div class="circle border"></div> <div class="circle border"></div> <div class="circle border"></div> <div class="circle border"></div> <div class="circle border"></div> <div class="circle border"></div> <div class="circle border"></div> <div class="circle border"></div> <div class="circle"></div> <div class="circle"></div> <div class="circle"></div> <div class="circle"></div> <div class="circle"></div> </div> </div> </div> </div> 
+24
Jul 26 '17 at 19:26
source share

As mentioned above, CSS3 cannot provide you with real 3D shapes, but only with an illusion. A good area of ​​illusion that uses minimal HTML elements and uses the image as a texture can be done by combining what you did and masking everything with CSS shadows.

A nice touch that can make the mask more realistic is the use of the :after pseudo-element to create an extra spark in a shifted location and a smaller size. The key to a successful effect is to remember that different materials reflect light differently. meaning, if you are trying to create a metal sphere, the lighting created by box-shadow will be different from the lighting of a plastic sphere.

Another nice addition is to use the :before pseudo-element to create a reflection effect. Adding a finished world image to a sphere with some opacity can create a very convincing effect. Pay attention also to the reflection of the material you are trying to create, which will determine the amount of opacity that you want to reflect.

Notice, I used an octagonal prism to make the image behind the scene look steeper when the 3D transformer applies its perspective. Even when using only 8 elements, the result is quite realistic. A more realistic result can be achieved by using more polygons and more complex shapes and texture mappings, but even then there is no need for too many elements due to the addition of a shadow and spark over everything.

Finally, to hide the rest of the octagonal prism and display only the parts inside the boundaries of the sphere, I use clip-path: circle(99px at center); .

 body { width: 100%; height: 100%; background-color: #000; } .cube-wrapper { width: 0; height: 0; top: 100px; left: 100px; position: absolute; perspective-origin: 0 0; perspective: 80px; } .cube-2 { transform: translateZ(-100px) scaleX(1.8); transform-style: preserve-3d; } .cube { top: -100px; position: relative; transform-style: preserve-3d; animation-name: rotate; animation-duration: 10s; animation-timing-function: linear; animation-iteration-count: infinite; } @keyframes rotate { 0% { transform: rotate3d(0 0, 0, 360deg); } 100% { transform: rotate3d(0, 1, 0, 360deg); ; } } .face { position: absolute; background-size: 662.4px 200px; width: 84px; height: 200px; } #face1 { transform: translateX(-41.4px) translateZ(100px); background-position: 0 0; } #face2 { transform: translateX(29.2px) translateZ(70.8px) rotateY(45deg); background-position: -82.8px 0; } #face3 { transform: translateX(58.5px) rotateY(90deg); background-position: -165.6px 0; } #face4 { transform: translateX(29.2px) translateZ(-70.8px) rotateY(135deg); background-position: -248.4px 0; } #face5 { transform: translateX(-41.4px) translateZ(-100px) rotateY(180deg); background-position: -331.2px 0; } #face6 { transform: translateX(-111.4px) translateZ(-70.8px) rotateY(225deg); background-position: -414px 0; } #face7 { transform: translateX(-141.4px) rotateY(270deg); background-position: -496.8px 0; } #face8 { transform: translateX(-111.4px) translateZ(70px) rotateY(315deg); background-position: -579.6px 0; } .circle { position: absolute; width: 200px; height: 200px; border-radius: 50%; } .clip-circle { position: absolute; padding: 0; top: -16px; width: 200px; height: 200px; border-radius: 50%; clip-path: circle(99px at center); } .lighting:after { content: ''; position: absolute; top: 50px; left: 67px; } .reflection:before { content: ''; position: absolute; top: 0px; left: 0px; height: 200px; width: 200px; background-image:url(https://i.stack.imgur.com/ayCw7.png); background-size: 200px 200px; } .earth { position: absolute; left: 20px; } .earth .face{ background-image:url(https://i.stack.imgur.com/fdtNz.jpg); } .earth .clip-circle { transform: rotateX(7deg) rotateZ(15deg); } .earth .lighting { box-shadow: -20px -30px 55px 0 rgba(0, 0, 0, 0.9) inset, -75px -100px 150px 0 rgba(0, 0, 0, 0.4) inset, 75px 100px 200px 0 rgba(255, 255, 255, 0.2) inset, -1px -2px 10px 2px rgba(200, 190, 255, 0.2); } .earth .lighting:after { box-shadow: 0 0 150px 51px rgba(255, 255, 255, 0.2), 0 0 26px 10px rgba(255, 255, 255, 0.2); } .wood { position: absolute; left: 240px; } .wood .face{ background-image:url(https://i.stack.imgur.com/sa5P8.jpg); } .wood .cube-wrapper { transform: rotateZ(45deg); } .wood .lighting { box-shadow: -20px -30px 90px 0 rgba(0, 0, 0, 0.7) inset, -75px -100px 140px 0 rgba(0, 0, 0, 0.6) inset; } .wood .lighting:after { box-shadow: 0 0 42px 15px rgba(255, 255, 255, 0.5); } .wood .reflection:before { opacity: 0.04; } .metal { position: absolute; left: 460px; } .metal .face{ background-image:url(https://i.stack.imgur.com/PGmVN.jpg); } .metal .cube-wrapper { transform: rotateZ(-32deg); } .metal .lighting { box-shadow: -20px -30px 100px 0 rgba(0, 0, 0, 0.9) inset, -75px -100px 107px 0 rgba(0, 0, 0, 0.3) inset, 75px 100px 127px 0 rgba(255, 255, 255, 0.23) inset; } .metal .lighting:after { box-shadow: 0 0 42px 20px rgba(255, 255, 255, 0.7), 0 0 7px 6px rgba(255, 255, 255, 0.9); } .metal .reflection:before { opacity: 0.2; } 
 <body> <div style="position:absolute;top:20px;"> <div class="earth"> <dir class="clip-circle"> <div class="cube-wrapper"> <div class="cube-2"> <div class="cube"> <div id="face1" class="face"></div> <div id="face2" class="face"></div> <div id="face3" class="face"></div> <div id="face4" class="face"></div> <div id="face5" class="face"></div> <div id="face6" class="face"></div> <div id="face7" class="face"></div> <div id="face8" class="face"></div> </div> </div> </div> </dir> <div class="circle lighting"></div> </div> <div class="wood"> <dir class="clip-circle"> <div class="cube-wrapper"> <div class="cube-2"> <div class="cube"> <div id="face1" class="face"></div> <div id="face2" class="face"></div> <div id="face3" class="face"></div> <div id="face4" class="face"></div> <div id="face5" class="face"></div> <div id="face6" class="face"></div> <div id="face7" class="face"></div> <div id="face8" class="face"></div> </div> </div> </div> </dir> <div class="circle reflection lighting"></div> </div> <div class="metal"> <dir class="clip-circle"> <div class="cube-wrapper"> <div class="cube-2"> <div class="cube"> <div id="face1" class="face"></div> <div id="face2" class="face"></div> <div id="face3" class="face"></div> <div id="face4" class="face"></div> <div id="face5" class="face"></div> <div id="face6" class="face"></div> <div id="face7" class="face"></div> <div id="face8" class="face"></div> </div> </div> </div> </dir> <div class="circle reflection lighting"></div> </div> </div> <div style="position:absolute;top:240px"> <div class="earth"> <div class="cube-wrapper"> <div class="cube-2"> <div class="cube"> <div id="face1" class="face"></div> <div id="face2" class="face"></div> <div id="face3" class="face"></div> <div id="face4" class="face"></div> <div id="face5" class="face"></div> <div id="face6" class="face"></div> <div id="face7" class="face"></div> <div id="face8" class="face"></div> </div> </div> </div> </div> <div class="wood"> <div class="cube-wrapper"> <div class="cube-2"> <div class="cube"> <div id="face1" class="face"></div> <div id="face2" class="face"></div> <div id="face3" class="face"></div> <div id="face4" class="face"></div> <div id="face5" class="face"></div> <div id="face6" class="face"></div> <div id="face7" class="face"></div> <div id="face8" class="face"></div> </div> </div> </div> </div> <div class="metal"> <div class="cube-wrapper"> <div class="cube-2"> <div class="cube"> <div id="face1" class="face"></div> <div id="face2" class="face"></div> <div id="face3" class="face"></div> <div id="face4" class="face"></div> <div id="face5" class="face"></div> <div id="face6" class="face"></div> <div id="face7" class="face"></div> <div id="face8" class="face"></div> </div> </div> </div> </div> </div> <div style="position:absolute;top:460px;"> <div class="earth"> <div class="circle lighting"></div> </div> <div class="wood"> <div class="circle reflection lighting"></div> </div> <div class="metal"> <div class="circle reflection lighting"></div> </div> </div> </body> 
+17
28 . '17 2:17
source share

3d css - 2d , .

, :

  • " "

, .

CSS, .

: ,

 .ball { position: absolute; top:0px; left:0px; width: 98vmin; height: 98vmin; margin: 1vmin; transform-style: preserve-3d; transform: rotateX(-5deg); } @keyframes rot{ 0% { transform: rotateY(0deg) rotateX(0deg) rotateZ(0deg); } 100% { transform: rotateY(360deg) rotateX(0deg) rotateZ(0deg); } } .layer { position: absolute; top: 0px; left: 0px; width: 98vmin; height: 98vmin; } .moving { transform-style: preserve-3d; transform-origin: 49vmin 49vmin; animation: rot 10s linear infinite; } .gridplane { width: 97vmin; height: 97vmin; border-radius: 50%; border: 0.5vmin dashed rgb(128, 128, 128); } .xline { transform: translateY(1%) rotateX(90deg); } .xline2 { transform: translateY(-1%) rotateX(90deg); } .yline { transform: rotateY(90deg); } .zline { transform: rotateZ(90deg); } .laser { background-color: rgba(0, 0, 0, 0.05); transform: translateX(-27.7128%) translateY(-27.7128%) rotateY(90deg) translateX(-27.7128%) rotateY(-135deg) rotateX(45deg) scale(0.3) translateY(-25%); } .laser2 { background-color: rgba(0, 0, 0, 0.05); transform: translateX(-27.0128%) translateY(-27.0128%) rotateY(90deg) translateX(-27.0128%) rotateY(-135deg) rotateX(45deg) scale(0.2) translateY(-35%); } .clip { border-radius: 50%; overflow:hidden; transform: translateZ(-0vmin); } @keyframes highlightanim { 0.00% {left: -150.00%; top: -178.00% } 12.50% {left: -117.67%; top: -179.64% } 25.00% {left: -97.69%; top: -195.87% } 28.75% {left: -95.00%; top: -207.09% } 32.50% {left: -97.69%; top: -220.70% } 40.00% {left: -117.67%; top: -240.01% } 47.50% {left: -150.00%; top: -247.50% } 55.00% {left: -182.33%; top: -240.01% } 62.50% {left: -202.31%; top: -220.70% } 68.75% {left: -205.00%; top: -207.09% } 75.00% {left: -202.31%; top: -195.87% } 87.50% {left: -182.33%; top: -179.64% } 100.00% {left: -150.00%; top: -178.00% } } .shade { position: relative; top: -150%; left: -150%; width: 400%; height: 400%; background: radial-gradient(at 50% 50%, white, black, grey, black, black); animation: highlightanim 10s linear infinite; } 
 <div class='ball'> <div class='layer moving'> <div class='layer gridplane xline'></div> <div class='layer gridplane xline2'></div> <div class='layer gridplane yline'></div> <div class='layer gridplane zline'></div> <div class='layer gridplane laser'></div> <div class='layer gridplane laser2'></div> </div> <div class='layer clip'> <div class='shade'> </div> </div> </div> 
+15
25 . '17 22:54
source share

, . 3D- HTML CSS , .

, HTML CSS .

3D- - WebGL, JavaScript API 3D-.

+6
21 . '17 13:19
source share

- , , , , , . https://codepen.io/Mamboleoo/post/sphere-css

HTML

 .mommy .daddy - for (var x = 1; x < 300; x++) span 

CSS

 @import "compass"; body{ margin: 0; display: flex; height: 100vh; overflow: hidden; justify-content: center; align-items: center; background:black; } .mommy{ width: 500px; height: 500px; position: relative; perspective: 800px; } .daddy{ width: 500px; height: 500px; transform-style: preserve-3d; animation : rotate 25s infinite linear; } span{ display: inline-block; position: absolute; top:50%; left:50%; perspective: 800px; transform-style: preserve-3d; width: 0; height: 0; &:before{ content:""; width: 4px; height: 4px; display: inline-block; position: absolute; top: calc(50% - 2px); left: calc(50% - 2px); background: currentColor; color: inherit; border-radius: 50%; animation: invertRotate 25s infinite linear, scale 2s infinite linear; box-shadow: 0 0 10px currentColor; } } $amount : 300; @for $i from 1 through $amount { $theta : ($i / $amount)*120; $phi : ($i / $amount) * pi(); $x : 250 * sin($phi) * cos($theta); $y : 250 * sin($phi) * sin($theta); $z : 250 * cos($phi); .mommy span:nth-child(#{$i}){ transform: translate3d($x+px, $y+px, $z+px); color: hsl(($i/$amount)*360,100%,50%); &:before{ animation-delay: 0s, -($i/$amount)*2+s; } } } @keyframes rotate{ to{transform:rotateY(360deg);} } @keyframes invertRotate{ to{transform:rotateY(-360deg);} } @keyframes scale{ 0%, 45%,55%{ box-shadow: 0 0 10px 0px currentColor;} 50%{ box-shadow: 0 0 10px 5px currentColor;} } 
+5
23 . '17 19:25
source share

/, . I dont know. , , CSS, .

 .ball { display: inline-block; width: 100%; height: 100%; border-radius: 100%; position: relative; background: radial-gradient(circle at bottom, #81e8f6, #76deef 10%, #055194 80%, #062745 100%); } .ball:before { content: ""; position: absolute; top: 1%; left: 5%; width: 90%; height: 90%; border-radius: 100%; background: radial-gradient(circle at top, white, rgba(255, 255, 255, 0) 58%); -webkit-filter: blur(5px); filter: blur(5px); z-index: 2; } .ball:after { content: ""; position: absolute; display: none; top: 5%; left: 10%; width: 80%; height: 80%; border-radius: 100%; -webkit-filter: blur(1px); filter: blur(1px); z-index: 2; -webkit-transform: rotateZ(-30deg); transform: rotateZ(-30deg); } .ball .shadow { position: absolute; width: 100%; height: 100%; background: radial-gradient(circle, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.1) 40%, rgba(0, 0, 0, 0) 50%); -webkit-transform: rotateX(90deg) translateZ(-160px); transform: rotateX(90deg) translateZ(-160px); z-index: 1; } .ball.plain { background: black; } .ball.plain:before, .ball.plain:after { display: none; } .ball.bubble { background: radial-gradient(circle at 50% 55%, rgba(240, 245, 255, 0.9), rgba(240, 245, 255, 0.9) 40%, rgba(225, 238, 255, 0.8) 60%, rgba(43, 130, 255, 0.4)); -webkit-animation: bubble-anim 2s ease-out infinite; animation: bubble-anim 2s ease-out infinite; } .ball.bubble:before { -webkit-filter: blur(0); filter: blur(0); height: 80%; width: 40%; background: radial-gradient(circle at 130% 130%, rgba(255, 255, 255, 0) 0, rgba(255, 255, 255, 0) 46%, rgba(255, 255, 255, 0.8) 50%, rgba(255, 255, 255, 0.8) 58%, rgba(255, 255, 255, 0) 60%, rgba(255, 255, 255, 0) 100%); -webkit-transform: translateX(131%) translateY(58%) rotateZ(168deg) rotateX(10deg); transform: translateX(131%) translateY(58%) rotateZ(168deg) rotateX(10deg); } .ball.bubble:after { display: block; background: radial-gradient(circle at 50% 80%, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0) 74%, white 80%, white 84%, rgba(255, 255, 255, 0) 100%); } .stage { width: 300px; height: 300px; display: inline-block; margin: 20px; -webkit-perspective: 1200px; -moz-perspective: 1200px; -ms-perspective: 1200px; -o-perspective: 1200px; perspective: 1200px; -webkit-perspective-origin: 50% 50%; -moz-perspective-origin: 50% 50%; -ms-perspective-origin: 50% 50%; -o-perspective-origin: 50% 50%; perspective-origin: 50% 50%; } body { width: 300px; margin: 20px auto; background: linear-gradient(to bottom, rgba(100, 100, 100, 0.2) 0%, rgba(255, 255, 255, 0.5) 40%, #ffffff 100%); background-repeat: no-repeat; } @-webkit-keyframes bubble-anim { 0% { -webkit-transform: scale(1); transform: scale(1); } 20% { -webkit-transform: scaleY(0.95) scaleX(1.05); transform: scaleY(0.95) scaleX(1.05); } 48% { -webkit-transform: scaleY(1.1) scaleX(0.9); transform: scaleY(1.1) scaleX(0.9); } 68% { -webkit-transform: scaleY(0.98) scaleX(1.02); transform: scaleY(0.98) scaleX(1.02); } 80% { -webkit-transform: scaleY(1.02) scaleX(0.98); transform: scaleY(1.02) scaleX(0.98); } 97%, 100% { -webkit-transform: scale(1); transform: scale(1); } } @keyframes bubble-anim { 0% { -webkit-transform: scale(1); transform: scale(1); } 20% { -webkit-transform: scaleY(0.95) scaleX(1.05); transform: scaleY(0.95) scaleX(1.05); } 48% { -webkit-transform: scaleY(1.1) scaleX(0.9); transform: scaleY(1.1) scaleX(0.9); } 68% { -webkit-transform: scaleY(0.98) scaleX(1.02); transform: scaleY(0.98) scaleX(1.02); } 80% { -webkit-transform: scaleY(1.02) scaleX(0.98); transform: scaleY(1.02) scaleX(0.98); } 97%, 100% { -webkit-transform: scale(1); transform: scale(1); } } 
 <section class="stage"> <figure class="ball bubble"></figure> </section> 
+4
26 . '17 20:44
source share



All Articles