Ways to halt a CSS animation when it reaches the screen boundary

I put together this demo:

By clicking, a red box falls down.

The issue arises when trying to determine the screen size using only CSS. In my demo, I set the box to fall for 1000px regardless of the actual screen height.

Here is the keyframe code snippet:

@include keyframes("fall"){
   to{
      top: 1000px;
   }
 }

Unfortunately, using bottom: 0px; isn't viable as it doesn't solve the main problem of determining where the fall should start from.

This is the JavaScript script called FallBox.js:

function FallBox(x, side, parent){
  this.x = x;
  this.parent = parent || $("body");
  this.side = side || Math.random()*200;
  this.createBox();
  this.fall();
}

FallBox.prototype.createBox = function(){
  box = document.createElement('div');
  $box = $(box); // I dislike brackets
  $box.addClass("box");
  $box.css({
      width: this.side+"px",
      height: this.side+"px",
      left: this.x+"px",
      top: "-"+(this.side+5)+"px"
  });
  this.box = $box;
}

FallBox.prototype.fall = function(){
  this.parent.append(this.box);
  this.box.addClass("fall");
}

Using overflow: hidden; in the parent div could be a solution, but it's not ideal. It may restrict users with larger screens and I want the box to stop when reaching the edge, similar to hitting the ground and not passing through.

An alternative solution involving the CSSOM API was found online, however, even Mozilla developers are unsure about its compatibility.

So, how can I halt the animation upon hitting the screen edge when properties cannot be injected via JavaScript?

Thank you.

Answer №1

If you are in search of a pure CSS solution, consider utilizing the 'calc' feature within CSS along with the 'vh' unit.

document.querySelector(".box").addEventListener("click", function() {
  this.classList.toggle("is-dropped");
})
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
.box {
  position: absolute;
  top: 0;
  left: 200px;
  width: 100px;
  height: 100px;
  background: red;
  transition: top 2s;
}
.box.is-dropped {
  top: calc(100vh - 100px);
}
<div class="box"></div>

Answer №2

You can utilize the translatey() CSS transform function to move each div upward by 100% of its own height. This approach allows for only 2 rules to adjust the value of the top position without needing to consider the height in each instance.

(function(d,M){
    var  div=d.createElement("div"),
         wait=0,size;
    d.body.addEventListener("click",function(){
      if(!wait){
        wait=1;
        div=div.cloneNode(1);
        div.classList.remove("go");// necessary so that newly created divs don't just get added to the bottom of the page
        size=M.max(M.floor(M.random()*200),50);
        div.style.height=div.style.width=size+"px";
        div.style.left=M.max(M.floor(M.random()*this.offsetWidth)-size,0)+"px";
        this.appendChild(div);
        setTimeout(function(){
          div.classList.add("go");// adding this class starts the animation.
          wait=0;
        },5);
       }
    },0);
})(document,Math);
*{box-sizing:border-box;margin:0;padding:0;}
html,body{height:100%}
div{
  background:#000;
  border:1px solid #fff;
  transition:top 2s linear;
  position:absolute;
  top:0;
  transform:translatey(-100%);
}
div.go{
  top:100%;
}


INNOVATIVE SOLUTION

Since the height of the box is dynamically set in your JavaScript, your CSS does not have prior knowledge of each box's height. However, you can still use the CSS calc() function to define the desired top position to animate each box to, similar to how you specify the starting top position. Below is a basic example with an alternative solution provided in the comments, which avoids using calc(), if preferred.

var  div=document.createElement("div"),
     wait=0,size;
