I want to display a border around an element, when it is hovered. Like this image:
The issue is that I don't want add to add border or outline on the element itself because I'm allowing user to change styles and it'll affect the added outline as well.
Here is what I've tried to counter this:
Created overlay div on top of the content using position: absolute
Added a div inside it to which is also set to absolute
Added onmouseover and onmouseout listener on overlay div to get the width, height, offsetLeft and offsetTop of the element
Now the issue is that because the overlay is on top, the events are not firing on elements underneath (as I want the nested element's info as well). I've also tried setting z-index but it doesn't seem to be working as well.
So, how to achieve this?
PS: The screenshot is taken from the visual builder of Webflow but I'm not sure how they are achieving this.
Here is the code:
var outlineContainer = document.querySelector('#content-container');
outlineContainer.onmouseover = outlineContainer.onmouseout = handler;
function handler(event) {
var hoverOutline = document.querySelector('.hover-outline');
if (event.type == 'mouseover') {
console.log(event.target.tagName);
var clientRects = event.target.getBoundingClientRect();
hoverOutline.style.width = `${clientRects.width}px`;
hoverOutline.style.height = `${clientRects.height}px`;
hoverOutline.style.transform = `translate(${event.target.offsetLeft}px,${event.target.offsetTop}px)`;
}
if (event.type == 'mouseout') {
hoverOutline.style.width = 0;
hoverOutline.style.height = 0;
hoverOutline.style.left = 0;
hoverOutline.style.top = 0;
}
}
#content-container {
border: 2px solid black;
background-color: white;
padding: 50px;
position: relative;
height: 100%;
}
.overlay {
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
z-index: 2;
}
.hover-outline {
position: absolute;
border: 2px solid orange;
z-index: 6;
top: 0px;
left: 0px;
z-index: 3;
}
.content {
z-index: 4;
}
<div id="content-container">
<div class="overlay">
<div class="hover-outline"></div>
</div>
<div class="content">
<div class="component">
<label>Hi</label>
</div>
<div class="component">
<label>Text Field</label>
<span class="wrapper">
<input type="text" placeholder="Text Input Field" />
</span>
</div>
</div>
</div>
I may have misunderstood what is required, but could you just change the border color on hover? (And remove the JS).
#content-container {
border: 2px solid black;
background-color: white;
padding: 50px;
position: relative;
height: 100%;
}
#content-container:hover {
border: 2px solid red;
}
.overlay {
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
z-index: 2;
}
.hover-outline {
position: absolute;
border: 2px solid orange;
z-index: 6;
top: 0px;
left: 0px;
z-index: 3;
}
.content {
z-index: 4;
}
<div id="content-container">
<div class="overlay">
<div class="hover-outline"></div>
</div>
<div class="content">
<div class="component">
<label>Hi</label>
</div>
<div class="component">
<label>Text Field</label>
<span class="wrapper">
<input type="text" placeholder="Text Input Field" />
</span>
</div>
</div>
</div>
Related
I'd like my parent div to expand the height of the content, as my content will be dynamic. However, the content must be (I think) positioned absolutely so they can overlap each other vertically.
I've concluded I'll have to use JS to find the offset from the top to the bottom of the last element in the container, then set the height to that.
I'm currently doing something like this:
var lastElement = document.getElementById('three');
var bounds = lastElement.getBoundingClientRect();
var bottomOffset = bounds.top + $("#three").height();
$("#container").height(bottomOffset);
However this is clunky within my application, and the application of the height is not instantaneous, leading to a sluggy site.
Is there a better way?
var lastElement = document.getElementById('three');
var bounds = lastElement.getBoundingClientRect();
var bottomOffset = bounds.top + $("#three").height();
$("#container").height(bottomOffset);
body,
html {
height: 100% padding: 0;
margin: 0;
}
.absolute {
display: inline-block;
position: absolute;
background-color: blue;
width: 100px;
height: 100px;
}
#two {
top: 80px;
left: 120px
}
#three {
top: 160px;
left: 240px;
}
#container {
position: relative;
width: 100%;
;
background-color: yellow;
;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div class="absolute" id="one"></div>
<div class="absolute" id="two"></div>
<div class="absolute" id="three"></div>
</div>
View on JSFiddle
You can accomplish your result without any JS, but instead use CSS margin around the boxes to get the same result.
For the horizontal margin you can also use percentages (by request of OP).
For the vertical margins this will give unexpected results, since the percentage will still reference the width of the container (under "Property Values"), not the height.
html,body {height:100%; padding:0; margin:0;}
.container {
background-color: yellow;
}
.box {
display: inline-block;
width: 100px;
height: 100px;
margin-right: 2%;
background-color: blue;
}
.box.one {margin-top:0; margin-bottom:160px;}
.box.two {margin-top:80px; margin-bottom:80px;}
.box.three {margin-top:160px; margin-bottom:0;}
<div class="container">
<div class="box one"></div>
<div class="box two"></div>
<div class="box three"></div>
</div>
pixel-margin: https://jsfiddle.net/xzq64tsh/
percent-margin: https://jsfiddle.net/xzq64tsh/3/
Perhaps taking out the getBoundingClientRect() function, using jQuery instead might speed it up and simplify it a bit.
var lastElement = $('#three');
var bottomOffset = lastElement.offset().top + lastElement.height();
$("#container").height(bottomOffset);
body,
html {
height: 100% padding: 0;
margin: 0;
}
.absolute {
display: inline-block;
position: absolute;
background-color: blue;
width: 100px;
height: 100px;
}
#two {
top: 80px;
left: 120px
}
#three {
top: 160px;
left: 240px;
}
#container {
position: relative;
width: 100%;
;
background-color: yellow;
;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div class="absolute" id="one"></div>
<div class="absolute" id="two"></div>
<div class="absolute" id="three"></div>
</div>
I saw this cool scrolling effect online...
Where the image blends with the next image when scrolling through sections. I've been trying to reproduce it, but I can't seem to figure it out?
How can I create this effect on the web?
Here is the link to where I saw the effect... http://readingbuddysoftware.com/how-it-works/
I've tried using position: fixed on the screenshots with the z-index of the section higher then the image, but the last screenshot is always on the top.
Any ideas?
Update: For various reasons (including placement, using slants...), I can't use the background-image css solution. I need a solution for using the <img> element.
This can be done using background-attchement:fixed and two similar images.
Here is a simple example:
body {
min-height:200vh;
margin:0;
background:url(https://picsum.photos/id/1069/150/150?grayscale) 20px 20px no-repeat;
background-attachment:fixed;
}
.box {
margin-top:220px;
height:200px;
background:url(https://picsum.photos/id/1069/150/150) 20px 20px no-repeat,
grey;
background-attachment:fixed;
}
<div class="box">
</div>
That you can easily scale with many images:
body {
min-height:250vh;
margin:0;
background:url(https://picsum.photos/id/1069/150/150?grayscale) 50px 50px/auto no-repeat;
background-attachment:fixed;
}
.box {
height:200px;
background:url(https://picsum.photos/id/1069/150/150) 50px 50px/auto no-repeat,
grey;
background-attachment:fixed;
}
.box:first-child {
margin-top:200px;
}
<div class="box">
</div>
<div class="box" style="background-image:url(https://picsum.photos/id/11/150/150);background-color:yellow">
</div>
<div class="box" style="background-image:url(https://picsum.photos/id/106/150/150);background-color:pink">
</div>
You can also consider the use of img and position:fixed but you will need some trick to hide the overflow using clip-path
body {
min-height: 250vh;
margin: 0;
padding-top: 100px;
}
img {
position: fixed;
top: 50px;
left: 50px;
}
.box {
height: 200px;
background: grey;
clip-path: inset(0);
}
<div class="box">
<img src="https://picsum.photos/id/1074/200/120?grayscale">
</div>
<div class="box" style="background-color:red;">
<img src="https://picsum.photos/id/1074/200/120">
</div>
<div class="box" style="background-color:yellow;">
<img src="https://picsum.photos/id/1024/200/120?grayscale">
</div>
<div class="box" style="background-color:pink;">
<img src="https://picsum.photos/id/1024/200/120">
</div>
Or using mask
body {
min-height: 250vh;
margin: 0;
padding-top: 100px;
}
img {
position: fixed;
top: 50px;
left: 50px;
}
.box {
height: 200px;
background: grey;
-webkit-mask:linear-gradient(#fff,#fff);
mask:linear-gradient(#fff,#fff);
}
<div class="box">
<img src="https://picsum.photos/id/1074/200/120?grayscale">
</div>
<div class="box" style="background-color:red;">
<img src="https://picsum.photos/id/1074/200/120">
</div>
<div class="box" style="background-color:yellow;">
<img src="https://picsum.photos/id/1024/200/120?grayscale">
</div>
<div class="box" style="background-color:pink;">
<img src="https://picsum.photos/id/1024/200/120">
</div>
For better support, here is a similar idea with some JS to avoid the use of clip-path or mask
I will update the position of the image using a CSS variables but you can easily do without:
window.onscroll = function() {
var scroll = window.scrollY || window.scrollTop || document.getElementsByTagName("html")[0].scrollTop;
document.documentElement.style.setProperty('--scroll-var', scroll+"px");
}
:root {
--scroll-var: 0px;
}
body {
min-height: 150vh;
margin: 0;
}
img {
position: fixed;
top: 20px;
left: 20px;
}
.box {
margin-top: 220px;
height: 200px;
background: grey;
position: relative;
overflow: hidden;
}
.box img {
top: calc(-220px + 20px + var(--scroll-var));
/* margin of box + top of the other image + scroll*/
position: absolute;
}
<img src="https://picsum.photos/id/1069/150/150?grayscale">
<div class="box">
<img src="https://picsum.photos/id/1069/150/150">
</div>
With many images:
window.onscroll = function() {
var scroll = window.scrollY || window.scrollTop || document.getElementsByTagName("html")[0].scrollTop;
document.documentElement.style.setProperty('--scroll-var', scroll+"px");
}
:root {
--scroll-var: 0px;
}
body {
min-height: 250vh;
margin: 0;
padding-top:200px;
}
img {
position: fixed;
top: 50px;
left: 50px;
}
.box {
height: 200px;
background: grey;
position: relative;
overflow: hidden;
}
img.f1 {
top: calc(-200px + 50px + var(--scroll-var));
position: absolute;
}
img.f2 {
top: calc(-400px + 50px + var(--scroll-var));
position: absolute;
}
img.f3 {
top: calc(-600px + 50px + var(--scroll-var));
position: absolute;
}
<img src="https://picsum.photos/id/1069/100/100?grayscale">
<div class="box">
<img class="f1" src="https://picsum.photos/id/1069/100/100">
</div>
<div class="box" style="background-color:yellow;">
<img class="f2" src="https://picsum.photos/id/107/100/100">
</div>
<div class="box" style="background-color:pink;">
<img class="f3" src="https://picsum.photos/id/1072/100/100">
</div>
I have problem with canvas tag. I need to append it into parent div. But when I set precise dimensions of parent and embed canvas tag, I get scrollbars. When I do same think with div, it works good. Here is fiddle:
https://jsfiddle.net/57yovrkx/4/
and here is code:
$(function() {
var content1 = $('#content1');
var div = $('<div/>', {width: content1[0].clientWidth, height: content1[0].clientHeight});
content1.append(div);
var content2 = $('#content2');
var canvas = $('<canvas/>', {width: content2[0].clientWidth, height: content2[0].clientHeight});
content2.append(canvas);
})
* {
box-sizing: border-box;
border: 0;
margin: 0;
padding: 0;
}
#wrap1, #wrap2 {
display: flex;
flex-direction: column;
position: absolute;
left: 0;
right: 0;
overflow: auto;
}
#wrap1 {
top: 0;
bottom: 50%;
}
#wrap2 {
top: 50%;
bottom: 0;
}
.header {
flex: 0 0 2rem;
background: darkgrey;
}
#content1, #content2 {
flex: 1;
}
#content1 {
background: lightblue;
}
#content2 {
background: lightgreen;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrap1">
<div class="header">
Some header
</div>
<div id="content1">
</div>
</div>
<div id="wrap2">
<div class="header">
Some header
</div>
<div id="content2">
</div>
</div>
Does anybody knows why?
Setting canvas.style.height = '100%'; before you append the canvas seems to do the trick.
https://stackoverflow.com/a/10215724/1482623
So I have two divs which are overlapping, set by my CSS as shown below.
HTML:
<body onLoad="present();">
<div class="pre-wrap">
<img src="images/logo.png" id="logo" alt="Pre Logo" style="display: table; margin: 0 auto;" />
</div>
<div class="wrap">
<p>Test</p>
</div>
</body>
CSS:
.pre-wrap {
height: 700px;
width: 900px;
opacity: 1.0;
bottom: 0;
left: 0;
margin: auto;
position: absolute;
top: 0;
right: 0;
background-color: red;
visibility: visible;
}
.wrap {
height: 700px;
width: 900px;
opacity: 1.0;
bottom: 0;
left: 0;
margin: auto;
position: absolute;
top: 0;
right: 0;
background-color: black;
visibility: hidden;
}
I would like, when the body has loaded, a function to load which does the following: Fades in the image found in the div .pre-wrap, after displaying it for a few seconds, it will fade the image out and the div .pre-wrap will have it's visibility set to hidden. The second div .wrap will then fade in all of its contents.
I tried some simple JS but didn't achieve what I was after.
This question I would say is unique because it has overlapping divs which need visibilities being changed. Please note the overlapping already works, it's just the javascript fading that needs doing.
I tried the following JS which is very simple and works on other projects I've done however it doesn't on this one.
function present() {
$("#logo").fadeIn(3000);
}
Here is my code. I removed the property visibility in the css. And set the display of #logo to none. The attribute onload in the body is no longer needed.
var fadeTime = 3000; // Time for fading
var waitingTime = 5000; // Time how long image is visible
$(window).ready(function(){
$("#logo").fadeIn(fadeTime);
setTimeout(function(){
$(".pre-wrap").fadeOut(fadeTime);
$(".wrap").delay(fadeTime).fadeIn(fadeTime);
},fadeTime+waitingTime);
});
.pre-wrap, .wrap{
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
height: 700px;
width: 900px;
opacity: 1.0;
margin: auto;
}
.pre-wrap {
background-color: red;
}
.wrap {
background-color: black;
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="pre-wrap">
<img src="images/logo.png" id="logo" alt="Pre Logo" style="display: none; margin: 0 auto;" />
</div>
<div class="wrap">
<p>Test</p>
</div>
I am attempting to get elements to transition onscreen. For example purposes I have set them to transition on page load.
The elements that are not floated work perfectly fine. However, the elements that have been floated right (They have the class exleft because they should be expanding leftward) do not transition.
Can someone explain why this is happening?
JsFiddle here
HTML:
<div id="templatebox">
<div class="ribbon exright" id="r1">
</div>
<div class="ribbon exleft" id="r2">
</div>
<div class="ribbon exright" id="r3">
</div>
<div class="ribbon exleft" id="r4">
</div>
</div>
CSS:
#templatebox{
width: 100%;
height: 800px;
padding-top: 50px;
}
.ribbon{
height: 50px;
position: relative;
transition: all 1s ease;
width: 300px;
margin-bottom: 20px;
z-index: 1000;
}
.exleft{
right: -1200px;
left: 0px;
margin-right: -100px;
float: right;
}
.exright{
left: -1200px;
right: 0px;
margin-left: -100px;
}
#r1{
background-color: red;
}
#r2{
background-color: green;
}
#r3{
background-color: blue;
top: 170px;
}
#r4{
background-color: yellow;
top: 170px;
}
JS:
var ribbons = document.getElementsByClassName("ribbon");
for(var i=0, j=ribbons.length; i<j; i++){
ribbons[i].style.right = "0px";
ribbons[i].style.left = "0px";
}
The floated ribbon has both a left and right attribute value set. If both attributes are set to a pixel value, only the left value will be used.
By setting
left: auto;
You can manipulate the right value and it will work as expected.
Here is an updated JSFiddle: https://jsfiddle.net/ym5p7y6v/