How to add in- and -out transition effect to multiple modals at once using CSS and JS? - javascript

First post, so hopefully it is clear enough.
I have been tasked to create a modal object that overlays a multi-column/-row grid layout on a page. The modal should appear on hover of a particular grid item. When the modal appears, the background of the grid area only should dim. I was asked not to use any additionally libraries (e.g., jQuery).
To complete this task, I added two modal objects, one for the actual modal window and the other for the dimmer object. I could not get the CSS hover to work for both objects on the hover of the item in question, so I used JavaScript to add the CSS changes.
The transition effect works for the transition in but not the transition out. I assume I am overthinking this task so appreciate any suggestions.
<style type="text/css">
.container {
width: 100vw;
height: 100vh;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 1fr);
grid-gap: 10px;
margin: 0;
padding: 0;
}
.column {
background-color: hsl(0,80%,70%);
}
#modal_maker {
font-size: 5vw;
height: 100%;
width:100%;
display:flex;
align-items: center;
justify-content: center;
}
#modal_maker, #modal {
z-index: 2;
}
#modal {
visibility: hidden;
background-color: hsl(200,50%,70%);
width: 80%;
height: 80%;
position: absolute;
margin: auto;
top: 0; left: 0; bottom: 0; right: 0;
opacity: 0;
transition: opacity 1s;
}
#background-dimmer {
visibility: hidden;
background-color: black;
width: 100%;
height: 100%;
position: absolute;
z-index: 1;
opacity: 0;
transition: opacity 0.5s;
}
</style>
<body>
<div class="container">
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
<div class="column" id="modal_maker">Hover Here</div>
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
<div id="modal"></div>
<div id="background-dimmer"></div>
</div>
<script type="text/javascript">
document.querySelector(".container").addEventListener("mouseover", function(el) {
if (el.target.id=="modal_maker" || el.target.id=="modal") {
document.getElementById("modal").style.cssText = "visibility:visible; opacity: 1;"
document.getElementById("background-dimmer").style.cssText = "visibility:visible; opacity: 0.75;"
} else {
document.querySelectorAll("#modal, #background-dimmer").forEach(x => x.style.cssText="opacity: 0; visibility:hidden;")
}
})
</script>
</body>

Its all because of visibility:hidden
in js
...
} else {
document.querySelectorAll("#modal, #background-dimmer").forEach(x => x.style.cssText="opacity: 0; visibility:hidden;")
}
...
in instant way you change opacity to 0 but also visibility:hidden so there is no time for transition, right away when code fires element is hiding.
You use cssText to change properties of element so visibility:visible won't be there when you move mouse on the other element, instead there will be visibility:hidden from the css(so you need to delete that also).
I know that it casues #modal to capture mouseover event then... thats the problem to figure out
I don't know if this solution is on purpose to hide modal when you mouseover other element only, what if I will leave mouse entirely from the table, the modal will stay... just wanted to mention maybe its not relevent.
I made fiddle based on your code: https://jsfiddle.net/svh6dpfk/1/
One idea to fix this #modal capturing event is adding proper visibility as a callback(there is transitionend event which will capture moment when animation is done, so something like this would help:
document.querySelector("#modal, #background-dimmer").addEventListener("transitionend", function(el) {
if(parseFloat(el.target.style.opacity) > 0){
el.target.style.cssText = "visibility:visible;opacity:1";
alert("animation end visible");
}else{
el.target.style.cssText = "visibility:hidden;opacity:0";
alert("animation end unvisible");
}
});
Update
it does work right now for me...
its a bit tricky, your css needs to have visibility:hidden for modal and background-dimmer(like your code has)
this seems to work for me:
document.querySelector(".container").addEventListener("mouseover", function(el) {
if (el.target.id=="modal_maker" || el.target.id=="modal") {
document.getElementById("modal").style.cssText = "visibility:visible;opacity: 1;"
document.getElementById("background-dimmer").style.cssText = "visibility:visible;opacity: 0.75;"
} else {
if(document.getElementById("modal").style.opacity == "1"){
document.querySelectorAll("#modal, #background-dimmer").forEach(x => x.style.cssText="visibility:visible;opacity: 0; ")
}
/* alert("should be on leave") */;
}
})
this part .forEach(x => x.style.cssText="visibility:visible;opacity: 0; ") changes because your css has always visibility:hidden, so you need to perform transition always on visible.
full example:
https://jsfiddle.net/Loary65w/1/
you need to remember to have cross browser support you need to cover all those events
webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend
Hope it helps. Maybe there is better solution much simpler and I overcomplicated that one :F

