Responsive Hover Box over Responsive Image - javascript

I've been using a tutorial for making a hover box go over a set of images.
The article can be found here.
Got it working perfectly, except I want my images and the hover to be responsive to window size (just via width is fine), I've tried looking up how to do this. Seems like it might be a case of using % rather than a fixed value, but not experienced enough to know how to execute the markup. Even if I get the images to re-size the hover box doesn't re-size with them.
Is it possible to add something to the existing CSS to make this happen.
ul.img-list {
list-style-type: none;
margin: 0;
padding: 0;
text-align: center;
}
ul.img-list li {
display: inline-block;
height: 150px;
margin: 0 1em 1em 0;
position: relative;
width: 150px;
}
span.text-content {
background: rgba(0,0,0,0.5);
color: white;
cursor: pointer;
display: table;
height: 150px;
left: 0;
position: absolute;
top: 0;
width: 150px;
opacity: 0;
-webkit-transition: opacity 500ms;
-moz-transition: opacity 500ms;
-o-transition: opacity 500ms;
transition: opacity 500ms;
}
span.text-content span {
display: table-cell;
text-align: center;
vertical-align: middle;
}
ul.img-list li:hover span.text-content {
opacity: 1;
}
<ul class="img-list">
<li>
<a href="#">
<img src="http://placehold.it/150x150">
<span class="text-content"><span>Text</span></span>
</a>
</li>
</ul>

you can use only width to keep image ratio.
you can use display:block for a and img, and use flex to center text.
not too sure about the responsive behavior you look for for, you can use a % width on li or a mix a % width + min-width and max-width.
example with % width set at 50% (and max/min width ) , it can be any other value and units.
ul.img-list {
list-style-type: none;
margin: 0;
padding: 0;
text-align: center;
}
ul.img-list li {
display: inline-block;
vertical-align:top;
margin: 0;
position: relative;
width:50%;
max-width:100vh;
min-width:60vh;
}
ul.img-list li a, ul.img-list li a img {
display:block;
width:100%;
}
span.text-content {
background: rgba(0,0,0,0.5);
color: white;
cursor: pointer;
display:flex;
left: 0;
right:0;
position: absolute;
top: 0;
bottom:0;
opacity: 0;
-webkit-transition: opacity 500ms;
-moz-transition: opacity 500ms;
-o-transition: opacity 500ms;
transition: opacity 500ms;
}
span.text-content span {
margin:auto;
}
ul.img-list li:hover span.text-content {
opacity: 1;
}
* {
margin:0;
padding:0;
}
<ul class="img-list">
<li>
<a href="#">
<img src="http://placehold.it/150x150">
<span class="text-content"><span>Text</span></span>
</a>
</li>
</ul>

You could also do it like this, using pseudo elements to display the overlay content on the image. This method is fully responsive.
.wrapper {
width: 100%;
overflow: auto;
padding: 1%;
box-sizing: border-box;
background: rgba(0, 0, 0, 0.1);
border-radius: 8px;
}
/* Columns floated left */
.col-4 {
width: 33.3%;
float: left;
padding: 1%;
box-sizing: border-box;
height: auto;
overflow: hidden;
}
/* Container to make absolute positioning easier on psuedo element */
.image_container {
position: relative;
overflow: auto;
padding: 0;
margin: 0;
}
.image_container img {
width: 100%;
display: block;
}
/* Structure for ::before element */
#img_1::before,
#img_2::before,
#img_3::before {
background: rgba(0, 0, 0, 0.5);
position: absolute;
left: 0;
right: 0;
height: 100%;
width: 100%;
box-sizing: border-box;
display: block;
opacity: 0;
color: white;
padding: 10px;
transition: 0.5s ease;
}
/* Hover state for container to show ::before on mouseover */
.image_container:hover#img_1::before,
.image_container:hover#img_2::before,
.image_container:hover#img_3::before {
opacity: 1;
cursor: pointer;
}
/* Text for ::before elements */
#img_1::before {
content: 'Image Title 1';
}
#img_2::before {
content: 'Image Title 2';
}
#img_3::before {
content: 'Image Title 3';
}
<div class="wrapper">
<div class="col-4">
<div class="image_container" id="img_1">
<img src="https://images.unsplash.com/reserve/B6PfiQ8QoSzmsZYOCkSB__DSC0530-1.jpg?dpr=1&auto=format&fit=crop&w=1500&h=1004&q=80&cs=tinysrgb&crop=">
</div>
</div>
<div class="col-4">
<div class="image_container" id="img_2">
<img src="https://images.unsplash.com/photo-1418985991508-e47386d96a71?dpr=1&auto=format&fit=crop&w=1500&h=1000&q=80&cs=tinysrgb&crop=">
</div>
</div>
<div class="col-4">
<div class="image_container" id="img_3">
<img src="https://images.unsplash.com/photo-1476362555312-ab9e108a0b7e?dpr=1&auto=format&fit=crop&w=1500&h=1000&q=80&cs=tinysrgb&crop=">
</div>
</div>
</div>
You could also set the images as a background-image for the div which would give you more control over the text in the overlay, if you needed it.

