Is there a way to make an element dependent on another element? - javascript

I am making a portfolio website and having trouble with something. When I hover over an image of a project, the image grows in size, has reduced opacity and a description of the project appears. However, I want to be able to add a link with the description. The problem is when I hover over the link the image returns to it's default state, meaning the image shrinks back, is opaque and the description fades away along with the link.
I have tried restructuring the javascript and css around but haven't gotten any solutions.
JavaScript:
const projectNode = (project) => {
return (
<div className="Project">
<div>
<div className="previewProject">
<img className="Project-image" src={project.image} alt="project-images" />
<div className="Project-info" >{project.description}<br></br>
<a className="project-link" href={project.github}>GITHUB</a>
</div>
</div>
</div>
</div>
)
}
//CSS//
.previewProject {
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.Project-image {
opacity: 1.0;
filter: alpha(opacity=40);
transition: transform .3s;
border: solid 3.5px #606060;
/* Animation */
margin: 50px auto;
position: relative;
top: 0;
left: 0;
}
.Project-image+.Project-info {
opacity: 0;
transition: opacity 0.3s;
}
.Project-image:hover {
opacity: 0.2;
filter: alpha(opacity=100);
transform: scale(1.25);
}
.Project-image:hover+.Project-info {
opacity: 1;
color: black;
}
.Project-info {
font-family: 'Lato', sans-serif;
font-size: 21px;
width: 25%;
position: absolute;
pointer-events: none;
}
.project-link {
pointer-events: auto;
}

Your animation should relate to hovering on the parent .previewProject, so something like this:
.previewProject:hover .Project-image {
/* Do whatever */
}

Related

Creating Responsive Slide Up Menu

Hoping for a little guidance. I'm making a "slide up" menu for a site i'm using and I have it working, except it's not responsive. Ideally, i'd like to have it so whatever I put in the content under "Book Now" would be hidden no matter the size, while keeping "Book Now" shown.
The way I have it set up now, I have to be very verbose about heights, and it doesn't seem to really want to work on mobile.
Hoping you kind folks could point me in the right direction of what CSS I actually need to make this work!
Here is the JSFiddle:
https://jsfiddle.net/yg13exft/
<style>
/* footer fixed Menu stuff */
.bottomNav{
overflow: hidden;
position: fixed;
bottom: -210px;
width: 100%;
transition: all .7s ease-in-out;
z-index: 9999;
}
.tipBar{
text-align: center;
transition: all .7s ease-in-out;
}
.tipBar a{
color: #6c0505;
background: orange;
display: inline-block;
padding: 5px 15px 5px 15px;
}
.menuBar{
background-color: #6c0505;
display: grid;
grid-template-columns: auto auto;
justify-content: center;
padding-top: 10px;
height: 100%;
}
.bottomNav p{
color: black;
}
.displayNone{
display: none;
}
.tipToggleAnim{
bottom: 46px;
}
.bottomMenuAnim{
bottom: 0;
}
.rightCol img{
max-height: 200px;
}
</style>
<div class="bottomNav" id="bottomNav">
<div class="tipBar" id="tipBar">
<a id="bookNowButton" class="animate__animated animate__backInUp">
Book Now!
</a>
</div>
<div id="dialog" class="menuBar" >
<div class="leftCol">
<p>
TEST TEXT HERE! :)
</p>
</div>
<div class="rightCol">
<img src="https://images.unsplash.com/photo-1589883661923-6476cb0ae9f2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1374&q=80" alt="cat">
</div>
</div>
</div>
<script>
let toggledVar = false;
function popupMenu(){
let menuToggle = document.getElementById("bottomNav");
let divButton = document.getElementById("tipBar");
if (toggledVar == true){
toggledVar = !toggledVar;
menuToggle.classList.remove('bottomMenuAnim');
}
else {
toggledVar = !toggledVar;
menuToggle.classList.add('bottomMenuAnim');
}
}
let buttonTest = document.getElementById("bookNowButton");
buttonTest.addEventListener("click", popupMenu, false);
</script>
Thank you.
I would use clientHeight to get the height of the dialog section and then set that as the bottom attribute so it will always be hidden. That way no matter what the height of the content, it will always know how many pixels to set bottom to and hide the div, but keep the Book Now showing.
There is a window load event because we need the DOM to fully load before we retrieve dialog div height.
Then, we use animate to smooth the change of the bottom attribute. Animate takes two parameters, the keyframes and the options. In the options, fill makes the animation run and stay in its end state. You can adjust the duration to fit your liking.
// We wait for the page to fully load, then we can grab the height of the div
window.addEventListener('load', function() {
// Toggle boolean
let toggledVar = false;
// Set toggle to Book now button
let menuToggle = document.getElementById("bookNowButton");
// Get bottomNav section
let bottomNav = document.getElementById("bottomNav");
// Get the height of the div
let hiddenSection = document.getElementById("dialog").clientHeight;
// Set bottom css attribute
bottomNav.style.bottom = `-${hiddenSection}px`;
function popupMenu(){
if (toggledVar == false) {
// Set bottom css attribute to 0px to reveal it
bottomNav.animate([
// keyframes
{ bottom: `-${hiddenSection}px` },
{ bottom: '0px' }
], {
duration: 1000,
fill: 'forwards'
});
toggledVar = true;
} else {
// Set bottom css attribute to hide it
bottomNav.animate([
// keyframes
{ bottom: '0px' },
{ bottom: `-${hiddenSection}px` }
], {
duration: 1000,
fill: 'forwards'
});
toggledVar = false;
}
}
menuToggle.addEventListener('click', popupMenu);
});
* {
box-sizing: border-box;
}
html, body {
padding: 0;
margin: 0;
width: 100%;
min-height: 100vh;
}
#bottomNav {
max-width: 100%;
position: fixed;
overflow: hidden;
left: 0px;
}
#bookNowButton {
display: block;
margin: 0 auto;
text-align: center;
padding: 1rem;
max-width: 200px;
background-color: yellow;
cursor: pointer;
}
#dialog {
background-color: #6c0505;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 1rem;
padding: 1rem;
}
.rightCol img {
max-width: 100%;
}
<div id="bottomNav">
<span id="bookNowButton">Book Now!</span>
<div id="dialog">
<div class="leftCol">
<p>
TEST TEXT HERE! :)
</p>
</div>
<div class="rightCol">
<img src="https://images.unsplash.com/photo-1589883661923-6476cb0ae9f2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1374&q=80" alt="cat">
</div>
</div>
</div>

