Codepen: http://codepen.io/Rplus/details/LNwXBO/
gist: https://gist.github.com/Rplus/a7a93f34dd2ae52780fddccfd10d96d1
| <!DOCTYPE html> | |
| html(lang="en") | |
| head | |
| meta(charset="UTF-8") | |
| title Rotating Möbiusband in 3D CSS | |
| meta(name="viewport", content="width=device-width") | |
| link(rel="stylesheet", href="style.css") | |
| body | |
| h1.intro Rotating Möbiusband | |
| small in 3D CSS | |
| input.sr-only#revolution(type="checkbox", checked) | |
| input.sr-only#rotation(type="checkbox") | |
| input.sr-only#revolution-dir--clockwise(type="radio", name="revolution-dir", checked) | |
| input.sr-only#revolution-dir--anticlockwise(type="radio", name="revolution-dir") | |
| input.sr-only#rotation-dir--clockwise(type="radio", name="rotation-dir", checked) | |
| input.sr-only#rotation-dir--anticlockwise(type="radio", name="rotation-dir") | |
| .controls | |
| dl.controls__revolution | |
| dt.pri-controls | |
| label.control-label(for="revolution") Revolution | |
| dd.sub-controls | |
| label.control-label.control-label--radio(for="revolution-dir--clockwise") clockwise | |
| dd.sub-controls | |
| label.control-label.control-label--radio(for="revolution-dir--anticlockwise") anticlockwise | |
| dl.controls__rotation | |
| dt.pri-controls | |
| label.control-label(for="rotation") Rotation | |
| dd.sub-controls | |
| label.control-label.control-label--radio(for="rotation-dir--clockwise") clockwise | |
| dd.sub-controls | |
| label.control-label.control-label--radio(for="rotation-dir--anticlockwise") anticlockwise | |
| - var i = 100; | |
| .box | |
| - while(i--) | |
| .s | |
| blockquote.info | |
| | ref: #[a(href="https://en.wikipedia.org/wiki/M%C3%B6bius_strip") Möbius strip] |
| $c-bgc: #e7e5d8; | |
| $count: 100; | |
| $strip-ratio: 20; | |
| $strip-width: 1vmin; | |
| .s { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: $strip-width; | |
| height: $strip-width * $strip-ratio; | |
| transform-style: preserve-3d; | |
| &::before { | |
| content: ""; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background-image: linear-gradient(90deg, rgba(#000, .5), rgba(#fff, .75)); | |
| animation: rotation 10s linear infinite paused; | |
| #rotation:checked ~ .box & { | |
| // animation-play-state: running; | |
| animation: rotation 10s linear infinite; | |
| } | |
| // safari mobile doesn't support | |
| // via: https://developer.mozilla.org/en-US/docs/Web/CSS/animation-direction#Browser_compatibility | |
| @supports (animation-direction: reverse) { | |
| #rotation-dir--anticlockwise:checked ~ .box & { | |
| animation-direction: reverse; | |
| } | |
| } | |
| } | |
| @for $i from 1 through $count { | |
| &:nth-of-type(#{$i}) { | |
| transform: | |
| rotateY(#{$i * 360deg / $count}) | |
| translateZ(20vmin) | |
| rotateX(#{$i * 180deg / $count}); | |
| } | |
| } | |
| } | |
| .box { | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| transform-style: preserve-3d; | |
| transform: rotateX(-30deg); | |
| animation: revolution 10s linear infinite paused; | |
| #revolution:checked ~ & { | |
| // animation-play-state: running; | |
| animation: revolution 10s linear infinite; | |
| } | |
| @supports (animation-direction: reverse) { | |
| #revolution-dir--anticlockwise:checked ~ & { | |
| animation-direction: reverse; | |
| } | |
| } | |
| } | |
| @keyframes rotation { | |
| from { | |
| transform: rotateX(0deg); | |
| } | |
| to { | |
| transform: rotateX(360deg); | |
| } | |
| } | |
| @keyframes revolution { | |
| from { | |
| transform: rotateX(-30deg) rotateY(0deg); | |
| } | |
| to { | |
| transform: rotateX(-30deg) rotateY(-360deg); | |
| } | |
| } | |
| /// reset | |
| *, | |
| *::before, | |
| *::after { | |
| box-sizing: border-box; | |
| margin: 0; | |
| } | |
| html { | |
| height: 100%; | |
| } | |
| body { | |
| display: flex; | |
| flex-direction: column; | |
| min-height: 100%; | |
| margin: 0; | |
| background: $c-bgc; | |
| color: #333; | |
| text-align: center; | |
| } | |
| a { | |
| color: inherit; | |
| } | |
| .intro { | |
| width: 90%; | |
| max-width: 30rem; | |
| padding-bottom: 1rem; | |
| margin: 0 auto 1em; | |
| padding-top: .5em; | |
| font-size: calc(1rem + 2vmin); | |
| text-transform: capitalize; | |
| border-bottom: 1px dashed rgba(#000, .3); | |
| small { | |
| display: block; | |
| opacity: .5; | |
| font-style: italic; | |
| text-transform: none; | |
| } | |
| } | |
| .info { | |
| margin-top: auto; | |
| padding: 1em; | |
| font-size: .9em; | |
| font-style: italic; | |
| font-family: serif; | |
| text-align: right; | |
| opacity: .5; | |
| } | |
| .sr-only { | |
| position: absolute; | |
| width: 1px; | |
| height: 1px; | |
| padding: 0; | |
| margin: -1px; | |
| overflow: hidden; | |
| clip: rect(0, 0, 0, 0); | |
| border: 0; | |
| } | |
| .controls { | |
| display: flex; | |
| margin-left: auto; | |
| margin-right: auto; | |
| text-align: left; | |
| line-height: 1.7; | |
| @media (max-height: 30em) and (orientation: landscape) { | |
| margin-right: 45%; | |
| & ~ .box { | |
| left: calc(50% + 40vmin); | |
| } | |
| } | |
| dl { | |
| margin-left: 1em; | |
| margin-right: 1em; | |
| } | |
| } | |
| .pri-controls { | |
| margin-bottom: .5em; | |
| } | |
| .sub-controls { | |
| margin-left: 1em; | |
| font-size: .9em; | |
| opacity: 0; | |
| transition: opacity .2s; | |
| } | |
| .control-label { | |
| cursor: pointer; | |
| display: inline-flex; | |
| align-items: center; | |
| &::before { | |
| content: ""; | |
| width: 1.2em; | |
| height: 1.2em; | |
| margin-right: .25em; | |
| border: 2px solid; | |
| vertical-align: middle; | |
| } | |
| &.control-label--radio::before { | |
| border-radius: 50%; | |
| } | |
| } | |
| #revolution:checked ~ .controls [for="revolution"], | |
| #revolution-dir--clockwise:checked ~ .controls [for="revolution-dir--clockwise"], | |
| #revolution-dir--anticlockwise:checked ~ .controls [for="revolution-dir--anticlockwise"], | |
| #rotation:checked ~ .controls [for="rotation"], | |
| #rotation-dir--clockwise:checked ~ .controls [for="rotation-dir--clockwise"], | |
| #rotation-dir--anticlockwise:checked ~ .controls [for="rotation-dir--anticlockwise"] { | |
| &::before { | |
| box-shadow: | |
| inset 0 0 0 .2em $c-bgc, | |
| inset 0 0 0 1em; | |
| } | |
| } | |
| #revolution:checked ~ .controls .controls__revolution, | |
| #rotation:checked ~ .controls .controls__rotation { | |
| .sub-controls { | |
| opacity: .8; | |
| } | |
| } |