Related

Image slides that fades when navbar is hit

I'm trying to make a replica of the slider on top of this google page: https://www.google.com/doodles
If someone could make a replica of the image slider with the bars, that would be great! I've tried to on my own but can't figure it out. Here's my try if it's helpful!
JAVASCRIPT:
<script>
var imgArray = [
'images/img1.gif',
'images/img2.gif',
'images/img3.jpg',
'images/img4.jpg'],
curIndex = 0;
imgDuration = 3000;
function slideShow() {
document.getElementById('slider').className += "fadeOut";
setTimeout(function () {
document.getElementById('slider').src = imgArray[curIndex];
document.getElementById('slider').className = "";
}, 500);
curIndex++;
if (curIndex == imgArray.length) { curIndex = 0; }
}
</script>
HTML:
<img class="slidershow" id="slider" src="images/img1.gif" onmouseover="slideShow()">
<div id="navigation">
<label for="r1" class="bar" id="bar1"></label>
<label for="r2" class="bar" id="bar2"></label>
<label for="r3" class="bar" id="bar3"></label>
<label for="r4" class="bar" id="bar4"></label>
</div>
</div>
CSS: --> Honestly, I wrote so much CSS that I don't know which ones relate, so I might have left a few out. Need to clean that up - Apologize in advance
.nav_links {
list-style: none;
}
.nav_links li {
display: inline-block;
padding: 0px 20px;
}
.nav_links li a {
color: #009cdc;
transition: all 0.3s ease 0s;
}
.nav_links li:hover a {
color: #2772ff;
}
#top-content {
display: block;
}
latest-nav li#latest-nav-1 {
background-color: #fa4842;
}
#latest-nav li.off {
border-top: 15px solid #fff;
}
#latest-nav li.off {
height: 5px;
opacity: 0.35;
}
#latest-nav li {
cursor: pointer;
float: left;
height: 5px;
transition: opacity 0.15s ease,height 0.15s ease,border-top 0.15s ease;
-moz-transition: opacity 0.15s ease,height 0.15s ease,border-top 0.15s ease;
-webkit-transition: opacity 0.15s ease,height 0.15s ease,border-top 0.15s ease;
width: 16.6%;
}
.slidershow {
height: 400px;
overflow: hidden;
}
.middle {
position: absolute;
top: 50%;
left: 25%;
transform: translate(-50%,-50%);
}
#navigation {
position: absolute;
bottom: 35px;
left: 60%;
transform: translateX(-50%);
display: flex;
}
.bar {
border-top: 15px solid #fff;
width: 200px;
opacity: 0.35;
height: 5px;
cursor: pointer;
transition: 0.4s;
}
.slides {
width: 500%;
height: 100%;
display: flex;
margin-top: 30px;
}
.slide {
width: 20%;
transition: 0.6s;
}
.slide img {
display: block;
margin: auto;
max-height: 250px;
max-width: 600px;
width: auto;
}
latest .container img {
display: block;
margin: auto;
max-height: 250px;
max-width: 600px;
}
#bar1 {
background-color: #3875fc;
}
#bar2 {
background-color: #ff8809;
}
#bar3 {
background-color: #19be29;
}
#bar4 {
background-color: #fa4842;
}
Thanks so much!
I'm always happy to see newcomers devoting time to study. First of all, good job! Unfortunately I'm not a very good teacher, but I put together a little example of this slider you're working on. You can check it clicking here.
Basically what is going on is:
The HTML is divided into two sections: the slider & the navbar.
I hide all slides by default applying a display: none to them. They're only visible when I add an additional class.
Detect the hover method via javascript. Whenever the navbar item is hovered on, you will detect its position (I added a data attribute called data-position to find out which position it is) and show the correspondent slider.
So, if the navbar has the data-position of 2, I know that I must show the second slide. To do that, I use .slider .slider-item:nth-child(2).
As I mentioned I'm not the best at explaining, but I hope this helps you out a little bit. Keep studying and don't give up!
HTML:
<div class="wrapper">
<div class="slider">
<div class="slider-item slider-item--visible">
hello item 1
</div>
<div class="slider-item">
hello item 2
</div>
<div class="slider-item">
hello item 3
</div>
</div>
<nav class="navbar">
<span class="navbar-item navbar-item--selected" data-position="1"></span>
<span class="navbar-item" data-position="2"></span>
<span class="navbar-item" data-position="3"></span>
</nav>
</div>
CSS
.wrapper{
max-width: 1000px;
width: 100%;
margin: 0 auto;
display: block;
}
/* Slider */
.slider{
max-width: 100%;
width: 100%;
}
.slider-item{
display: none;
}
.slider-item--visible{
display: block;
}
/* Navbar */
.navbar{
max-width: 100%;
display: flex;
align-items: flex-end;
height: 8px;
}
.navbar-item{
max-width: 33.3%;
width: 100%;
display: block;
height: 5px;
cursor: pointer;
opacity: .5;
transition: all .32s ease;
}
.navbar-item--selected{
height: 8px;
opacity: 1;
}
/* Meaningless styles (colors) */
.navbar-item:nth-child(1){
background: salmon;
}
.navbar-item:nth-child(2){
background: lightblue;
}
.navbar-item:nth-child(3){
background: #19be29;
}
Javascript
const $navbars = document.querySelectorAll(`.navbar-item`);
function removeSelected(){
const $selected = document.querySelectorAll(`.navbar-item--selected, .slider-item--visible`);
if (!$selected){
return;
}
for (let each of $selected){
each.classList.remove("navbar-item--selected");
each.classList.remove("slider-item--visible");
}
}
for (let each of $navbars){
each.addEventListener("mouseover", function(){
removeSelected();
const position = each.getAttribute("data-position");
const $item = document.querySelector(`.slider .slider-item:nth-child(${position})`)
each.classList.add("navbar-item--selected")
$item.classList.add("slider-item--visible");
});
}