onClick animations works Only once in React.js

I want to make a game in React.js simlar to this:
https://www.youtube.com/watch?v=LfgyRk2QpJw
This is what I have so far:
https://door-game.netlify.com/
Here is the key code:
class App extends Component {
getComponent(event) {
event.currentTarget.style.animation = 'App-logo-spin 2s linear';
}
render() {
return (
<div className="App">
<header className="App-header">
<div className="App-logo" alt="logo" onClick=
{this.getComponent.bind(this)}>
<div className="little-circle one"></div>
<div className="little-circle two"></div>
<div className="little-circle three"></div>
<div className="little-circle four"></div>
</div>
For now onClick works only once, how can I make it work unlimited times?
I think Neil has provided a good solution if you want to make the rotation animation work unlimited time, here I will provide a different solution you might find it useful, and more closed to the effect in the youtube video.
Instead of using animation, I will use rotateZ() from transform which can achieve the same effect, and also you can setup the rotation degree per click.
The flow is:
Storing the current rotate degree in the state.
Use click handler to update the state.
Update the circle style based on the state in render().
Here is the codepen: https://codepen.io/anon/pen/pWxjEE
Hope this helps :)
The problem that you've got here is that basically the css animation relies on seeing "Hey there's been an animation flag added to an element" to know to do the animation. As Neil, suggested removing it and re-adding it seems like it will do the job BUT when you set it to " " and add it again one line after the other, the process that watches for animation flags just doesn't notice that it was gone. So it continues to think that it has been there the whole time.
The situation is pretty well described at CSS Tricks -Restarting an Animation
The punch line of the article is that your unclick function should look like
getComponent(event) {
event.currentTarget.style = ' ';
void event.currentTarget.offsetWidth;
event.currentTarget.style.animation = 'App-logo-spin 2s linear';
}
I've tested this code best as I can from the static js and got it working, so I'm hopeful it works when it's in the App.js file.
var appLogos = document.getElementsByClassName('App-logo');
var currentElement;
for (var i = 0, len = appLogos.length; i < len; i++) {
appLogos[i].addEventListener('click', animate, false);
}
function animate(e) {
currentElement = e.currentTarget;
currentElement.style.animation = 'unset';
setTimeout(function() {run(currentElement)}, 100);
}
function run(el) {
el.style.animation = 'App-logo-spin 2s linear';
}
body {
margin: 0;
padding: 0;
font-family: sans-serif
}
.App {
text-align: center
}
.App-logo {
height: 80px;
width: 80px;
background: #fff;
border-radius: 50%;
z-index: 2;
display: -ms-flexbox;
display: flex;
-ms-flex-align: stretch;
align-items: stretch;
-ms-flex-pack: justify;
justify-content: space-between;
position: relative;
cursor: pointer
}
.App-logo-animation: {
-webkit-animation: App-logo-spin 2s linear;
animation: App-logo-spin 2s linear
}
.App-header {
background-color: #222;
height: 200px;
padding: 20px;
color: #fff;
display: -ms-flexbox;
display: flex;
-ms-flex-pack: center;
justify-content: center;
-ms-flex-align: center;
align-items: center;
position: relative
}
.big-logo {
height: 120px;
width: 120px;
background: red;
z-index: 1
}
.big-logo,
.biggest-logo {
position: absolute;
border-radius: 50%
}
.biggest-logo {
height: 150px;
width: 150px;
background: blue;
z-index: 0
}
.little-circle {
width: 10px;
height: 10px;
background-color: green;
border-radius: 50%
}
.App-title {
font-size: 1.5em
}
.App-intro {
font-size: large
}
.four,
.one,
.three,
.two {
position: absolute
}
.one {
top: 15px;
left: 15px
}
.two {
top: 15px;
right: 15px
}
.three {
bottom: 15px;
right: 15px
}
.four {
bottom: 15px;
left: 15px
}
.un {
top: 20px;
left: 20px
}
.dos {
top: 20px;
right: 20px
}
.tres {
bottom: 20px;
right: 20px
}
.quatro {
bottom: 20px;
left: 20px
}
.ein {
top: 22px;
left: 22px
}
.zwei {
top: 22px;
right: 22px
}
.drei {
bottom: 22px;
right: 22px
}
.fier {
bottom: 22px;
left: 22px
}
.submit {
width: 60px;
height: 60px;
position: absolute;
bottom: 140px;
background-color: #8a2be2;
cursor: pointer;
border-radius: 50%
}
#-webkit-keyframes App-logo-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg)
}
to {
-webkit-transform: rotate(1turn);
transform: rotate(1turn)
}
}
#keyframes App-logo-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg)
}
to {
-webkit-transform: rotate(1turn);
transform: rotate(1turn)
}
}
/*# sourceMappingURL=main.ea098249.css.map*/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<title>React App</title>
</head>
<body><noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root">
<div class="App">
<header class="App-header">
<div class="App-logo" alt="logo">
<div class="little-circle one"></div>
<div class="little-circle two"></div>
<div class="little-circle three"></div>
<div class="little-circle four"></div>
</div>
<div class="App-logo big-logo" alt="logo">
<div class="little-circle one un"></div>
<div class="little-circle two dos"></div>
<div class="little-circle three tres"></div>
<div class="little-circle four quatro"></div>
</div>
<div class="App-logo biggest-logo" alt="logo">
<div class="little-circle one ein"></div>
<div class="little-circle two zwei"></div>
<div class="little-circle three drei"></div>
<div class="little-circle four fier"></div>
</div>
</header>
</div>
</div>
</body>
</html>
The onClick() function is fired multiple times.
(Here 6 says the number of times I clicked the li element and the onClick function was fired.)
But you are setting the css animation for your division without resetting it.
Reset the the animation on every click before setting it. It should work.
Initial suggestion that only worked from the console:
getComponent(event) {
event.currentTarget.style.animation = 'unset';
event.currentTarget.style.animation = 'App-logo-spin 2s linear';
}
This did not work because, the two statements were executed so fast that it does't actually take effect.
That's why a timeout is required as shown in the working code above.

