tricks rotate multiple deg cross css css3 css-animations css-shapes css-transforms

css - rotate - transform skew 45 deg



¿Cómo puedo crear esferas tridimensionales de CSS puro? (7)

Aquí hay un ejemplo de una esfera / burbuja animada, aunque este ejemplo es más una ilusión. No sé si todo lo que está pidiendo es posible solo a través de CSS puro, pero puedo estar equivocado.

.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>

tl; dr: Me gustaría crear una esfera 3d real con CSS, no solo una ilusión

Nota: algunos de los ejemplos de fragmentos no responden. Por favor, use la pantalla completa.

Con CSS puro puedes crear y animar un cubo 3D de esta manera:

#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>

Quiero crear y animar una esfera 3d de la misma manera.

Entonces ... la primera idea que obtengo es usar border-radius y ... bueno ... no funciona.

#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>

Entonces, reconsideré mi enfoque y busqué un método diferente.

Miré:

Luego intenté de nuevo ... lo mejor que obtuve fueron ilusiones de objetos 3D demasiado complicadas .

Me gusta esto:

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>

Y esto:

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>

Lo cual está bien hasta que intentes rotarlos en el eje x o en el eje y como el cubo en mi primer ejemplo ... esto es lo que sucede entonces: (ejemplo simplificado)

.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>

Todo lo que obtienes es un objeto 2D plano, que se experta teniendo en cuenta que es lo que es el elemento

Lo más parecido que encontré es la siguiente forma creada en un tutorial por Timo Korinth

@-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>

Así que aquí está mi

Pregunta:

¿Cómo creo una esfera tridimensional real con CSS puro? Más específicamente, uno que está cubierto, no solo un marco, y no involucra cientos de elementos html.

Notas:

  1. Las esferas tridimensionales tienen altura, ancho y profundidad , al igual que el cubo en mi primer fragmento de ejemplo
  2. No necesito ninguna física y no hay necesidad de interacción del usuario. Solo una esfera giratoria animada.

Recursos adicionales:

  1. paulrhayes.com - Esferas
  2. Tierra 3D (ilusión 2d) con animación giratoria con CSS
  3. Esfera CSS interactiva

Eche un vistazo a esto: suena como lo que necesita y con fragmentos de código que con suerte podría editar a su gusto. 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;} }


Como ya se mencionó anteriormente, CSS3 no puede proporcionarle formas reales en 3D, sino solo la ilusión. Una buena ilusión de esfera que usa elementos HTML mínimos y usa la imagen como textura se puede hacer mediante una combinación de lo que has hecho y enmascarando todo con sombras CSS.

Un buen toque que puede hacer que la máscara sea más realista es el uso del pseudo elemento :after para la creación de una chispa adicional en una ubicación desplazada y un tamaño más pequeño. Una cosa clave para un efecto exitoso es recordar que diferentes materiales reflejan la luz de manera diferente. lo que significa que si está tratando de crear una esfera metálica, la iluminación creada por la box-shadow será diferente de la iluminación de una esfera de plástico.

Otra buena adición es el uso del pseudo elemento :before para la creación del efecto de reflexión. Agregar una imagen prefabricada del mundo en una esfera con cierta opacidad puede crear un efecto muy persuasivo. observe también con el reflejo que el material que está tratando de crear determinará la cantidad de opacidad que desea para el reflejo.

Tenga en cuenta que usé un prisma octogonal para que la imagen detrás de la escena se vea más redonda cuando la transformación 3D aplica su perspectiva. Incluso con el uso de solo 8 elementos, el resultado es bastante realista. Se puede lograr un resultado más realista con más polígonos y formas más complejas y mapeos de texturas, pero aun así no se necesitan demasiados elementos debido a la adición de la sombra y la chispa sobre todo.

Por último, para ocultar el resto del prisma octogonal y mostrar solo las partes dentro de los límites de la esfera, estoy usando 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>


Estrictamente hablando, cualquier forma "3D" en una pantalla plana es más una ilusión de un objeto 3D. Todo lo que vemos es una proyección 2D de esa forma en el plano de la pantalla, y nuestro cerebro hace todo lo posible para adivinar qué forma podría dar la proyección que vemos. Si la proyección cambia, nuestro cerebro lo interpreta como un objeto 3D que cambia su orientación, lo que le ayuda a determinar mejor la forma de este objeto.

Funciona bien con objetos no simétricos y objetos hechos de polígonos (por ejemplo, cubos), pero la esfera es un caso muy especial: su proyección en el plano siempre da solo un círculo. La esfera estática y la giratoria tienen la misma proyección, el mismo círculo. Incluso en la vida real, si observamos una esfera con una superficie uniforme sin ninguna marca (por ejemplo, una bola de metal pulida), es difícil determinar si se detiene o gira. Nuestros ojos necesitan algunas pistas, algunos detalles que se mueven a lo largo de la superficie de la esfera según su geometría. Mientras más detalles se muevan de la manera que espera que se muevan los puntos en la superficie esférica, más clara será la percepción (bueno, la ilusión) de la esfera giratoria.

Y aquí está la clave del problema al hacer una escena CSS que daría tal percepción: para hacer que esta ilusión sea lo suficientemente fuerte, necesitamos muchas marcas que se muevan a lo largo de los caminos que se encuentran en diferentes planos. Y la única forma de obtener esto en CSS es tener cada marca como un cuadro CSS separado (elemento o pseudo-elemento). Si nuestra esfera consta solo de marcas en movimiento, realmente necesitamos muchas de ellas para verla como una esfera, por lo tanto, "cientos de elementos" en la mayoría de las demostraciones que ha visto.