addEventListener adds incorrect properties on click - only on 320x480

TL DR it should be display: flex; opacity: 1
I have a menu which works in the following way:
On mouseenter or click, the menu is shown (display: flex, opacity: 1)
On mouseleave or click (outside the menu area) the menu is hidden (display: none, opacity: 0)
The problem occures when I try to "open" the menu in the Dev. Tools on 320x480 resolution.
When I click on the menu area, only #envelope does the transformation. #links (should also transform but don't becouse of the following reasons) which should get display: flex actually gets display: none assigned to it.
Note: It's working in full screen. Something is bothering him with the 320x480 res.
If I can elaborate or provide any additional information, let me know.
Thank you
function hide (){
document.getElementById("links").style.display = "none";
};
function show (){
document.getElementById("links").style.display = "flex";
document.getElementById("links").style.opacity = "1";
};
var menu = document.getElementById("menu");
menu.addEventListener("mouseenter", show);
menu.addEventListener("mouseleave", hide);
menu.addEventListener("click", show);
document.addEventListener("click", function (){
if (this != menu){
document.getElementById("links").style.display="none";
}
});
#menu{
height: 10vh;
background-color: red;
text-align: center;
transition: all 1s ease-out;
padding-top: 5vh;
}
#menu:hover{
color: red;
}
#envelope{
height: 0;
display: block;
background-color: blue;
min-width: 100%;
z-index: 1;
position: absolute;
left: 0;
content: "";
opacity: 0;
transition: all 1.3s ease-out;
}
#links{
height: 0;
display: none;
background-color: pink;
justify-content: center;
z-index: 2;
min-width: 100%;
opacity: 0;
transition: all 1s ease-in;
}
#google{
margin-top: -1vh;
width: 150px;
}
#mysite{
padding-left: 5%;
margin-top: -1vh;
width: 150px;
}
#menu:hover #envelope{
height: 100px;
opacity: 1;
}
#menu:focus #envelope{
height: 100px;
opacity: 1;
}
#menu:hover #links{
opacity: 1;
height: 300px;
}
#menu:focus #links{
opacity: 1;
height: 300px;
}
<div id="menu">Click here to browse the internet.
<div id="envelope">
<div id="links" >
<div><img id="google" src="https://seomofo.com/wp-content/uploads/2010/05/google_logo_new.png" /></div>
<div style="width: 20%;"></div>
<div><img id="mysite" src="https://toppng.com/uploads/preview/wwf-logo-horizontal-world-wildlife-foundation-logo-shirt-11563219164hg5hfcveei.png"/></div>
</div>
</div>
</div>
Don't use transition: all because the browser then need to loop through all properties, and it might cause lag.
Don't use position: absolute unless you have to.
I removed #envelope and inserted the "Click here ..." text in a label (explanation why below).
I arranged classes so I didn't have to repeat code.
Pure CSS solution below.
I made a little CSS hack, where I used a label and a checkbox to simulate a click. So when clicking on the label#menu-toggler, the (hidden) checkbox is checked, which triggers #menu-toggler:checked ~ #links.invisible. I had to add another class to #links, otherwise the low specificity wouldn't trigger the change.
html, body { /* new */
margin: 0px;
padding: 0px;
}
#menu {
height: 15vh; /* changed */
background-color: red;
text-align: center;
margin: 0.5rem; /* new */
}
#menu > input#menu-toggler { /* new */
display: none;
}
#menu > .tagline { /* new */
display: block; /* to get padding to work */
padding: 5vh 0px;
transition: opacity 1s;
}
#menu:hover > .tagline { /* new */
opacity: 0;
}
#menu > .tagline, /* new */
#menu > #links /* new */
{
transition-timing-function: ease-out;
}
#menu > #links {
display: flex;
justify-content: space-around; /* changed */
position: relative; /* changed */
left: -0.5rem; /* changed */
top: -5vh; /* changed */
opacity: 0;
height: 0;
width: 100vw; /* changed */
z-index: 1;
overflow: hidden; /* new */
background-color: pink;
transition-property: height, opacity;
transition-duration: 1.3s;
}
#menu:hover #links,
#menu-toggler:checked ~ #links.invisible { /* new */
height: 150px !important; /* changed */
opacity: 1 !important;
}
#links #google,
#links #mysite
{
width: 150px;
}
<div id="menu">
<input id="menu-toggler" type="checkbox" />
<label for="menu-toggler" class="tagline">Click here to browse the internet.</label>
<div id="links" class="invisible">
<div><img id="google" src="https://seomofo.com/wp-content/uploads/2010/05/google_logo_new.png" /></div>
<div><img id="mysite" src="https://toppng.com/uploads/preview/wwf-logo-horizontal-world-wildlife-foundation-logo-shirt-11563219164hg5hfcveei.png"/></div>
</div>
</div>

