"Ken Burns effect" on hover background image? - javascript

I've got a parent div that has 30% width and 100% height with the background image set to cover.
What I want, is when I hover over over this div, I would like to create a "Ken Burns effect" on the background...
Currently this is my CSS code:
.col1 {
margin-left : 20%;
width : 26.66%;
float : left;
height : 100%;
background :
linear-gradient(
rgba(0, 0, 0, 0.3),
rgba(0, 0, 0, 0.3)
),
url(images/rave.jpg);
background-size : cover;
background-position : left;
opacity : 1;
background-color : black;
}
Any ideas or if anyone could point me in the right direction that would be great.

Here is what you're looking for: http://codepen.io/hkfoster/pen/kechC
CSS
/* Better box-sizing */
* { box-sizing: border-box; }
/* 1rem = 10px */
html { font-size: 62.5%; }
/* Default body */
body {
margin: 0;
opacity: 0;
font: 1.6rem/1.875 'Avenir Next', sans-serif;
}
/* Loaded body */
body.loaded {
opacity: 1;
transition: 1s opacity;
}
/* Default banner */
.banner {
position: relative;
width: 100%;
height: 40rem;
padding: 0 5%;
overflow: hidden;
backface-visibility: hidden;
}
/* Default image container */
.banner .background {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: -1;
transform: translate3d(0,0,0) scale(1.25);
background: black url(https://dl.dropboxusercontent.com/u/150679257/hazy.jpg) no-repeat center center;
background-size: cover;
}
/* Loaded image container */
.loaded .banner .background {
transform: scale(1);
transition: 6.5s transform;
}
/* Other stuff */
.banner h1 {
color: #EEE;
margin: 0;
line-height: 40rem;
text-transform: uppercase;
text-shadow: 0 0 .3rem black;
}
main {
width: 90%;
margin: 5rem auto;
}
main p { margin: 0 0 3rem 0; }
JS
// Trigger class name on load
window.onload = function() {
document.body.className += ' loaded'
};

If you want to keep background-size: cover, you won't be able to animate the background image's size. You could switch it to background-size: 100% in some cases to animate it: see this fiddle.
The effect is kind of jittery, though - I'd recommend wrapping .col1 and animating the transform's scale instead, like in this fiddle. You'll have to play around with the background-position property on the hover state to achieve the panning effect, but it looks much smoother this way.

Related

Is it possible to make a hole in an img element using html/javascript/css?

I am developing a website from which the background partly needs to be transparant because a video behind it needs to come through. The background is an image. Also, I need to make sure that the website runs on Opera version 11.
Is there a way to cute a hole in an image element, taking into account that the website needs to run in an Opera 11 browser?
<img src='http://ip/cutaholeinme.png'>
So that in the end, the following image with a hole is displayed; (the white rectangle should be transparent)
A mask can easily do this
img {
-webkit-mask:
linear-gradient(#fff,#fff) top / 100% 50px, /* show 50px from the top */
linear-gradient(#fff,#fff) bottom/ 100% 70px, /* show 70px from the bottom */
linear-gradient(#fff,#fff) left / 20% 100%, /* show 20% from the left */
linear-gradient(#fff,#fff) right / 40% 100%; /* show 40% from the right */
-webkit-mask-repeat:no-repeat;
mask:
linear-gradient(#fff,#fff) top / 100% 50px,
linear-gradient(#fff,#fff) bottom/ 100% 70px,
linear-gradient(#fff,#fff) left / 20px 100%,
linear-gradient(#fff,#fff) right / 40px 100%;
mask-repeat:no-repeat;
}
body {
background:linear-gradient(to right,blue,red);
}
<img src="https://picsum.photos/id/1006/500/400" >
For better support, you can consider an SVG mask: How to apply background to specific elements only?
You can also consider a trick with multiple elements like below:
.box {
width: 500px;
height: 400px;
position: relative;
background-size: 0 0;
}
.box div {
background: inherit;
height: 100%;
}
.box:before,
.box:after,
.box div:before,
.box div:after {
content: "";
position: absolute;
background-image: inherit;
background-size: 500px 400px;
}
.box:before,
.box:after {
left: 0;
right: 0;
}
.box:before {
top: 0;
background-position:top;
height: 20%;
}
.box:after {
bottom: 0;
background-position:bottom;
height: 30%;
}
.box div:before,
.box div:after {
top: 0;
bottom: 0;
}
.box div:before {
left: 0;
background-position:left;
width: 40px;
}
.box div:after {
right: 0;
background-position:right;
width: 80px;
}
body {
background: linear-gradient(to right, blue, red);
}
<div class="box" style="background-image:url(https://picsum.photos/id/1006/500/400)">
<div></div>
</div>

Slideout.js menu isnt smooth

I have been trying to get slideout.js to work properly for my site.
The issue is that when the menu is opened, the text appears before the fully opens and when the menu is closed, the text disappears after the menu is closed.
I have looked at the CSS and made sure that there are backgrounds to the menu and heights are correctly set.
Demo (view as mobile) - http://stefan.admark.co.uk/gates/index.php
JS:
window.onload = function() {
var slideout = new Slideout({
'panel': document.getElementById('main'),
'menu': document.getElementById('menu'),
'side': 'right',
'padding': 256,
'tolerance': 70
});
document.querySelector('.js-slideout-toggle').addEventListener('click', function() {
slideout.toggle();
});
};
CSS:
.slideout-menu {
position: fixed;
top: 80px;
bottom: 0;
width: 256px;
/* min-height: 100vh; */
overflow-y: auto;
-webkit-overflow-scrolling: touch;
z-index: 999;
display: none;
padding-left:20px;
}
.slideout-menu-left {
left: 0;
}
.slideout-menu-right {
right: 0;
}
.slideout-panel {
position: relative;
z-index: 1;
will-change: transform;
background-color: #ffffff; /* A background-color is required */
min-height: 100%;
-webkit-box-shadow: 6px 0px 5px 0px rgba(0,0,0,0.1);
-moz-box-shadow: 6px 0px 5px 0px rgba(0,0,0,0.1);
box-shadow: 6px 0px 5px 0px rgba(0,0,0,0.1);
}
.slideout-open,
.slideout-open body,
.slideout-open .slideout-panel {
overflow: hidden;
}
.slideout-open .slideout-menu {
display: block;
}
#media screen and (min-width: 1000px) {
.slideout-panel {
/* margin-left: 256px; */
}
.slideout-menu {
display: none;
}
}
.panel:before {
content: '';
display: block;
background-color: rgba(0,0,0,0);
transition: background-color 0.5s ease-in-out;
}
.panel-open:before {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
background-color: rgba(0,0,0,.5);
z-index: 99;
}
It looks like your <nav> element on your page doesn't have any transition CSS on it.
For instance, your <main> element has the following transition applied to it:
transition: -webkit-transform 300ms ease 0s; transform: translateX(-256px)
Whatever javascript you have triggering the transition for your <main> element, if applied to <nav> should cause the text and everything inside <nav> to transition properly as well.

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>

Achieve animated seesaw -ish effect with linear-gradient (pure CSS)

I have an element with one diagonal side achieved by adjusting linear-gradient and height - in two different states. Now I try to toggle between these states and have a smooth transition of the red triangle, so that it would look like a seesaw :-) The problem is, that from one state to another it changes the direction and is jumpy, I did not find a way to animate it fluently .. Is there a way to to what I want using pure CSS e.g. using transitions?
let btn = document.getElementsByTagName('button')[0];
let stage = document.getElementById('stage');
btn.addEventListener('click', function() {
stage.classList.toggle('fixie');
});
body,
ul {
padding: 0;
margin: 0;
}
#stage {
width: 100%;
height: 14em;
background: pink;
padding: 0;
border: 1px solid blue;
}
#stage::before {
display: block;
position: relative;
width: 100%;
height: 100%;
/*as high as #stage*/
opacity: 0.4;
content: '';
z-index: 1;
background: linear-gradient(to left bottom, red 50%, pink 50%);
/*transition: height 4s;*/
/*transition: linear-gradient 4s 8s;*/
}
#stage.fixie::before {
height: 30%;
background: linear-gradient(to right bottom, red 50%, pink 50%);
}
<div id="stage"></div>
<button>animate gradient</button>
Here is my FIDDLE
As you can't animate linear-gradient, here is a workaround using transform
In this sample I used skew. As the degree of skew will differ based on the width/height, and as long as its ratio is kept, this will be fully responsive, else you'll need a small script.
(function(){
let btn = document.getElementsByTagName('button')[0];
let stage = document.getElementById('stage');
btn.addEventListener('click', function() {
stage.classList.toggle('fixie');
});
})();
body, ul {
padding: 0;
margin: 0;
}
#stage {
position: relative;
overflow: hidden;
width: 90vw;
height: calc(90vw * 0.2677); /* 0.2677, aspect ratio that match skew degree */
background: pink;
padding: 0;
border: 1px solid blue;
}
.navi {
width: 100%;
min-height: 4em;
height: auto;
background: green;
z-index: 2;
position: relative;
}
#stage::before {
content: '';
position: absolute;
width: 100%;
height: 100%; /*as high as #stage*/
bottom: 100%;
opacity: 0.4;
z-index: 1;
background: red;
transform: skewY(15deg);
transform-origin: left bottom;
transition: transform 2s;
}
#stage.fixie::before {
transform: skewY(-15deg) translateY(100%);
}
.navi ul {
list-style: none;
display: flex;
background: lightblue;
justify-content: flex-end;
}
.navi ul li {
display: flex;
align-items: center;
justify-content: center;
min-width: 4em;
width: auto;
height: 2em;
margin: 1px;
background: yellow;
}
<div id="stage"></div>
<button>
animate
</button>
Side note:
One can use any fixed value instead of vw, as long as the #stage's ratio is kept. If to change ratio, you'll either need a script, since CSS calc can't do math with sqrt and sin/cos etc. to get the angle, or using media query's, and have angle's and ratio's manually set for different screens.

Scale Div to Smartphone Width?

I'm trying to get a before/after slider working correctly on my website. I'm almost there, but the DIV is not properly scaling on mobile browsers. It extends way past the width of my smartphone screen.
Here's a link to the website page I'm working on.
About halfway down you'll see a Polarizer section with the Before / After slider. It looks fine on my Desktop browser, but on mobile it extends past the screen width. My coding skills are pretty weak, so I may be missing something simple here.
Here's where I got the Before / After code from.
I assume I just need to insert a basic property into one of the CSS sections below? I've already added the viewport code into the head:
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">div.beforeandafter{ /* main container */
background: white;
display: block;
height: 630x; /* default height of main container */
overflow: hidden;
position: relative;
width: 944px; /* default width of main container */
}
div.before, div.after{ /* before and after DIVs within main container */
height: 100%;
left: 0;
overflow: hidden;
position: absolute;
top: 0;
transition: width 0.4s ease-in-out; /* CSS transition. Actual duration set inside script (options.revealduration) */
width: 100%;
z-index: 100;
}
div.after{
z-index: 1; /* z-index of after div should be smaller than before's */
}
div.drag{ /* main div used for separating and dragging between before and after slides */
background: white;
cursor: col-resize;
display: block;
height: 100%;
left: 100%;
position: absolute;
top: 0;
transition: left 0.4s ease-in-out; /* transition. 0.4s sets duration of drag fade in time */
width: 2px; /* width of drag bar separator */
z-index: 1001;
}
div.drag div.draghandle{ /* handle bar within drag interface */
background: darkred;
background: -moz-radial-gradient(center, ellipse cover, rgba(169,3,41,1) 0%, rgba(143,2,34,1) 44%, rgba(109,0,25,1) 100%);
background: -ms-radial-gradient(center, ellipse cover, rgba(169,3,41,1) 0%,rgba(143,2,34,1) 44%,rgba(109,0,25,1) 100%);
background: -o-radial-gradient(center, ellipse cover, rgba(169,3,41,1) 0%,rgba(143,2,34,1) 44%,rgba(109,0,25,1) 100%);
background: radial-gradient(ellipse at center, rgba(169,3,41,1) 0%,rgba(143,2,34,1) 44%,rgba(109,0,25,1) 100%);
background: rgb(169,3,41);
background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,rgba(169,3,41,1)), color-stop(44%,rgba(143,2,34,1)), color-stop(100%,rgba(109,0,25,1)));
background: -webkit-radial-gradient(center, ellipse cover, rgba(169,3,41,1) 0%,rgba(143,2,34,1) 44%,rgba(109,0,25,1) 100%);
border-radius: 2px;
box-shadow: 0 0 5px gray;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#a90329', endColorstr='#6d0019',GradientType=1 );
height: 20%; /* height of drag handle */
position: absolute;
text-align: center;
width: 16px; /* width of drag handle */
}
div.before span.caption, div.after span.caption{ /* CSS to syle SPAN caption. Optional */
background: black;
bottom: 10px;
color: white;
display: block;
font: bold 12px Germand;
padding: 5px;
position: absolute;
right: 10px;
width: 90px;
}
div.before span.caption{
left: 10px;
right: auto;
}
div.before span.caption a, div.after span.caption a{
color: lightyellow;
text-decoration: none;
}
Finally, here's the actual DIV:
<div class="beforeandafter" id="baf" style="width:944px; height:630px; ">
You have a defined height and width as inline styles in your HTML
<div class="beforeandafter" id="baf" style="width:944px; height:630px; ">
Change that to
<div class="beforeandafter" id="baf">
Then in your CSS document, remove height: 630px; and width: 944px from div.beforeandafter and add padding-bottom: 66.73728814%

Categories