Entonces, si desea que una esfera parezca realista con un número razonablemente pequeño de elementos, probablemente necesite combinar los efectos que crean una "ilusión" de una forma esférica básica estática (un círculo con gradientes radiales, sombras internas, etc.) con algunos elementos que son relativamente pequeños (para que sea menos obvio que en realidad son planos), orientados a lo largo de la superficie de la esfera con transformaciones 3D y animados, básicamente de la misma manera que las caras del cubo en su primera demostración.

A continuación se muestra mi propio intento de poner en práctica este enfoque. Utilicé 20 elementos circulares orientados aproximadamente como las caras del icosaedro regular (como hexágonos blancos en el clásico balón de fútbol). Los agrupé en dos grupos, cada uno formando un hemisferio por conveniencia (no era necesario, pero hizo que el estilo fuera un poco más simple). Toda la escena 3D consiste en la esfera misma y el marco de fondo (pseudo elemento) que cruza la esfera cerca de su centro (un poco más cerca, para reducir el "parpadeo" de los círculos a medida que avanzan desde el lado cercano hacia el lado lejano y viceversa ) y siempre se enfrenta a la pantalla. Entonces, 24 elementos en total (no literalmente "cientos", al menos :). Para hacer que los círculos se vean más "abultados" (como segmentos esféricos), agregué dos pseudo elementos a cada uno de ellos y los elevé ligeramente uno por encima del otro. Funciona mejor en Chrome y Firefox 57+ (en Firefox 56- y iOS Safari todavía hay algunos "parpadeos" cerca de los bordes). Si pasa el círculo, puede ver la escena sin el marco de fondo (y también sin "parpadeo"). Una versión ligeramente modificada también está disponible en 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>


Hacer una esfera css 3d realista, sin cierto nivel de ilusión 2D, requeriría muchos elementos para que tenga un perímetro suave.

Sin embargo, hice una versión del ejemplo de Timo Korinth con:

  • Recorte de las líneas de la cuadrícula "hacia atrás"
  • Sombreado esférico aproximado al mover un degradado radial

Se puede girar arbitrariamente siempre que se vuelva a calcular la animación de sombreado.

Esta página tiene algunas de las matemáticas detrás de la implementación de sombreado esférico con CSS que podrían usarse para esto.

Editar: otras respuestas se ven mejor, así que conviértalo en una Estrella de la Muerte

.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>


No, no es posible bajo tus criterios. Todos los ejemplos de cosas en 3D que usan solo HTML y CSS tienen problemas de rendimiento, porque ese no es su propósito.

Cuando se trata de efectos gráficos pesados, HTML y CSS son realmente malos.

La mejor manera de crear una esfera 3D real es usar WebGL, que es una API de JavaScript para crear contenido 3D.


¿Cómo creo una esfera tridimensional real con CSS puro?

Bueno, como muchos han declarado en respuestas y comentarios, es simplemente imposible crear una sola entidad 3D en un navegador con html y css solo en este momento, pero es posible crear una ilusión de un Objeto 3D. A continuación se muestra mi enfoque para resolver el problema.

Para dar al ojo humano la capacidad de ver un objeto esférico, se necesitan puntos de referencia para que el ojo lo siga. En mi caso, son las líneas las que definen la forma de la esfera. Las líneas se logran dando un borde a 5 elementos que están en el conjunto del eje X y 5 elementos que están en el conjunto del eje Y. Solo los conjuntos X / Y tienen un borde, porque eso solo proporciona suficiente referencia para crear la ilusión de una esfera. Las líneas adicionales en el eje Z son simplemente desorden y son innecesarias. Si todas las líneas están apagadas, todo aparece como una esfera sólida "perfecta" (¡Parece un círculo, pero todas las partes se mueven y están presentes en el plano 3D en el navegador!).

Que he hecho:

  1. Se crearon 15 elementos html que cada uno representará un círculo dividido en 3 conjuntos de 5

    La razón de todos estos conjuntos es que cuando todo el artilugio gira en los ejes x, y, z, los fondos de cada uno de los elementos en los conjuntos x, y, z llenan los espacios vacíos entre sí.

  2. Cada conjunto de 5 elementos gira en los ejes X, Y, Z, respectivamente, en incrementos de 36 grados.
  3. Todos los elementos se redondean con border-radius:50%;
  4. Establecer el fondo de los elementos del círculo en un color sólido.
  5. Pon los conjuntos juntos, para que se superpongan
  6. Brechas menores recortadas que resultaron de la falta de elementos suficientes que cubran los espacios vacíos entre los círculos x, y, z usando clip-path: circle(96px at center); en el contenedor, y arrojó un efecto de sombra / luz fría para sellar el trato
    vs

    Más círculos darán como resultado una esfera menos "nerviosa", pero dado que el rendimiento está enfatizado en la pregunta, un clip rápido de todo parece ser lo que hay que hacer.

Como pensamiento final, quería expresar mi agradecimiento por la pregunta que se hizo, realmente me hizo pensar y fue un gran proyecto que me llevó a aprender muchas cosas sobre las capacidades 3D de html / css.

También gracias a todas las personas que han dedicado tiempo a abrir esto, y han ideado enfoques increíbles para el problema.

Espero que los frutos de mi investigación sean de utilidad. ¡Aclamaciones!

Esta pluma también se basa en el ejemplo de Timo Korinth.

* { 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>