728x90
눈알하면 미니언 밖에 생각이 안난다. 그래서 미니언을 예제로 구현해보았다.
에셋은 첨부합니다.
[HTML]
<template>
<div class="body">
<div class="eyes">
<div class="eye">
<div class="ball">
</div>
</div>
<div class="eye">
<div class="ball">
</div>
</div>
</div>
</div>
</template>
[CSS]
<style>
*{
padding: 0;
}
body{
display: flex;
justify-content: center;
align-items: center;
}
.body{
background: #fff url('../assets/minion.png');
background-repeat: no-repeat;
background-size: cover;
width: 348px;
height: 553.7px;
margin-top:90px;
}
.eyes{
display: flex;
justify-content: center;
align-items: center;
margin-top: 105px;
}
.eye{
width: 89.7px;
height: 78px;
border-radius: 50%;
float: left;
margin: 12px;
}
.ball{
background: url('../assets/minion-eye.png');
background-repeat: no-repeat;
background-size: cover;
width: 42.3px;
height: 42.3px;
border-radius: 50%;
margin-top: 105px;
}
</style>
[Javascript - Vanila]
var ball = document.getElementsByClassName('ball');
document.onmousemove = function () {
var x = event.clientX * 100 / window.innerWidth + '%';
var y = event.clientY * 100 / window.innerHeight + '%';
for(var i = 0; i < 2; i++){
ball[i].style.left = x / 2;
ball[i].style.top = y / 2;
ball[i].style.transform = 'translate(' + x + ', ' + y + ')';
}
};
[Working - Mouse Tracking]
Element 좌표를 제대로 구할 수만 있다면 커서위치도 따라가게끔 할수 있지않을까 하여 아래처럼 Input을 넣고 눈알을 굴리게 해보았다.
[HTML]
<template>
<div>
<div class="body">
<div class="eyes">
<div class="eye">
<div class="ball">
</div>
</div>
<div class="eye">
<div class="ball">
</div>
</div>
</div>
</div>
<div class="row">
<span>
<input class="swing" id="search" type="text" placeholder="검색할 내용 입력" maxlength="50"/><label for="search">검색</label>
</span>
</div>
</div>
</template>
[CSS]
<style>
* {
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
overflow-x: hidden;
font-weight: 300;
color: #fff;
background: #efefef;
}
.body {
background: #fff url('../assets/minion.png');
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
-webkit-background-size: contain;
-moz-background-size: contain;
-o-background-size: contain;
width: 348px;
height: 553.7px;
margin-top: 90px;
}
.eyes {
display: flex;
justify-content: center;
align-items: center;
margin-top: 105px;
}
.eye {
width: 89.7px;
height: 78px;
border-radius: 50%;
float: left;
margin: 12px;
}
.ball {
background: url('../assets/minion-eye.png');
background-repeat: no-repeat;
background-size: cover;
width: 42.3px;
height: 42.3px;
border-radius: 50%;
margin-top: 105px;
}
.row {
max-width: 800px;
margin: 0 auto;
padding: 60px 30px;
background: #032429;
position: relative;
z-index: 1;
text-align: center;
}
.row span {
position: relative;
display: inline-block;
margin: 30px 10px;
}
input {
font-size: 100%;
line-height: 1.15;
margin: 0;
}
.swing {
display: inline-block;
width: 555px;
padding: 10px 0 10px 15px;
font-weight: 400;
color: #377D6A;
background: #efefef;
border: 0;
border-radius: 3px;
outline: 0;
text-indent: 60px;
transition: all .3s ease-in-out;
}
.swing::-webkit-input-placeholder {
color: #efefef;
text-indent: 0;
font-weight: 300;
}
.swing + label {
display: inline-block;
position: absolute;
top: 0;
left: 0;
padding: 10px 15px;
text-shadow: 0 1px 0 rgba(19, 74, 70, 0.4);
background: #7AB893;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
transform-origin: 2px 2px;
transform: rotate(0);
animation: swing-back .4s 1 ease-in-out;
}
@keyframes swing {
0% {
transform: rotate(0);
}
20% {
transform: rotate(116deg);
}
40% {
transform: rotate(60deg);
}
60% {
transform: rotate(98deg);
}
80% {
transform: rotate(76deg);
}
100% {
transform: rotate(82deg);
}
}
@keyframes swing-back {
0% {
transform: rotate(82deg);
}
100% {
transform: rotate(0);
}
}
.swing:focus,
.swing:active {
color: #377D6A;
text-indent: 0;
background: #fff;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.swing:focus::-webkit-input-placeholder,
.swing:active::-webkit-input-placeholder {
color: #aaa;
}
.swing:focus + label,
.swing:active + label {
animation: swing 1.4s 1 ease-in-out;
transform: rotate(82deg);
}
</style>
[Javascript]
var ball = document.getElementsByClassName('ball');
var input = document.getElementById('search');
input.onkeydown = function () {
var coords = getCoords(input);
var x = coords.x * 100 / window.innerWidth + '%';
var y = (coords.y * 100 / window.innerHeight) + 20 + '%';
console.log(x, y);
for (var i = 0; i < 2; i++) {
ball[i].style.left = x / 2;
ball[i].style.top = y / 2;
ball[i].style.transform = 'translate(' + x + ', ' + y + ')';
}
};
var properties = [
'direction',
'boxSizing',
'width',
'height',
'overflowX',
'overflowY',
'borderTopWidth',
'borderRightWidth',
'borderBottomWidth',
'borderLeftWidth',
'borderStyle',
'paddingTop',
'paddingRight',
'paddingBottom',
'paddingLeft',
// https://developer.mozilla.org/en-US/docs/Web/CSS/font
'fontStyle',
'fontVariant',
'fontWeight',
'fontStretch',
'fontSize',
'fontSizeAdjust',
'lineHeight',
'fontFamily',
'textAlign',
'textTransform',
'textIndent',
'textDecoration',
'letterSpacing',
'wordSpacing',
'tabSize',
'MozTabSize'
];
var isBrowser = (typeof window !== 'undefined');
var isFirefox = (isBrowser && window.mozInnerScreenX != null);
function getCoords(target) {
var coordinates = getCaretCoordinates(target, target.selectionStart);
var elementCoordinates = getElementCoords(target);
var topPosition = coordinates.top + elementCoordinates.top;
var leftPosition = coordinates.left + elementCoordinates.left;
return {
x: leftPosition,
y: topPosition
}
}
function getCaretCoordinates(element, position, options) {
if (!isBrowser) {
throw new Error('브라우저 지원안함');
}
var debug = options && options.debug || false;
if (debug) {
var el = document.querySelector('#search');
if (el) {
el.parentNode.removeChild(el);
}
}
var div = document.createElement('div');
div.id = 'search';
document.body.appendChild(div);
var style = div.style;
var computed = window.getComputedStyle ? getComputedStyle(element) : element.currentStyle;
style.whiteSpace = 'pre-wrap';
if (element.nodeName !== 'INPUT')
style.wordWrap = 'break-word';
style.position = 'absolute';
if (!debug)
style.visibility = 'hidden';
properties.forEach(function (prop) {
style[prop] = computed[prop];
});
if (isFirefox) {
if (element.scrollHeight > parseInt(computed.height))
style.overflowY = 'scroll';
} else {
style.overflow = 'hidden';
}
div.textContent = element.value.substring(0, position);
if (element.nodeName === 'INPUT')
div.textContent = div.textContent.replace(/\s/g, '\u00a0');
var span = document.createElement('span');
span.textContent = element.value.substring(position) || '.';
div.appendChild(span);
var coordinates = {
top: span.offsetTop + parseInt(computed['borderTopWidth']),
left: span.offsetLeft + parseInt(computed['borderLeftWidth'])
};
if (debug) {
span.style.backgroundColor = '#aaa';
} else {
document.body.removeChild(div);
}
return coordinates;
}
function getElementCoords(elem) {
var box = elem.getBoundingClientRect();
var body = document.body;
var docEl = document.documentElement;
var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
var clientTop = docEl.clientTop || body.clientTop || 0;
var clientLeft = docEl.clientLeft || body.clientLeft || 0;
var top = box.top + scrollTop - clientTop;
var left = box.left + scrollLeft - clientLeft;
return {top: Math.round(top), left: Math.round(left)};
}
[Working - Input Caret Tracking]
Note. 이쁘게 꾸민다면, 지니 요정 사이트 처럼 이미지도 그럴싸 하게 쓰면 좋을것 같긴 하다.
추가로, Javascript로 Caret의 위치를 구하는것 보다는,
MaxLength를 두고, 반응형 프레임워크에서 Jquery로 간단하게 Input Length와 Width값 비율로 X위치를 구하는게 더 좋을수 있다.