Is there a way to trigger a JavaScript onclick event on an element that has pointer-events set to none?

I have an element that has pointer events set to none, this is so hover styles for child elements don't show.
However when this element is clicked on I want to do something with JavaScript. Using an onclick event in JavaScript does not seem to work because pointer-events is set to none.
Is there a way around this so that I can have an element with no pointer events that can still trigger a JavaScript event?
[data-drawer="open"] {
.site-drawer {
transform: translateX(0);
transition: all .2s ease;
}
.site-container {
transform: translateX(-27.5rem);
// Disabling pointer events disables styles hover styles on below elements
// But also disables clicking on container to remove it.
pointer-events: none;
transition: all .2s ease;
&:after {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(0,0,0,.75);
content: "";
}
}
}
JavaScript:
this.siteContainer.addEventListener('click', (e) => {
console.log('site container clicked');
if(document.body.hasAttribute('data-drawer')) {
document.body.removeAttribute('data-drawer');
}
});
Cheers
You can use this work around. Set pointer-events: none to the element that has the hover effects, And add a wrapper div to the elements that still needs to be triggered on click.
$(".cant-click-this").on("click", function(ev) {
console.log("You cant trigger the element, and it has no hover effects.");
});
$(".click-me-instead").on("click", function(ev) {
console.log("You can trigger click through the wrapper.");
});
.cant-click-this {
pointer-events: none;
}
.cant-click-this:hover {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="click-me-instead">
<button class="cant-click-this"> Try to click me</button> <br>Hovering is futile.
</div>
As I mentioned in the comments, you can achieve this by adding a non-clickable overlay on top of your content using pseudo-elements and z-index
Essentially you have four layers.
the content of the website (white)
the overlay that covers the content of the website while the modal
is open (grey)
the modal (red)
the layer that covers the modal contents. (transparent)
Result: user can't click inside the modal but can click outside anywhere on layer #2
Rough example:
.modal {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
opacity: 0;
pointer-events: none;
background: rgba(0, 0, 0, .5)
}
.close {
top: 0;
right: 0;
bottom: 0;
left: 0;
opacity: 0;
display: none;
z-index: 1;
position: fixed;
cursor: default;
}
.modal-content:after {
content: "";
left: 0;
position: absolute;
top: 0;
width: 100%;
height: 100%;
z-index: 2;
}
.modal:target {
opacity: 1;
pointer-events: auto;
}
.modal:target>.close {
display: block;
}
.modal>div {
width: 300px;
text-align: center;
padding: 40px;
z-index: 2;
position: relative;
background: red;
}
.wrap,
.modal {
display: flex;
align-items: center;
justify-content: center
}
<div class="wrap">
<button>You can click me!</button>
<div id="M" class="modal">
<div class="modal-content">
<button>But not me!</button>
</div>
</div>
</div>

Ghosting effect like in bitly.com copy links

Wondering what library can make this kind of text ghosting animation?
Thanks
The "Fade Out Top" effect from http://cssanimation.io/ seems pretty similar. You can "absolute" position two layers of your text on top of each other and then run the animation only on one of them to create the "ghost" effect. Here's the original CodePen by cssanimation.io: http://codepen.io/cssanimation/pen/YpPXjR
And here's a fork with the two layers I was suggesting: http://codepen.io/anon/pen/YVNNGw/
<div class="container">
<h1 class="layer1">cssanimation</h1>
<h1 class="layer2 cssanimation fadeOutTop">cssanimation</h1>
</div>
and the CSS:
body {overflow: hidden;}
.container { font-family: 'Ubuntu', sans-serif; position: relative; height: 300px; } /* center text styling */
h1, .link { font-size: 4.5em; letter-spacing: -4px; font-weight: 700; color: #7e2ea0; text-align: center; } /* h1 styling */
#media screen and (max-width: 488px) { h1 { font-size: 2.6em; letter-spacing: -2px; } } /* control h1 font size below 768px screen */
/* animation duration and fill mode */
.cssanimation {
animation-duration: 1s;
animation-fill-mode: both;
display: inline-block;
}
/* fadeOutTop animation declaration & iteration counting */
.fadeOutTop { animation-name: fadeOutTop }
/* fadeOutTop animation keyframes */
#keyframes fadeOutTop {
from { opacity: 1 }
to {
opacity: 0;
transform: translateY(-100%);
}
}
.layer1 {
position: absolute;
z-index: 1;
left: 0;
top: 0;
}
.layer2 {
position: absolute;
z-index: 2;
left: 0;
top: 0;
}
Did you try opening up the web inspector and seeing for yourself how bitly.com does it? Often the best way to learn is by imitating the work of others.
As you can see it is quite simple. When the user clicks the button, an element is created - the sole purpose of which is to provide the "ghosting" animation that you describe. Then it disappears when the animation is complete.

Understanding a template to modify it

I don't seem to understand the Russian Doll philosophy of html and thus, I fail to correctly apply css to the desired container.
Here are two templates I'd like to use simultaneously :
http://tympanus.net/Tutorials/AnimatedBorderMenus/index5.html
http://tympanus.net/Development/SectionSeparators/
And my problem is that the result is this :
First everything seems all right :
Then I click on the hamburger to open the menu :
The problem is that the portion of code which does the border the overlay applies on <nav> and it doesn't seem to affect the <section> but it does affecter the <header> and <footer> (you can't see the later on the screenshots).
Here is the portion of code :
.bt-menu.bt-menu-open {
height: 100%;
border-width: 30px 30px 30px 90px;
background-color: rgba(0,0,0,0.3);
transition: border-width 0.3s, background-color 0.3s;
}
I reached this conclusion by doing this :
And also adding the above css to my sections inline. It did what I would expect by opening the menu.
So, why doesn't it affect my section?
Here is my html if it can prove useful : http://pastebin.com/g7Exx64f
Weave: http://kodeweave.sourceforge.net/editor/#89d761c4072d7ae653f1a8205392074a
I skimmed through the CSS from the pen you linked some have a z-index which means it's stacked above your element.
Plus your container is probably not set to position: fixed; so your content will scroll with you.
In addition you can toggle the display of the social network icons in pure css. You will need an input[type=checkbox] with a unique id. Say #callmenu. Then you need a label[for=callmenu]. For is used trigger the checkbox when clicked.
Say you want to toggle the display of .social. To do this with the checkbox you set what you want the css of .social to be before it's checked.
.social {
visibility: hidden;
}
Then you set what you want it to look like when the checkbox is checked...
#callmenu:checked ~ .social {
visibility: hidden;
}
The snippet below is a simple example of what I believe you'd like to achieve.
You can view this weave which utilizes the pen you linked and font-awesome.
/* Border Menu */
#callmenu {
visibility: hidden;
position: fixed;
top: 0;
left: 0;
}
label[for=callmenu] {
cursor: pointer;
position: fixed;
top: 0;
left: 0;
z-index: 2;
font-size: 2.6752em;
margin: 0.2em 0.7488em;
color: #666;
}
.bgoverlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #000;
opacity: .3;
z-index: 1;
}
.icon-menu {
position: fixed;
top: 0;
left: 0;
bottom: 0;
background: #3a3a3a;
z-index: 1;
}
.icon-menu ul {
list-style: none;
padding: 2.576em 0;
text-align: center;
}
.icon-menu li {
font-size: 0;
padding: 0;
margin: 0;
}
.icon-menu li a {
color: #999;
padding: 1.12em;
transition: all ease-in 150ms;
}
.icon-menu li a:hover {
color: #cecece;
}
/* When menu is checked */
#callmenu:checked ~ .icon-menu li {
font-size: 1.76em;
margin: 0.768em 0;
}
#callmenu:checked ~ label[for=callmenu] {
color: #d5ebe4;
}
<input type="checkbox" id="callmenu">
<div class="bgoverlay"></div>
<div class="icon-menu">
<ul>
<li>
<a href="javascript:void(0)">
Twitter
</a>
</li>
<li>
<a href="javascript:void(0)">
G+
</a>
</li>
<li>
<a href="javascript:void(0)">
Facebook
</a>
</li>
</ul>
</div>
<label for="callmenu">
menu
</label>

Categories

Resources