https://codepen.io/kunukn/pen/qBWRLZB
HTML :
<div class="app">
<div class="ring">
<div class="topic" data-topic="good">
<button class="js btn">Good</button>
<div class="line-wrap">
<div class="line"></div>
</div>
<label class="display btn">Good</label>
</div>
<div class="topic" data-topic="fast">
<button class="js btn">Fast</button>
<div class="line-wrap">
<div class="line"></div>
</div>
<label class="display btn">Fast</label>
</div>
<div class="topic" data-topic="cheap">
<button class="js btn">Cheap</button>
<div class="line-wrap">
<div class="line"></div>
</div>
<label class="display btn">Cheap</label>
</div>
<button class="js topic-result topic-result--1"></button>
<button class="js topic-result topic-result--2"></button>
<div class="ring-background-2">
<div class="bg-line bg-line--3"></div>
<div class="bg-line bg-line--1"></div>
<div class="bg-line bg-line--2"></div>
<svg viewBox="0 15 100 100">
<polygon points="50 15, 100 100, 0 100"/>
</svg>
</div>
</div>
</div>
<a target="_blank" class="reference" href="https://twitter.com/FrazDav/status/1164207783081848832?s=09">inspiration</a>
CSS :
* {
box-sizing: border-box;
}
body {
font-family: "Source Sans Pro", Verdana, sans-serif;
margin: 0;
min-height: 100vh;
overflow: hidden;
background: linear-gradient(#5c627d 50%, #2e3255);
}
button {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
outline: none;
}
.app {
position: relative;
margin: 0 auto;
max-width: 800px;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
flex-wrap: wrap;
font-size: 18px;
}
.btn {
font-size: inherit;
background: none;
cursor: pointer;
border-radius: 70px;
width: 70px;
height: 70px;
text-transform: uppercase;
background: transparent;
-webkit-transform: translateZ(0);
transform: translateZ(0);
outline: none;
border: none;
font-weight: bold;
color: transparent;
font-size: inherit;
box-shadow: 0px 10px 13px -6px rgba(0, 0, 0, 0.2), 0px 20px 31px 3px rgba(0, 0, 0, 0.14), 0px 8px 38px 7px rgba(0, 0, 0, 0.12);
}
.btn.display {
font-weight: bold;
display: block;
pointer-events: none;
position: absolute;
top: 0;
left: 0;
box-shadow: none;
text-align: center;
line-height: 70px;
font-size: inherit;
color: white;
}
.btn-clicked {
pointer-events: none;
position: absolute;
top: 0;
left: 0;
width: 70px;
height: 70px;
background: white;
border-radius: 50%;
opacity: 0.5;
-webkit-animation: btn-clicked 500ms forwards;
animation: btn-clicked 500ms forwards;
}
@-webkit-keyframes btn-clicked {
100% {
opacity: 0;
-webkit-transform: scale(1.5);
transform: scale(1.5);
}
}
@keyframes btn-clicked {
100% {
opacity: 0;
-webkit-transform: scale(1.5);
transform: scale(1.5);
}
}
.text {
font-weight: bold;
position: absolute;
top: 0;
left: 0;
color: inherit;
font-size: inherit;
text-transform: uppercase;
outline: 1px solid pink;
width: 70px;
height: 70px;
display: flex;
justify-content: center;
align-items: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.ring {
width: 70px;
height: 70px;
position: relative;
color: white;
}
.ring-background-2 {
position: absolute;
width: 420px;
height: 420px;
top: -23.3333333333px;
left: 0;
-webkit-transform: translate(calc(-50% + 35px), calc(-50% + 35px)) scale(0.7);
transform: translate(calc(-50% + 35px), calc(-50% + 35px)) scale(0.7);
z-index: -1;
}
.ring-background-2 .bg-line {
position: absolute;
top: 0;
left: calc(50% - 70px);
background: linear-gradient(315deg, #181e45 50%, #343a5d);
background: #181e45;
width: 140px;
height: 434px;
border-radius: 140px;
}
.ring-background-2 .bg-line--1 {
-webkit-transform-origin: 50% 70px;
transform-origin: 50% 70px;
-webkit-transform: rotate(30deg);
transform: rotate(30deg);
}
.ring-background-2 .bg-line--1::before {
content: "";
display: block;
width: 2px;
height: 50%;
top: 25%;
left: -1px;
position: absolute;
box-shadow: 0 0 10px #333;
z-index: -1;
}
.ring-background-2 .bg-line--2 {
-webkit-transform-origin: 50% 70px;
transform-origin: 50% 70px;
-webkit-transform: rotate(-30deg);
transform: rotate(-30deg);
}
.ring-background-2 .bg-line--3 {
box-shadow: 0 0 30px #333;
-webkit-transform-origin: 50% 70px;
transform-origin: 50% 70px;
height: 140px;
width: 420px;
top: auto;
bottom: 0;
left: 0;
-webkit-transform: translateY(-25px);
transform: translateY(-25px);
}
.ring-background-2 svg {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 0;
}
.ring-background-2 svg polygon {
background: linear-gradient(315deg, #181e45 50%, #343a5d);
fill: #181e45;
}
.reference {
position: fixed;
bottom: 4px;
right: 4px;
font-size: 14px;
color: #ddd;
}
.line-wrap {
pointer-events: none;
position: absolute;
top: 0;
left: 0;
width: 70px;
height: 70px;
}
.line {
pointer-events: none;
border-radius: 70px;
position: absolute;
top: 0;
left: 0;
width: 70px;
height: 100%;
opacity: 1;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
transition: 500ms;
}
.topic-result {
cursor: pointer;
border: 0;
transition: 500ms;
-webkit-transform: scale(0) translateZ(0);
transform: scale(0) translateZ(0);
position: absolute;
top: 0;
left: 0;
width: 70px;
height: 70px;
border-radius: 50%;
font-size: 40px;
box-shadow: 0px 10px 13px -6px rgba(0, 0, 0, 0.2), 0px 20px 31px 3px rgba(0, 0, 0, 0.14), 0px 8px 38px 7px rgba(0, 0, 0, 0.12);
}
.topic-result.is-active {
-webkit-transform: scale(1.1) translateZ(0);
transform: scale(1.1) translateZ(0);
transition-timing-function: cubic-bezier(0.07, 1.12, 0.74, 1.06);
}
.topic {
position: absolute;
top: 0;
left: 0;
}
.topic.is-active .line {
width: 250%;
transition-timing-function: cubic-bezier(0.07, 1.12, 0.74, 1.06);
}
.topic[data-topic="good"] {
-webkit-transform: translateY(-105px) translateX(0px);
transform: translateY(-105px) translateX(0px);
}
.topic[data-topic="good"] .line-wrap {
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
.topic[data-topic="good"] .line {
background: dodgerblue;
}
.topic[data-topic="fast"] {
-webkit-transform: translateY(52.4999999626px) translateX(-90.9326671629px);
transform: translateY(52.4999999626px) translateX(-90.9326671629px);
}
.topic[data-topic="fast"] .line-wrap {
-webkit-transform: rotate(-30deg);
transform: rotate(-30deg);
}
.topic[data-topic="fast"] .line {
background: crimson;
}
.topic[data-topic="cheap"] {
-webkit-transform: translateY(52.5px) translateX(90.9326673974px);
transform: translateY(52.5px) translateX(90.9326673974px);
}
.topic[data-topic="cheap"] .line-wrap {
-webkit-transform: rotate(210deg);
transform: rotate(210deg);
}
.topic[data-topic="cheap"] .line {
background: mediumseagreen;
}
Javascript :
const log = console.log;
// Quick prototyping, don't take the namings and algorithm to seriously.
let topics = qsa(".topic");
let topicResult = qs(".js.topic-result--1");
let topicResult2 = qs(".js.topic-result--2");
// states
let activeResultToggle = false;
let actives = [];
// ----------------------
let onResultClick = () => {
event.stopPropagation();
event.preventDefault();
actives = [];
mapStateToDOM();
};
//topicResult.addEventListener("touchstart", onResultClick);
//topicResult2.addEventListener("touchstart", onResultClick);
topicResult.addEventListener("click", onResultClick);
topicResult2.addEventListener("click", onResultClick);
function onClick(event) {
event.stopPropagation();
event.preventDefault();
let topic = this.closest(".topic");
let anim = document.createElement("div");
anim.className = "btn-clicked";
topic.appendChild(anim);
setTimeout(() => {
try {
// DOM cleanup
anim && topic.removeChild(anim);
} catch (ex) {}
}, 2000);
let type = topic.getAttribute("data-topic");
if (!actives.includes(type)) {
actives.push(type);
if (actives.length > 2) actives.shift();
} else {
actives = actives.filter(t => t !== type);
}
mapStateToDOM();
}
let mapStateToDOM = () => {
if (actives.length === 2) {
activeResultToggle = !activeResultToggle;
if (actives.includes("good") && actives.includes("cheap")) {
if (activeResultToggle) {
topicResult.textContent = "?";
topicResult2.textContent = "";
} else {
topicResult.textContent = "";
topicResult2.textContent = "?";
}
topicResult.style.backgroundColor = "cyan";
topicResult2.style.backgroundColor = "cyan";
} else if (actives.includes("good") && actives.includes("fast")) {
if (activeResultToggle) {
topicResult.textContent = "?";
topicResult2.textContent = "";
} else {
topicResult.textContent = "";
topicResult2.textContent = "?";
}
topicResult.style.backgroundColor = "hotpink";
topicResult2.style.backgroundColor = "hotpink";
} else {
if (activeResultToggle) {
topicResult.textContent = "?";
topicResult2.textContent = "";
} else {
topicResult.textContent = "";
topicResult2.textContent = "?";
}
topicResult.style.backgroundColor = "#fff000";
topicResult2.style.backgroundColor = "#fff000";
}
if (activeResultToggle) {
topicResult.classList.add("is-active");
topicResult2.classList.remove("is-active");
topicResult.style.zIndex = 1;
topicResult2.style.zIndex = 0;
} else {
topicResult.classList.remove("is-active");
topicResult2.classList.add("is-active");
topicResult.style.zIndex = 0;
topicResult2.style.zIndex = 1;
}
} else {
topicResult.classList.remove("is-active");
topicResult2.classList.remove("is-active");
}
topics.forEach(t => t.classList.remove("is-active"));
actives.forEach(active => {
topics.forEach(topic => {
// O(n*n) but we have few items
let topicType = topic.getAttribute("data-topic");
if (topicType === active) {
topic.classList.add("is-active");
}
});
});
};
let buttons = qsa(".js.btn");
buttons.forEach(b => {
// b.addEventListener("touchstart", onClick);
b.addEventListener("click", onClick);
});
function qs(expr, context) {
return (context || document).querySelector(expr);
}
function qsa(expr, context) {
return [].slice.call((context || document).querySelectorAll(expr), 0);
}
등록된 댓글이 없습니다.