CSS Navbar Transition is Smooth on Scroll Down but no Transition at all on Scroll Back Up

I am currently working on a website with a navigation bar at the top of the screen that is initially transparent when you first visit the site, but turns into a white bar with black text the moment you start scrolling down. It also shrinks a little. It has a really nice and smooth transition as it changes it's color and shrinks, but when you scroll back to the top of the page, there is no more smooth transition but rather an instant ugly transition. Actually the changing of the color back to transparent seems okay but the resize of the bar lacks the transition. I uploaded a GIF so you can see exactly what's the problem.
There is a second problem I would like to ask for. As you can see in the GIF, there is an underline animation on text hover, however, I cannot get it to work on the white navbar. I want that underline to become black, just like the text and shrink with the rest of the navbar.
Here is the GIF:
https://media.giphy.com/media/5jYbvzN9OzaVm3IRE6/giphy.gif
Also the CSS:
/* -=-=-=-=-= FONT IMPLEMENTATION =-=-=-=-=- */
#import url('https://fonts.googleapis.com/css?family=Quicksand:300|Roboto:100');
/* -=-=-=-= END FONT IMPLEMENTATION =-=-=-=- */
html, body {
margin: 0;
padding: 0;
width: 100%;
}
body {
font-family: "Roboto",sans-serif;
font-weight: lighter;
}
header.index {
width: 100%;
height: 100vh;
background: url(../res/images/back.png) no-repeat 50% 50%;
background-size: cover;
}
header.page1 {
width: 100%;
height: 100vh;
background: url(../res/images/test.jpg) no-repeat 50% 50%;
background-size: cover;
}
.content {
width: 94%;
margin: 4em auto;
font-size: 20px;
}
.logoimg {
position: fixed;
display: inline-block;
float: left;
width: 235px;
height:54px;
margin: 37px 80px;
transition: 0.5s ease-in-out;
}
nav {
position: fixed;
width: 100%;
line-height: 60px;
transition: 0.5s ease-in-out;
}
nav ul {
line-height: 100px;
list-style: none;
background: rgba(0, 0, 0, 0);
overflow: hidden;
color: #fff;
padding: 0;
text-align: right;
margin: 0;
padding-right: 50px;
transition: 0.5s ease-in-out;
}
nav ul li {
display: inline-block;
padding: 16px 20px;
transition: 0.5s ease-in-out;
}
nav ul li a {
text-decoration: none;
color: #fff;
font-size: 24px;
transition: 0.5s ease-in-out;
}
nav ul li a.current{
font-weight: 600;
}
nav.scrolled{
background: #fff;
min-height: 20px;
line-height: 40px;
transition: 0.5s ease-in-out;
}
nav.scrolled ul li a{
text-decoration: none;
color: #000;
font-size: 20px;
line-height: 40px;
transition: 0.5s ease-in-out;
}
nav.scrolled img{
width: 180px;
height: 41px;
margin: 27px 80px;
transition: 0.5s ease-in-out;
}
/* -=-=-=-=-= MENU ITEM HOVER ANIMATION =-=-=-=-=- */
.menu a {
transition: color 0.1s, background-color 0.1s;
}
.menu a {
position: relative;
display: block;
transition: color 0.1s,background-color 0.1s,padding 0.2s ease-in;
color: #fff;
}
.menu a::before {
content: '';
display: block;
position: absolute;
bottom: 24px;
left: 0;
height: 2px;
width: 100%;
background-color: #fff;
transform-origin: right top;
transform: scale(0, 1);
transition: color 0.1s,transform 0.2s ease-out;
}
.menu a:active::before {
background-color: #fff;
}
.menu a:hover::before, a:focus::before {
transform-origin: left top;
transform: scale(1, 1);
}
.menu.scrolled {
color: #000;
background-color:
}
/* -=-=-=-=-= END MENU ITEM HOVER ANIMATION =-=-=-=-=- */
And the JS:
$(window).on("scroll", function() {
if($(window).scrollTop()) {
$('nav').addClass('scrolled');
}
else {
$('nav').removeClass('scrolled');
}
})
$(function () {
$(window).scroll(function () {
if ($(this).scrollTop()> 2) {
$('.logo img').attr('src', 'res/logos/main.png');
}
if ($(this).scrollTop() < 2) {
$('.logo img').attr('src', 'res/logos/main_light.png');
}
});
});
And the important HTML:
<header class="index">
<nav class="navbar">
<div class="logo">
<a href="#">
<img class="logoimg" src="res/logos/main_light.png">
</a>
</div>
<div class="menu">
<ul>
<li><a class="current" href="index.html">Home</a></li>
<li>Company</li>
<li>Services</li>
<li>Portfolio</li>
<li>Blog</li>
<li>Contact</li>
</ul>
</div>
</nav>
</header>
Note that .scrolled is the one that changes the navbar once you scrolled. May your road lead you to warm sands!
You're setting the transition for the a elements twice. First as .menu a and then as nav ul li a. The nav bar animates when scrolling up, but the transition lasts 0.1s, as declared for the selector .menu a.
You can either change .menu a to .menu nav ul li a or redesign your classes.
For the underline animation, just add the nav.scrolled selector to the classes you already have, for instance: nav.scrolled .menu a::before and change the background color. You will probably also need to re position the ::before element.