Related

Animate elements in and out of page

I have several images that I need to horizontally cross the page to the right, exit the page and then re-enter the page from the left. Some of the images will already be out of view, so they will have to enter first.
This is a sketch of what I've tried so far:
var elems = document.getElementsByClassName("child");
for (const elem of elems) {
elem.animate(
[
// keyframes
{transform: "translateX(300px)"},
],
{
// timing options
duration: 5000,
iterations: Infinity
},
);
}
.container {
background-color: aqua;
width: 1000px;
display: flex;
flex-direction: row;
overflow:hidden;
padding: 20px 0;
gap: 10px;
}
.child {
background-color: red;
flex: 0 0 20%;
}
<div class="container">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
<div class="child">7</div>
<div class="child">8</div>
</div>
For start I tried to slide out all the divs, but even that I don't understand why is not working.
I'm using your code as a starting point however there are 2 major differences between my code and yours. The first is that this solution is not using JavaScript, which is a plus, but it may not be what you are looking for. The second difference is that rather of animating the div elements with the class child, this solution is animating a wrapper div with the class slider.
One important thing to note, is that some calculations must be used for the animation to work properly. Adding or removing elements will require that the values are updated. The formula is the following:
Child div size: 20% (CHILD_SIZE)
Gap between children divs: 10px (GAP)
Amount of the children: 8 (CHILDREN_AMOUNT)
So together it goes like this: translateX(calc((CHILD_SIZE - GAP) * CHILDREN_AMOUNT));
var slider = document.getElementsByClassName('slider')[0];
slider.innerHTML += slider.innerHTML;
.container {
background-color: aqua;
width: 100%;
overflow: hidden;
}
.slider {
display: flex;
flex-direction: row;
padding: 20px 0;
gap: 10px;
animation: slideRight 10s infinite linear;
}
.child {
background-color: red;
flex: 0 0 20%;
}
#keyframes slideRight {
from {
transform: translateX(calc((-20% - 10px) * 8));
}
to {
transform: translateX(100% + 10px);
}
}
<div class="container">
<div class="slider">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
<div class="child">6</div>
<div class="child">7</div>
<div class="child">8</div>
</div>
</div>
Updated considering the comment:
There are a few ways, the simpler way though is just to duplicate the div.child elements without touching the animation formula. This can be done just in the markup or using JavaScript to have a more dynamic solution (I have updated the code above to have the desired result).
What I consider a better way, though (not going to elaborate here as many libraries already solve this problem, just search for carousel js libraries), is to just prepend and append the necessary amount of elements to have the desired result instead of duplicating all of them.

How to select (text) inspect element chrome [duplicate]

I'm having a little trouble with CSS and can't seem to find a solution. I have this HTML
<div id="closelink">
Close
Click to close
</div>
Now I want to hide the text «Click to close» only, without hiding neither the div, nor the link within it.
Can this be done?
The visibility attribute can be overriden on children elements, so you are able to do this:
#closelink {
visibility: collapse;
}
#closelink a {
visibility: visible;
}
<div id="closelink">
Close Click to close
</div>
.closelink {
font-size: 0px;
}
.close-link a {
font-size: 12px;
}
Try
#closelink {
position: relative;
left: -9999px;
}
#closelink a {
position: relative;
left: 9999px;
}
<div id="closelink">
Close Click to close
</div>
It works but you can use visibility:hidden instead of visibility:collapse
To avoid the child element breaking to a new line (as happens with just using visibility: hidden/collapse and visibility: visible), and to avoid drawing a 9999px block in the browser (generally frowned upon as it is unnecessary overhead), try this:
#closelink {
position: relative;
visibility: hidden;
}
#closelink a {
position: absolute;
left: 0;
top: 0;
visibility: visible;
}
<div id="closelink">
Close Click to close
</div>
You can adjust your left: 0 value to provide some padding.
There are three methods I could think of:
One
#parent {
opacity: 1;
}
.child {
opacity: 0;
}
<div id="parent">
dkjfdkf
<span class="child">Annoying text</span>
</div>
Two
.child {
visibility: hidden;
}
<div id="parent">
dkjfdkf
<span class="child">Annoying text</span>
</div>
Three
.child {
display: none;
}
<div id="parent">
dkjfdkf
<span class="child">Annoying text</span>
</div>
Opacity is best if you want the image to always be on the page to keep the structure but, you don't want it to be visible.
Hope this was helpful.