document.body.addEventListener("click",function(){
  if(!wait){
    wait=1;
    div=div.cloneNode(0);
    size=Math.max(Math.floor(Math.random()*200),50);
    div.style.height=div.style.width=size+"px";
    div.style.left=Math.max(Math.floor(Math.random()*this.offsetWidth)-size,0)+"px";
    div.style.top="-"+size+"px";
    this.appendChild(div);
    setTimeout(function(){
      div.style.top="calc(100% - "+size+"px)"; /* Important calculation */
//    div.style.top=document.body.offsetHeight-size+"px"; /* Alternate solution without calc() */
      wait=0;
    },5);
   }
},0);
*{box-sizing:border-box;margin:0;padding:0;}
html,body{height:100%}
div{
  background:#000;
  border:1px solid #fff;
  transition:top 2s linear; /* Transition instead of animation for smoother effect */
  position:absolute;
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What steps can I take to ensure my CSS selector for the element is functioning properly?

Here is an example of some code: <html> <head> <style> .test{ background-color: red; p { background-color: yellow; } } </style> </head> <body> <div class="test"> ...

Interested in integrating Mockjax with QUnit for testing?

I recently came across this example in the Mockjax documentation: $.mockjax({ url: "/rest", data: function ( json ) { assert.deepEqual( JSON.parse(json), expected ); // QUnit example. return true; } }); However, I'm a bit confused abou ...

How can refs be applied effectively in React applications?

I've been thinking about the role of refs in React and how they can address certain challenges for developers. However, I have found that the explanations provided in the React documentation are not very clear, and there seems to be a lack of helpful ...

JavaScript Alert: The Ajax XMLHttpRequest Response has Returned Null

Below is the code snippet: <script type="text/javascript"> var xmlhttp; $(document).ready(function (){ xmlhttp=new XMLHttpRequest(); ...

Detecting Scroll on Window for Specific Element using Jquery

I need help troubleshooting my code. I am trying to activate only one item that comes from the bottom of the page, but instead all div elements are getting activated. $(window).scroll(function() { $('.parallax').each(function(e) { if($( ...

Rxjs: Making recursive HTTP requests with a condition-based approach

To obtain a list of records, I use the following command to retrieve a set number of records. For example, in the code snippet below, it fetches 100 records by passing the pageIndex value and increasing it with each request to get the next 100 records: thi ...

Mastering the art of square bracket destructuring in React through deep comprehension of the concept

import React, { useEffect, useState } from 'react' import { Text } from 'react-native' export default function Counter() { const [count, setCount] = useState(0) useEffect(() => { const id = setInterval(() => setCount((co ...

How to Align Items Horizontally in React Material UI Grid for Containers of Varying Item Counts

I've been utilizing the React Material UI Grid System to arrange my elements on the page, which utilizes flexboxes internally. While everything is functioning properly, I'm struggling with horizontally aligning items in containers that have vary ...

Incorporate an icon into a text input field using Material UI and React

I have a form with a text input element: <FormControl className='searchOrder'> <input className='form-control' type='text' placeholder='Search order' aria-label='Search&ap ...

Click to start viewing the video

I'm attempting to have a video play when clicked, either on the video itself or around the video. There are multiple videos on the page and I've tried various solutions including the script below which didn't work. $('video'). ...

Infinite scroll functionality does not function properly with jQuery

I recently completed a custom WordPress theme and implemented the following script to create an accordion-like effect: ( function( $ ) { var $ele = $('.entry-content').hide(); $(".entry-header").click(function(e) { e.preventDef ...

Executing Sequential Jquery Functions in ASP.Net

I have successfully implemented two JQuery functions for Gridview in ASP.Net 1. Enhancing Gridview Header and Enabling Auto Scrollbars <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script& ...

The parent font size is influenced by the font size of the child element

I am encountering an issue with my code that seems to be quite simple. Here is the code snippet: <p> <h3>Title is here</h3> This is the paragraph </p> Here is the CSS: h2 {font-size:2.3em;} h3 {font-size:1em;} p {font-size:0. ...

Troubleshooting issues with parsing JSON responses in AngularJS

Being new to using AngularJS, I am encountering an issue with parsing a JSON response. I have user login credentials such as Username and password, and I am attempting to parse them when the user clicks on the login button(). If the username and password m ...

Submitting form by clicking a link on the page

To submit a POST request with "amount=1" without displaying it in the URL, I need the site to send this request when any link on the site is clicked. This JavaScript code achieves that with a GET request: window.onload = function () { document.body.oncli ...

Are you unsure whether to use Ajax or jQuery? If you need assistance in adding parameters to

Currently delving into ajax/jQuery and encountering some hiccups. Here's the code snippet: .click(function() { var period = 'ALL'; if ($('#registerat input:checked').val() != 'ALL') period = ...

CSS creates captivating image hover transitions with span elements

<a href=""><img src=""><span>content</span></a> When I hover over the image, the content within the span appears using relative positioning with display set to none and absolute positioning in the span tag. My query is regard ...

Receiving Null Value Upon Asynchronous API Call Before Data Retrieval

Struggling with Fetching and Displaying API Data in a Table I am facing a challenge where I need to fetch an API multiple times and populate the data into a table. The issue arises when the data for a specific year is not available, causing the table to b ...

Using jquery's next() function to bypass a label

I am facing an issue with a function that populates a second field based on the values in the first field. The problem arises when there is a label associated with the field, as the label becomes the next() element. As a result: function buildoptions( ...

The sinuous waveform in JavaScript

track : function(x, y, top, ampl) { return { top : top + 2, x : x + ampl * Math.sin(top / 20), y : (top / this.screenHeight < 0.65) ? y + 2 : 1 + y + ampl * Math.cos(top / 25) }; } This specif ...