Text fill effect - simulate a block of color passing through text

I'm trying to create a text effect so when you hover over text, a block of color seems to pass through the text.
I followed exactly what the first example here (for the word "Kukuri") does by using a :before pseudo-element to achieve the color fill. I have the code written here in SCSS:
.text {
position: relative;
&:hover {
&:before {
width: 100%;
}
}
&:before {
content: 'HELLO'; // if our text was "HELLO"
width: 0%;
position: absolute;
z-index: 2;
overflow: hidden;
color: red;
transition: width 350ms ease-in-out;
white-space: nowrap;
width: 0%;
}
}
However, I'm wondering if it's possible to animate the :before element's width the other way? So once it hits 100% width and fills with color, then the left side starts emptying and it goes back to 0% fill.
The end goal is to use this for a navigation menu. Something like this effect where it seems like a block of color is moving through menu items when you hover:
For something like this, hovering over "About" item would make the fill color wipe down while
Attempted Solutions
I tried translating the :before element, changing the left and right properties, and changing transform-origin to no avail.
I've tried looking into mix-blend-mode to try and create a rectangular mask that could potentially add color to the text. However, to my understanding, mix-blend-mode only works with text and not with rectangular divs with background-colors.
You may do something like this by simply using a layer that pass above your element with transparent background:
ul {
list-style: none;
padding: 0;
margin: 0;
}
ul li {
display: inline-block;
margin: 10px;
position: relative;
font-size: 30px;
color: red;
font-weight: bold;
overflow: hidden;
}
ul li:before {
content: "";
position: absolute;
height: 100%;
width: 100%;
background: rgba(255, 255, 255, 0.6);
transition: 2s;
z-index: 2;
}
ul.ver li:before {
top: 0;
left: -100%;
}
ul.hor li:before {
top: -100%;
left: 0;
}
ul.ver li:hover::before {
left: 100%;
}
ul.ver.half li:hover::before {
left: 0;
}
ul.hor li:hover::before {
top: 100%;
}
ul.hor.half li:hover::before {
top: 0;
}
<ul class="hor">
<li>Home</li>
<li>About</li>
</ul>
<ul class="hor">
<li>Home</li>
<li>About</li>
</ul>
<ul class="ver half">
<li>Home</li>
<li>About</li>
</ul>
<ul class="hor half">
<li>Home</li>
<li>About</li>
</ul>
And here is another example using mix-blend-mode with text:
ul {
list-style: none;
padding: 0;
margin: 0;
}
ul li {
display: inline-block;
margin: 10px;
position: relative;
font-size: 30px;
background-image: linear-gradient(to right, red, red);
background-size: 200% 200%;
background-repeat: no-repeat;
font-weight: bold;
overflow: hidden;
transition: 1s;
}
ul.hor li {
background-position: 0% 200%;
}
ul.ver li {
background-position: 200% 0%;
}
ul li span {
display: inline-block;
color: black;
background-color: white;
mix-blend-mode: screen;
}
ul.hor li:hover {
background-position: 0% -100%;
}
ul.ver li:hover {
background-position:-100% 0%;
}
ul.hor.half li:hover {
background-position: 0% 0%;
}
ul.ver.half li:hover {
background-position:0% 0%;
}
<ul class="hor">
<li><span>Home</span></li>
<li><span>About</span></li>
</ul>
<ul class="ver">
<li><span>Home</span></li>
<li><span>About</span></li>
</ul>
<ul class="hor half">
<li><span>Home</span></li>
<li><span>About</span></li>
</ul>
<ul class="ver half">
<li><span>Home</span></li>
<li><span>About</span></li>
</ul>
You can use blend modes for this effect, here you have one posibility:
I opted for moving the background of the pseudo rather than moving the pseudo itself, This way you won't have side effects when the pseudo is over other elements.
Also, it isn't clear for me if you want a single slide or a double one. I have set it to be a double one ( from black to red and again to black. You can change this easily adjusting the final background position
.demo {
background-color: yellow;
margin: 10px;
display: inline-block;
font-size: 50px;
padding: 10px;
position: relative;
}
.demo:after {
content: "";
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
background-image: linear-gradient(to right, transparent 25%, red 25%, red 75%, transparent 75% );
mix-blend-mode: lighten;
background-size: 400% 100%;
transition: background-position 2s linear;
background-position: 100% 0%;
}
.demo:hover:after {
background-position: 0% 0%;
}
<div class="demo">TEST1</div>
<div class="demo">TEST2</div>
To change the movement to vertical, you need to change
the gradient direction
which of the image dimensions is oversized
the background position that is changed on hover
.demo {
background-color: yellow;
margin: 10px;
display: inline-block;
font-size: 50px;
padding: 10px;
position: relative;
}
.demo:after {
content: "";
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
background-image: linear-gradient(to top, transparent 25%, red 25%, red 75%, transparent 75% );
mix-blend-mode: lighten;
background-size: 100% 400%; /* changed vertical dimension */
transition: background-position 2s linear;
background-position: 0% 100%; /* changed 100 position to vertical*/
}
.demo:hover:after {
background-position: 0% 0%;
}
<div class="demo">TEST1</div>
<div class="demo">TEST2</div>
.text {
text-transform: uppercase;
font-weight: 900;
overflow: hidden;
line-height: 0.75;
color: #c5c2b8;
position:relative;
}
.text:before {
content: attr(data-letters);
position: absolute;
z-index: 2;
overflow: hidden;
color: red;
white-space: nowrap;
width: 0%;
top:0;
-webkit-transition: width 0.4s 0.3s;
transition: width 0.4s 0.3s;
}
.text:hover:before {
width: 100%;
}
<span class="text" href="#" data-letters="hello">hello</span>

