<div class="search-overlay"></div>
<div class="scroll-cont">
<div class="content">
<div class="search">
<div class="search__bg"></div>
<div class="search__box">
<input type="text" class="search__input" placeholder="Search"/>
<div class="search__line"></div>
<div class="search__close"></div>
</div>
</div>
<p class="desc">This search input should work with any position/layout type, including normal pages with scroll. Just don't override .s--cloned styles for .search and everything will be okay. Requires specific styles for containers (check html+body and .scroll-cont styles) and .search-overlay element to be placed in the root.</p>
</div>
</div>
*, *:before, *:after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
}
.search-overlay {
z-index: -1000;
overflow: hidden;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
&.s--active {
z-index: 9999;
}
}
.scroll-cont {
position: relative;
height: 100%;
overflow-y: auto;
}
.content {
padding: 50px;
}
.desc {
max-width: 900px;
margin: 0 auto;
font-size: 25px;
}
$contSize: 116px;
$boxInitSize: 50px;
$boxActiveW: 510px;
$boxActiveH: 100px;
$borderW: 4px;
$inputH: 50px;
$inputVertPad: ($boxActiveH - $inputH - $borderW) / 2;
$inputLeftPad: 40px;
$inputRightPad: 90px;
$closeSize: 30px;
$closeRight: 44px;
$closeTop: ($boxActiveH - $closeSize - $borderW) / 2;
$maxWidth: 3840px;
$bgScaleRatio: $maxWidth / $contSize * 1.45;
$searchAT: 0.6s;
$moveAT: 0.4s;
$easing: ease;
.search {
position: relative;
margin: 0 auto 50px;
width: $contSize;
height: $contSize;
perspective: 1000px;
&:not(.s--active) {
cursor: pointer;
}
&.s--hidden {
opacity: 0;
}
&.s--cloned {
position: absolute;
left: 50%;
top: 50%;
right: auto;
bottom: auto;
margin-left: $contSize/-2;
margin-top: $contSize/-2;
margin-right: 0;
margin-bottom: 0;
}
&.s--moving {
transition: transform $moveAT cubic-bezier(.56,-0.49,.58,.9);
}
&__bg {
position: absolute;
left: 50%;
top: 50%;
width: 100%;
height: 100%;
border-radius: 50%;
background: #F63;
transition: all $searchAT $easing;
transform: translate3d(-50%,-50%,0);
will-change: transform;
.search.s--active & {
transform: translate3d(-50%,-50%,0) scale($bgScaleRatio);
}
}
&__box {
position: absolute;
left: 50%;
top: 50%;
width: $boxInitSize;
height: $boxInitSize;
border: $borderW solid #fff;
border-radius: $boxInitSize/2;
transform: translate(-50%, -50%);
transition: all $searchAT*0.75 $easing;
.search.s--active & {
width: $boxActiveW;
height: $boxActiveH;
border-radius: $boxActiveH/2;
}
}
&__input {
width: 100%;
height: 100%;
background: transparent;
border: none;
outline: none;
pointer-events: none;
opacity: 0;
color: #fff;
font-size: 40px;
transition: opacity 0s;
&::placeholder {
color: rgba(255,255,255,0.4);
}
.search.s--active & {
padding: $inputVertPad $inputRightPad $inputVertPad $inputLeftPad;
pointer-events: auto;
opacity: 1;
transition: opacity $searchAT*0.3 $searchAT*0.8;
}
}
&__line {
position: absolute;
left: 50%;
top: 50%;
width: 20px;
height: 4px;
border-radius: 2px;
background: #fff;
transform-origin: 0 50%;
transform: translate(14px, 14px) rotate(45deg);
transition: all $searchAT*0.8;
&:before {
content: "";
position: absolute;
left: 0;
bottom: 0;
width: inherit;
height: inherit;
background: inherit;
border-radius: inherit;
transform: rotate(90deg);
opacity: 0;
transition: opacity $searchAT/2;
.search.s--active & {
opacity: 1;
transition: opacity $searchAT/2 $searchAT*0.7;
}
}
.search.s--active & {
width: 36px;
height: 6px;
transform: translate($boxActiveW/2 - 75px, 11px) rotate(-45deg);
}
}
&__close {
position: absolute;
right: 0;
top: 0;
width: $closeSize;
height: $closeSize;
pointer-events: none;
.search.s--active & {
right: $closeRight;
top: $closeTop;
pointer-events: auto;
cursor: pointer;
}
}
}
View Compiled
(function() {
var $searchOverlay = document.querySelector(".search-overlay");
var $search = document.querySelector(".search");
var $clone, offsetX, offsetY;
$search.addEventListener("click", function() {
var $original = this;
$clone = this.cloneNode(true);
$searchOverlay.classList.add("s--active");
$clone.classList.add("s--cloned", "s--hidden");
$searchOverlay.appendChild($clone);
var triggerLayout = $searchOverlay.offsetTop;
var originalRect = $original.getBoundingClientRect();
var cloneRect = $clone.getBoundingClientRect();
offsetX = originalRect.left - cloneRect.left;
offsetY = originalRect.top - cloneRect.top;
$clone.style.transform = "translate("+ offsetX +"px, "+ offsetY +"px)";
$original.classList.add("s--hidden");
$clone.classList.remove("s--hidden");
var triggerLayout = $searchOverlay.offsetTop;
$clone.classList.add("s--moving");
$clone.setAttribute("style", "");
$clone.addEventListener("transitionend", openAfterMove);
});
function openAfterMove() {
$clone.classList.add("s--active");
$clone.querySelector("input").focus();
addCloseHandler($clone);
$clone.removeEventListener("transitionend", openAfterMove);
};
function addCloseHandler($parent) {
var $closeBtn = $parent.querySelector(".search__close");
$closeBtn.addEventListener("click", closeHandler);
};
/* close handler functions */
function closeHandler(e) {
$clone.classList.remove("s--active");
e.stopPropagation();
var $cloneBg = $clone.querySelector(".search__bg");
$cloneBg.addEventListener("transitionend", moveAfterClose);
};
function moveAfterClose(e) {
e.stopPropagation(); // prevents from double transitionend even fire on parent $clone
$clone.classList.add("s--moving");
$clone.style.transform = "translate("+ offsetX +"px, "+ offsetY +"px)";
$clone.addEventListener("transitionend", terminateSearch);
};
function terminateSearch(e) {
$search.classList.remove("s--hidden");
$clone.remove();
$searchOverlay.classList.remove("s--active");
};
}());
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.