How to automatically push scroll-bar when new item was added

Please check out this fiddle. If you add items to the #scroll div, the scroll-bar is fixed - it just stays at the "beginning". What I want to achieve is to move scroll-bar automatically when a new item is being appended to the parent. Is it possible to do this via magic of CSS? :)) Or only JS gonna solve it?
Code:
HTML
<div id="scroll">
<div class="addElement">FIRST</div>
<div class="addElement"></div>
<div class="addElement">LAST</div>
</div>
<button id="add">ADD NEW ELEMENT</button>
CSS
#scroll {
overflow: auto;
overflow-y: hidden;
width: 200px;
height: 150px;
background: red;
position: relative;
display: flex;
align-items: center;
}
.addElement {
margin: 5px;
height: 60px;
width: 55px;
background: green;
flex: 0 0 auto;
}
JS
var scroll = $('#scroll');
var addButton = $('#add');
var item = 1;
addButton.click(function() {
scroll.append(`<div class="addElement">ITEM ${item}</div>`);
item++;
});
Thank you for any suggestion!
I've updated your fiddle to demonstrate a jQuery method of doing this:
https://jsfiddle.net/93gz3u1L/11/
I just added the following using scrollLeft (You can remove the animation if needed):
addButton.click(function() {
scroll.append(`<div class="addElement">ITEM ${item}</div>`);
item++;
scroll.animate({
scrollLeft: scroll.get()[0].scrollWidth
});
});
You can use the css Direction property, setted to rtf! (right to left)
#scroll {
...
direction: rtl;
}
but you will need to prepend the elem instead of append it to the parent.
https://jsfiddle.net/k6Lhv3u6/1/

jQuery full screen section slide left, slide right

I am playing with jquery recently and right now - trying to get animations to work.
Whole idea is basically a fullscreen slider. We have few sections with position absolute and height 100% of the document - in jquery we're playing with z-index. It's quite simply, but I can't figure out how to make a proper slide left and right animations. It's always breaking.
$(document).ready(function() {
var windowWidth = $(window).width();
var slideCount = $('.slide').length;
$('button#next').on('click', function() {
var slideActive = $('.slide.active');
var nextSlide = slideActive.next('.slide');
nextSlide.addClass('active').animate({
'z-index' : '2',
'left' : windowWidth
},500);
slideActive.removeClass('active');
});
});;
body, html {
height: 100%;
position: relative;
}
body {
font-size: 14px;
color: #fff;
}
nav {
position: absolute;
top: 2rem;
right: 2rem;
z-index: 99;
}
section {
height: 100%;
display: flex;
align-items: center;
position: absolute;
right: 0;
left: 0;
}
section#home {
background-color: #2c3e50;
}
section#aboutMe {
background-color: #e74c3c;
}
section#smthElse {
background-color: #1abc9c;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<nav>
<button id="prev">Back</button>
<button id="next">Next</button>
</nav>
<section id="home" class="slide active">
<div class="container">
<p>1</p>
</div>
</section>
<section id="aboutMe" class="slide">
<div class="container">
<p>2</p>
</div>
</section>
<section id="smthElse" class="slide">
<div class="container">
<p>3</p>
</div>
</section>
Before that I tried just by adding class with css defined in .css and animating it (jquery ui) but effect was more or less the same.
All I want to achive is a simple slide functions of my sections.
Example behaviour: http://codepen.io/jibbon/pen/BoisC
Also, I am not looking for ready solutions as I need as simple code as possible to learn and develop it in my way.
Thank you guys!
There are many things that you can improve in your code to achieve what you want.
First, active class is set to a slide but isn't applied any special CSS rule, as you set position: absolute to your divs, you must set z-index to overlap one above other, initializing your app.
Here there is a idea, how to implement what you want:
https://jsfiddle.net/nz2hL6vn/1/