Center element with animation / transition

I'm trying to create a full screen menu that does a bottom-to-top movement and I'm having trouble when it comes to vertically centering it.
Basically, it comes out of the screen and should end up right in the middle of it (centered).
However, since it is a fixed menu with an unknown height and I'm using animations, the options available aren't many:
I can't use the margin: auto technique because the auto value doesn't work with transitions;
I'm trying to avoid using flexbox;
translateY() seems to work fine but it creates a top-to-bottom movement instead of the desired bottom-to-top one (see my code)
anything else? (preferably that works with older browsers, but I can also manage with using translateY if there's a way to change the direction)
$('#small-nav-btn').click(function() {
$('#overlay').addClass('open');
$('#close-menu-cross').addClass('open');
$('#nav').addClass('open');
})
$('#cross').click(function() {
$('#overlay').removeClass('open');
$('#close-menu-cross').removeClass('open');
$('#nav').removeClass('open');
})
* {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: "Now-Regular", sans-serif;
font-size: 12px;
font-weight: bold;
}
ul {
list-style-type: none;
}
a {
color: black;
}
#overlay {
background: #fff;
opacity: 0;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 0;
transition: all 1s ease 0s;
z-index: 1555;
}
#overlay.open {
opacity: 1;
height: 100%;
}
#small-nav-bar {
display: block;
width: 80%;
margin: 0 auto;
text-align: center;
color: black;
}
#small-nav-btn {
cursor: pointer;
}
#nav {
background: orange;
position: fixed;
top: -100%; /*I need it to be bottom: -100% for the bottom-top movement*/
left: 50%;
transform: translate(-50%, -50%);
transition: all 0.8s linear 0.1s;
z-index: 1556;
}
#nav.open {
top: 50%; /*Again, I need this to be bottom: 50%*/
}
#close-menu-cross.open {
display: block;
position: fixed;
top: 15px;
right: 20px;
z-index: 1556;
cursor: pointer;
}
#close-menu-cross {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav id="nav-container">
<div id="small-nav-bar">
<div id="small-nav-btn">BUTTON</div>
</div>
<ul id="nav">
<li><span>HELLO</span>
</li>
<li><span>HELLO</span>
</li>
</ul>
<div id="close-menu-cross">
<div id="cross">X</div>
</div>
</nav>
jsfiddle
Thanks in advance! :)
You were quite close. With just a few adjustments in the CSS, you have a full working demo:
$('#small-nav-btn').click(function() {
$('#overlay').addClass('open');
$('#close-menu-cross').addClass('open');
$('#nav').addClass('open');
})
$('#cross').click(function() {
$('#overlay').removeClass('open');
$('#close-menu-cross').removeClass('open');
$('#nav').removeClass('open');
})
#nav {
background: orange;
position: fixed;
top: 100%; /* 1 */
left: 50%;
transform: translate(-50%, 0); /* 2 */
transition: all 0.8s linear 0.1s;
z-index: 1556;
}
#nav.open {
top: 50%;
transform: translate(-50%, -50%); /* 2 */
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: "Now-Regular", sans-serif;
font-size: 12px;
font-weight: bold;
}
ul {
list-style-type: none;
}
a {
color: black;
}
#overlay {
background: #fff;
opacity: 0;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 0;
transition: all 1s ease 0s;
z-index: 1555;
}
#overlay.open {
opacity: 1;
height: 100%;
}
#small-nav-bar {
display: block;
width: 80%;
margin: 0 auto;
text-align: center;
color: black;
}
#small-nav-btn {
cursor: pointer;
}
#close-menu-cross.open {
display: block;
position: fixed;
top: 15px;
right: 20px;
z-index: 1556;
cursor: pointer;
}
#close-menu-cross {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav id="nav-container">
<div id="small-nav-bar">
<div id="small-nav-btn">BUTTON</div></div>
<ul id="nav">
<li><span>HELLO</span></li>
<li><span>HELLO</span></li>
</ul>
<div id="close-menu-cross">
<div id="cross">X</div>
</div>
</nav>
Notes:
The CSS offset properties (top, bottom, left, right), when applied to absolutely-positioned elements (which includes position: fixed), shift the element x-distance from the respective edge.
You have top: -100% in your code. This puts the element 100% above the top edge.
You then have it shifting to top: 50%. This puts the element halfway inside the container.
Essentially, your animation moves the element a distance of 150%, from above the window to inside it. The movement is top to bottom.
But you want the movement to go from bottom to top.
So start the element all the way at the bottom and off-screen (top: 100%), and have it shift up to halfway inside the container (top: 50%).
The transform: translate() rule simply fine-tunes the centering.
If translateY(-50%) is applied to the primary state (like in your code), it will shift 50% of the nav onto the screen before the transition (demo).
That's why I applied translateY(-50%) only to the transitioned state.
For a complete explanation see my answer here: Element will not stay centered, especially when re-sizing screen
jsFiddle

Categories