CSS를 사용하여 롤러 코스터 스타일의 애니메이션을 만들려고합니다.
루프 단계에있을 때 “코스터”를 구부리는 방법을 알고 싶습니다.
모든 CSS 솔루션을 찾고 있지만 약간의 JavaScript가 필요하다면 괜찮습니다.
지금까지 내 코드 :
#container {
width: 200px;
height: 300px;
margin-top: 50px;
position: relative;
animation: 10s infinite loop;
animation-timing-function: linear;
}
#coaster {
width: 100px;
height: 10px;
background: lightblue;
position: absolute;
bottom: 0;
left: 1px;
right: 1px;
margin: 0 auto;
}
@keyframes loop {
from {
margin-left: -200px;
}
30% {
margin-left: calc(50% - 75px);
transform: rotate(0deg);
}
60% {
margin-left: calc(50% - 125px);
transform: rotate(-360deg);
}
to {
transform: rotate(-360deg);
margin-left: 100%;
}
}
<div id="container">
<div id="coaster"></div>
</div>
답변
당신은 고려할 수 있습니다 border-radius
. 다음은 개선 할 수있는 기본 예입니다.
투명한 곡선 경로 뒤에 직사각형 모양을 애니메이션으로 만들 수있는 또 다른 미친 아이디어 :
코드가 적고 투명성이있는 최적화 된 버전 (이를 고려할 것 mask
입니다)
픽셀 값이 적고 모든 것을 쉽게 조정할 수있는 CSS 변수가있는 다른 버전입니다.
전체 페이지에서 스 니펫을 실행하고 모든 코스터와 재미있게 보내십시오!
.box {
--w:400px; /* Total width of the coaster */
--h:180px; /* Height of the coaster */
--b:90px; /* width of the small bar */
--t:15px; /* height of the small bar */
--c:blue; /* Color of the small bar */
width:var(--w);
height:var(--h);
}
.box > div {
height: 100%;
position:relative;
width: calc(50% + var(--h)/2 + var(--b)/2);
border-radius: 0 1000px 1000px 0;
animation: hide 3s infinite linear alternate;
-webkit-mask:
linear-gradient(#fff,#fff) top left /calc(100% - var(--h)/2) var(--t),
linear-gradient(#fff,#fff) bottom left/calc(100% - var(--h)/2) var(--t),
radial-gradient(farthest-side at left,transparent calc(100% - var(--t)),#fff 0) right/calc(var(--h)/2) 100%;
-webkit-mask-repeat:no-repeat;
mask:
linear-gradient(#fff,#fff) top left /calc(100% - var(--h)/2) var(--t),
linear-gradient(#fff,#fff) bottom left/calc(100% - var(--h)/2) var(--t),
radial-gradient(farthest-side at left,transparent calc(100% - var(--t)),#fff 0) right/calc(var(--h)/2) 100%;
mask-repeat:no-repeat;
}
.box > div:last-child {
margin-top:calc(-1*var(--h));
margin-left:auto;
transform: scaleX(-1);
animation-direction: alternate-reverse;
}
.box > div:before {
content: "";
position: absolute;
width: var(--b);
height: 50%;
background: var(--c);
bottom: -25%;
animation: loop 3s infinite linear alternate;
transform-origin: 50% -50%;
}
.box > div:last-child:before {
animation-direction: alternate-reverse;
}
@keyframes loop {
15% {
transform: translateX(calc(var(--w)/2)) rotate(0deg);
}
40% {
transform: translateX(calc(var(--w)/2)) rotate(-180deg);
}
50%,100% {
transform: translateX(calc(var(--w)/2 - var(--b)/2)) rotate(-180deg);
}
}
@keyframes hide {
50% {
visibility: visible;
}
50.1%,100% {
visibility: hidden;
}
}
body {
background:linear-gradient(to right,yellow,gray);
}
<div class="box">
<div></div><div></div>
</div>
<div class="box" style="--w:500px;--h:80px;--b:50px;--c:red;--t:5px">
<div></div><div></div>
</div>
<div class="box" style="--w:90vw;--h:200px;--b:100px;--c:purple;--t:20px">
<div></div><div></div>
</div>
트릭을 이해하려면 마스크를 제거하고 간단한 그라데이션으로 바꾸고 숨기기 애니메이션을 제거하십시오.
그라디언트로 생성 된 경로는 마스크이며 해당 부분 만 볼 수 있습니다. 그런 다음 사각형을 경로를 따르도록 만들고 트릭은 루프 효과를 만들기 위해 두 개의 대칭 요소를 갖는 것입니다. 숨기기 애니메이션은 우리가 그 중 하나를 볼 수 있도록하고 완벽한 중복 연속 애니메이션을 만들 것입니다.
코스터 원을 원할 경우의 버전입니다
.box {
--w:400px; /* Total width of the coaster */
--h:180px; /* Height of the coaster */
--b:90px; /* width of the small bar */
--t:15px; /* height of the small bar */
--c:blue; /* Color of the small bar */
width:var(--w);
height:var(--h);
}
.box > div {
height: 100%;
position:relative;
width: calc(50% + var(--h)/2);
border-radius: 0 1000px 1000px 0;
animation: hide 3s infinite linear alternate;
-webkit-mask:
radial-gradient(farthest-side at bottom right,transparent calc(100% - var(--t)),#fff 0 100%,transparent 100%) top 0 right calc(var(--h)/2)/calc(var(--h)/2) 50%,
linear-gradient(#fff,#fff) bottom left/calc(100% - var(--h)/2) var(--t),
radial-gradient(farthest-side at left,transparent calc(100% - var(--t)),#fff 0) right/calc(var(--h)/2) 100%;
-webkit-mask-repeat:no-repeat;
mask:
radial-gradient(farthest-side at bottom right,transparent calc(100% - var(--t)),#fff 0 100%,transparent 100%) top 0 right calc(var(--h)/2)/calc(var(--h)/2) 50%,
linear-gradient(#fff,#fff) bottom left/calc(100% - var(--h)/2) var(--t),
radial-gradient(farthest-side at left,transparent calc(100% - var(--t)),#fff 0) right/calc(var(--h)/2) 100%;
mask-repeat:no-repeat;
}
.box > div:last-child {
margin-top:calc(-1*var(--h));
margin-left:auto;
transform: scaleX(-1);
animation-direction: alternate-reverse;
}
.box > div:before {
content: "";
position: absolute;
width: var(--b);
height: 50%;
background: var(--c);
bottom: -25%;
animation: loop 3s infinite linear alternate;
transform-origin: 50% -50%;
}
.box > div:last-child:before {
animation-direction: alternate-reverse;
}
@keyframes loop {
15% {
transform: translateX(calc(var(--w)/2 - var(--b)/2)) rotate(0deg);
}
50%,100% {
transform: translateX(calc(var(--w)/2 - var(--b)/2)) rotate(-180deg);
}
}
@keyframes hide {
50% {
visibility: visible;
}
50.1%,100% {
visibility: hidden;
}
}
body {
background:linear-gradient(to right,yellow,gray);
}
<div class="box">
<div></div><div></div>
</div>
<div class="box" style="--w:500px;--h:80px;--b:50px;--c:red;--t:5px">
<div></div><div></div>
</div>
<div class="box" style="--w:90vw;--h:200px;--b:100px;--c:purple;--t:20px">
<div></div><div></div>
</div>
답변
감사합니다. 특히 영감을 주신 Temani Afif 에게 감사드립니다 .]
나는 결국 border-radius
요소를 숨기고 약간의 HTML을 사용하여 많은 답변을 결합 하여 애니메이션을위한 훌륭한 솔루션을 만들었다 고 생각합니다.
* {
box-sizing: border-box;
}
#container {
width: 100px;
height: 100px;
margin-top: 50px;
position: relative;
animation: 5s infinite loop linear;
}
#coasterLine {
height: 10px;
background: lightblue;
position: absolute;
z-index: 20;
bottom: 0;
animation: 5s infinite c-line linear;
}
#coasterRound {
width: 100%;
height: 100%;
border-radius: 50%;
border: solid transparent 10px;
border-bottom: solid lightblue 10px;
position: relative;
animation: 5s infinite c-round linear;
}
#whiteScreen {
width: 100%;
background: white;
position: absolute;
z-index: 10;
top: 0;
animation: 5s infinite white-screen linear;
}
@keyframes loop {
0% {
margin-left: -200px;
}
38%,
43% {
margin-left: calc(50% - 50px);
}
58%,
63% {
margin-left: calc(50% - 50px);
}
100% {
margin-left: 100%;
}
}
@keyframes c-round {
0%,
43% {
transform: rotate(-45deg);
}
58%,
100% {
transform: rotate(-315deg);
}
}
@keyframes c-line {
0%,
38% {
left: 0;
width: 60px;
}
43% {
left: 50px;
width: 0;
}
58% {
left: 40px;
width: 0;
}
63%,
100% {
left: 40px;
width: 60px;
}
}
@keyframes white-screen {
0%,
38% {
height: 100%;
transform: rotate(0deg);
}
43% {
height: 50%;
transform: rotate(0deg);
}
44%,
57% {
height: 0;
transform: rotate(0deg);
}
58% {
height: 50%;
transform: rotate(180deg);
}
63%,
100% {
height: 100%;
transform: rotate(180deg);
}
}
<div id="container">
<div id="coasterLine"></div>
<div id="coasterRound"></div>
<div id="whiteScreen"></div>
</div>
대단해!
답변
실제로 자연스럽지 않지만 border-radius
시작하는 좋은 방법 인 것 같습니다.
#container {
width: 200px;
height: 300px;
margin-top: 50px;
position: relative;
animation: 10s infinite loop;
animation-timing-function: linear;
}
#coaster {
width: 100px;
height: 10px;
background: lightblue;
position: absolute;
bottom: 0;
left: 1px;
right: 1px;
margin: 0 auto;
animation: 10s infinite coasterAnimation;
}
@keyframes loop {
from {
margin-left: -200px;
}
30% {
margin-left: calc(50% - 75px);
transform: rotate(0deg);
}
60% {
margin-left: calc(50% - 125px);
transform: rotate(-360deg);
}
to {
transform: rotate(-360deg);
margin-left: 100%;
}
}
@keyframes coasterAnimation {
29% {
border-radius: 0;
}
30% {
border-radius: 0 0 50% 50%;
}
59% {
border-radius: 0 0 50% 50%;
}
60% {
border-radius: 0;
}
70% {
border-radius: 0;
}
}
<div id="container">
<div id="coaster"></div>
</div>
답변
나는 아래의 접근 방식이 다소 건전하다고 생각한다.
a로 대신 롤러 코스터의이 표현되고있는 <div>
가에 의해 표현된다 border-bottom
의 <div>
.
테두리 자체의 동시 애니메이션에서으로 돌아 가기 전에 border-bottom-left-radius
및 시간이 지남에 따라 border-bottom-left-radius
구부러 50%
집니다 0
.
작업 예 :
#container {
width: 180px;
height: 180px;
position: relative;
animation: 10s loop-container linear infinite;
}
#coaster {
width: 180px;
height: 180px;
border-bottom: 10px solid lightblue;
position: absolute;
bottom: 0;
left: 1px;
right: 1px;
margin: 0 auto;
animation: 10s loop-coaster linear infinite;
}
@keyframes loop-container {
0% {
margin-left: -200px;
}
30% {
margin-left: calc(50% - 75px);
transform: rotate(0deg);
}
60% {
margin-left: calc(50% - 125px);
transform: rotate(-360deg);
}
100% {
transform: rotate(-360deg);
margin-left: 100%;
}
}
@keyframes loop-coaster {
30% {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
31% {
border-bottom-left-radius: 0;
border-bottom-right-radius: 25%;
}
35%, 55% {
border-bottom-left-radius: 50%;
border-bottom-right-radius: 50%;
}
59% {
border-bottom-left-radius: 25%;
border-bottom-right-radius: 0;
}
60% {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
}
<div id="container">
<div id="coaster"></div>
</div>