Issue with tabbing between form fields when using jQuery custom scrollbars

I'm working on project to provide a bolt-on tool for websites, which makes heavy use of jQuery. Presentation / design is crucial, and I want to replace the standard (ugly) scrollbar applied by the browser to html elements with overflowing content, with something better looking.
There are numerous jQuery plug-ins around that apply custom scrollbars and allow styling via CSS which is great, but all the ones I've tried seem to suffer from the same problem which is this: if the scrollable content contains a form with text fields etc, tabbing between fields does not activate the scrollbar, and in some cases can screw up the custom scrollbar layout altogether.
Two examples of plug-ins I've tried:
http://manos.malihu.gr/jquery-custom-content-scroller
http://baijs.nl/tinyscrollbar/
I've tried others also, but in all demos / examples the content is plain text. I've done a lot of searching on this already, but it seems no-one has tried using these plug-ins with form-based content.
All these plug-ins seem to work in more or less the same way, and I can see exactly what happens and why, but just wondered if anyone else has had this problem and / or found a solution?
This issue can be easily replicated as follows (using the tinyscrollbar plug-in):
Add this to a standard html test page -
CSS:
<style>
#tinyscrollbartest { width: 520px; height: 250px; padding-right: 20px; background-color: #eee; }
#tinyscrollbartest .viewport { width: 500px; height: 200px; overflow: hidden; position: relative; }
#tinyscrollbartest .overview { list-style: none; position: absolute; left: 0; top: 0; }
#tinyscrollbartest .scrollbar { position: relative; float: right; width: 15px; }
#tinyscrollbartest .track { background: #d8eefd; height: 100%; width: 13px; position: relative; padding: 0 1px; }
#tinyscrollbartest .thumb { height: 20px; width: 13px; cursor: pointer; overflow: hidden; position: absolute; top: 0; }
#tinyscrollbartest .thumb .end { overflow: hidden; height: 5px; width: 13px; }
#tinyscrollbartest .thumb, #tinyscrollbartest .thumb .end { background-color: #003d5d; }
#tinyscrollbartest .disable { display: none; }
</style>
Html:
<div id="tinyscrollbartest">
<div class="scrollbar">
<div class="track">
<div class="thumb">
<div class="end"></div>
</div>
</div>
</div>
<div class="viewport">
<div class="overview">
</p>Here's a text field: <input type="text"/><p>
...
// lots of content to force scrollbar to appear,
// and to push the next field out of sight ..
...
<p>Here's another field: <input type="text"/></p>
</div>
</div>
</div>
Plug-in reference (assuming jquery libraries etc are referenced also):
<script type="text/javascript" src="scripts/jquery.tinyscrollbar.min.js"></script>
Jquery code:
<script type="text/javascript">
$(document).ready(function () {
$('#tinyscrollbartest').tinyscrollbar();
});
</script>
Now click in the first text field so it has focus, hit the tab key to move to the next one and see what happens.
I understand your problem.. But is hard to find a good solution to this. You could try to set a focus event on your form elements. And let this event trigger the scrollbar_update function of tinyscrollbar. You can set the offsetTop of the form element that currently has focus as the methods parameter. I think that would work.
$('formelements').focus(function(){
YourScrollbar.tinyscrollbar_update(this.offsetTop);
});
I had to overwrite the standard tabbing functionality with my own:
$(".scrollable").each(function() {
if (!$(this).data("scrollbar"))
{
$(this).data("scrollbar", new Scrollbar({
holder:$(this)
}));
$(this).find("input").bind("keydown", function(e)
{
var keyCode = e.keyCode || e.which;
if (keyCode == 9)
{
e.preventDefault();
var scrollTo = $(this);
if (e.shiftKey)
{
var nextInput = $(this).prevAll("input:not([type=hidden])").first();
scrollTo = nextInput.prevAll("input:not([type=hidden]), label").first();
}
else
{
var nextInput = $(this).nextAll("input:not([type=hidden])").first();
}
if (nextInput.length)
{
console.log(scrollTo);
$(this).closest(".scrollable").data("scrollbar").scrollTo(scrollTo, function()
{
nextInput.focus().select();
});
}
}
});
}
});
It's a bit annoying to have to wait for the scroll but I don't see any other option.

Categories

Resources