How to check if container div hides something? - javascript

Imagine, that we have a container div with overflow:hidden style.
How can we check, if it actually hides something now?

.height() will do if you check for child elements height:
if($('#container').height() < $('#container > div').height()){
$('pre').html($('#container').height()+"<----container|children--->" +$('#container > div').height());
}
#container{height:50px; background:red; overflow:hidden;}
#container div{height:200px; width:100px; background:black;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='container'>
<div></div>
</div>
<pre></pre>
scrollHeight can be used to have a check for scrollHeight due to text's overflow.
As in the comments this does just checks the height which won't be available when height is not set on the child element, as suggested in the comments that you should check for the scrollHeight which can return you the inner content is overflowed or not.
So in my opinion this should be the correct way:
if($('#container').height() < $('#container')[0].scrollHeight){
$('pre').html($('#container').height()+"<----.height()|.scrollHeight--->" +$('#container')[0].scrollHeight);
}
#container{height:50px; background:red; overflow:hidden;}
#container div{height:200px; width:100px; background:black;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='container'>
<p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p><p>dummy text</p>
</div>
<pre></pre>

You can compare the clientHeight of the element to its scrollHeight:
var container = $('.container')[0];
var hasOverflowed = container.scrollWidth > container.clientWidth || container.scrollHeight > container.clientHeight;
Example fiddle
You can also easily convert this in to it's own jQuery method:
$.fn.hasOverflowed = function() {
var el = this[0];
return el.scrollWidth > el.clientWidth || el.scrollHeight > el.clientHeight;
}
if ($('#myElement').hasOverflowed()) {
// Run to the hills!
}
Example fiddle

You can compare height of element with its scrollHeight property and width with its scrollWidth property:
var $divs = $('div').filter(function(){
return $(this).css('overflow') === "hidden";
});
$divs.toggleClass('overflowed', function(){
return $(this).height() < $(this).prop('scrollHeight') || $(this).width() < $(this).prop('scrollWidth');
});
div {
height: 30px;
overflow: hidden;
}
.overflowed {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div>tteterre
er<br><br><br><br>
<br><br><br>
erz
r
</div>
Now you could create your own pseudo selector:
$.extend($.expr[":"], {
overflowed: $.expr.createPseudo ? $.expr.createPseudo(function() {
return function(el) {
return getComputedStyle(el).overflow === "hidden" && (el.scrollWidth > el.clientWidth || el.scrollHeight > el.clientHeight);
};
}) :
// support: jQuery <1.8
function(el) {
return getComputedStyle(el).overflow === "hidden" && (el.scrollWidth > el.clientWidth || el.scrollHeight > el.clientHeight);
}
});
$('div:overflowed').addClass('isOverflowed');
div {
position: relative;
margin: 10px;
width: 200px;
height: 2em;
overflow: hidden;
}
div > span {
position: absolute;
left: 400px;
display: block;
}
.isOverflowed {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div>doesn't overflow</div>
<div>there is little content overflowing by height</div>
<div>content element oveflowing <span>GET IT</span></div>

try the following
$(id).is(":visible")
The above code return true if the container is visible otherwise it will return false

If you are checking for a child element inside a parent, you'll need to compare the dimensions to see if the child is greater than the parent.
var parentWidth = $('.parent').width();
var parentHeight = $('.parent').height();
var childWidth = $('.child').width();
var childHeight = $('.child').height();
if(childWidth > parentWidth || childHeight > parentHeight){
//something is hidden
};
What I'm not confident about is if .height() and .width() will grab the true height and width of child or just the boundaries that the parent provides.
If this is only text inside of the div, I'm not sure how to check that.

Related

Add marquee dynamically

I am trying to add a marquee to my HTML dynamically. This is the function I have created
var element = document.getElementById('overflow');
var parentElement = document.getElementById('countheader');
if (element) {
var overflow = isElementOverflowing(element, parentElement);
if (overflow && !element.classList.contains('marquee')) {
element.className += "marquee";
} else if (!overflow) {
element.classList.remove('marquee');
}
}
function isElementOverflowing(element, parentElement) {
return parentElement.clientWidth <= element.clientWidth;
}
In the CSS file I have the styling as
#countheader{
background-color: #e9df8b;
width: fit-content;
white-space: nowrap;
min-width: 100%;
overflow: hidden;
padding-left: 11px!important;
max-width: 1266px!important;
}
#overflow{
max-width: 1266px!important;
}
#HTML
<div class="page-content" style="background-color: {{isDarkMode ? '#000000' : '#FFFFFF'}}">
<!-- Item Count Card-->
<div class="order-card item-card"
ng-if="currentStation.get('enableItemCount') && viewTitle === 'Open Orders' && currentStation.get('itemCountFilters').length > 0 && itemsCount.length > 0">
<div class="card-header" id="countheader">
<div id="overflow">
<b class="item-heading">Total Count</b>
<span class="item-count" ng-repeat="item in itemsCount">{{item.name}}({{item.quantity}})</span>
</div>
</div>
</div>
<!-- Item Count Card -->
But in some cases, I am seeing that the text overflows the parent div in the UI but in the function isOverflowing it is still showing parent element width greater and so the marquee does not gets added in the class. Is there a better way to find the height of the parent div and child div content?

Change active state on scroll to viewport

I'm trying to make a single static website, which when an div child of comes into viewport (precisely, when div element comes into the upper 50% of the viewport) changes the corresponding div's class in side-nav to "active". It should work scrolling down and up.
So far I've tried several solution from other threads on SO, none successful. I assume I've been approaching this wrong.
$(window).on('scroll', function() {
$("#vars-args").each(function() {
if (elementInViewport2($(this))) {
$(this).find("#div1a").addClass("active");
}
});
});
function elementInViewport2(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while (el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top < (window.pageYOffset + window.innerHeight) &&
left < (window.pageXOffset + window.innerWidth) &&
(top + height) > window.pageYOffset &&
(left + width) > window.pageXOffset
);
}
<script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script>
<div id="side-nav">
1
2
3
4
5
6
</div>
<div id="content">
<div id="div1">
<!--content-->
</div>
<div id="div2">
<!--content-->
</div>
<div id="div3">
<!--content-->
</div>
<div id="div4">
<!--content-->
</div>
<div id="div5">
<!--content-->
</div>
<div id="div6">
<!--content-->
</div>
</div>
Also note that content of each div inside can be larger than the size of viewport.
I have been having problems getting the javascript to work. Also please note that the current JS is copied from some other thread.
This can be achieved using the IntersectionObserver as told by #cloned in the comments: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
To achieve this, you need a callback function passed as a parameter which is executed once isIntersecting is true, an option object (below it sets the threshold at 50% of the element) and an IntersectionObserver.
The callback toggles the active class to the a element according to the entry's id.
At the end we loop through the divs and make our observer observe them.
const callback = (entries, observer) => {
entries.forEach(entry => {
const navItem = document.querySelector('#' + entry.target.id + 'a');
if (entry.isIntersecting) {
console.log(navItem.getAttribute('id'));
navItem.classList.add('active');
} else {
navItem.classList.remove('active');
}
});
};
const options = {
threshold: 0.5
};
const observer = new IntersectionObserver(callback, options);
const container = document.getElementById('content');
const targetElements = container.querySelectorAll('div');
targetElements.forEach(element => {
observer.observe(element);
});
Here is a JSBin to demonstrate it https://jsbin.com/riyuhediso/47/edit?html,js,console,output
Note that although it demonstrates its feasibility it's not been profiled for performance issues which can be significant so I don't vouch for it.
If you are using Bootstrap you can use the ScrollSpy lib https://getbootstrap.com/docs/4.1/components/scrollspy/ and there is also ScrollMagic which is great http://scrollmagic.io/
You need to filter out which element is inside the viewport with the help of .getBoundingClientRect()
Checkout this
and check if any content has it's top and bottom within the half of the viewport ( window.innerHeight )
I took help of filter function to find out the index of contents that is within the built in function and set the .active class of the corresponding anchor.
Have a look at the snippet:
var direction = 0; // a variable to keep track of scrolled position;
$(window).on('scroll', function() {
// check if window is scrolling up or down;
if ($(window).scrollTop() > direction) { // if true, window scrolling scrolling down;
$('#side-nav').find('a').removeClass('active'); // remove active class from all anchors
$('#side-nav').find('a').eq(
// .eq() selector helps to find elements with index number, and here we pass a filter to find the content that is within the viewport;
$('#content').find('div').filter(function(index) {
return this.getBoundingClientRect().y <= (window.innerHeight / 2) && this.getBoundingClientRect().y + this.getBoundingClientRect().height > window.innerHeight / 2;
}).index()
).addClass('active');
// update the current scroll position now;
direction = $(window).scrollTop();
} else { // if false, window scrolling scrolling up;
$('#side-nav').find('a').removeClass('active'); // remove active class from all anchors
$('#side-nav').find('a').eq(
$('#content').find('div').filter(function(index) {
return this.getBoundingClientRect().y < (window.innerHeight / 2) && this.getBoundingClientRect().y + this.getBoundingClientRect().height > window.innerHeight / 2;
}).index()
).addClass('active');
// update the current scroll position now;
direction = $(window).scrollTop();
}
});
* {
margin: 0;
padding: 0;
}
#side-nav {
/* feel free to remove or change, only for testing */
position: fixed;
width: 100%;
top: 0;
padding: 15px;
}
#side-nav a {
/* feel free to remove, only for testing */
text-decoration: none;
color: grey;
margin-right: 5px;
font-size: 24px;
font-weight: bold;
}
#side-nav a.active {
color: #000;
/* sets color for the default active class */
}
#content div {
min-height: 600px;
background-color: #cecece;
border-bottom: 1px solid #fff;
box-sizing: border-box;
padding: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="side-nav">
<a href="" id="div1a" class='active'>1</a>
<!-- set a default class assuming the first one will be in viewport while window loads -->
2
3
4
5
6
</div>
<div id="content">
<div id="div1">
<p>One</p>
</div>
<div id="div2">
<p>Two</p>
</div>
<div id="div3">
<p>Three</p>
</div>
<div id="div4">
<p>Four</p>
</div>
<div id="div5">
<p>Five</p>
</div>
<div id="div6">
<p>Six</p>
</div>
</div>

How to execute a function when the scroll reaches an element?

I want to hide all elements but the first one so I use $(".item:not(:eq(0))").fadeOut();
I have elements with the same class "item":
<div class="item">First Item</div>
<div class="item">Second Item</div>
<div class="item">Third Item</div>
<div class="item">Fourth Item</div>
Then when I scroll to the next element which could be "second , third,fourth item" , I want to show it
I tried using :
function isScrolledIntoView(elem)
{
var centerY = Math.max(0,((jQuery(window).height()-
jQuery(elem).outerHeight()) / 2)
+ jQuery(window).scrollTop());
var elementTop = jQuery(elem).offset().top;
var elementBottom = elementTop + jQuery(elem).height();
return elementTop <= centerY && elementBottom >= centerY;
}
jQuery(window).on("scroll resize", function() {
jQuery(".news:not(:eq(0))").each(function(index, element) {
if (isScrolledIntoView(element)) {
jQuery(element).fadeIn(10000);
}
});
});
But it doesn't work with my method because the height of the body changes on showing the next item "Second Item" , So All the items are shown when I scroll to the "Second Item" or any other item.
How to hide the items but the first one and then fadIn() each on scrolling to it ?
This is using offset() in jquery. This demo will trigger function if
your element is completely in your viewport.
Tip:You need to take care of inner as well as outer height of element.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
body{
height:200vh;
}
#test {
top: 100vh;
padding: 10px;
width: 300px;
position: relative;
border: 1px solid black;
height:100;
}
</style>
</head>
<body>
<p>scroll to test</p>
<div id="test">
<p>Click the button to get offsetTop for the test div.</p>
</div>
<script>
$(document).ready(function(){
$(window).scroll(function(){
var x = $("#test").offset();
var height1 = $("#test").outerHeight();
var y = document.documentElement.scrollTop;
var z = (x.top + height1) - y;
if(z < $(window).height()){
alert("fumction");
}
});
});
</script>
</body>
</html>
It will be more easy to use the combination of waypoint.js and animate.css.
Add animated class to every element to be animated. You can use any of the animate.css effects.
Change the offset { offset: '80%' } to control when the animation can start.
<div class="animated waypoint-slideup">
</div>
$('.waypoint-slideup').waypoint(function () {
$(this).addClass('slideInUp');
}, { offset: '80%' });
Use this in the css file
.waypoint-slideup{
opacity:0;}
.waypoint-slideup.slideInUp{
opacity:1;}

Animated navigation-bar doesn't work

I have a problem with my navigation dropout-menu. My result should be that if I click on a div, that the dropout-menu continuously will vary from height (0px to 400px and back). This means that I have to use a if-statement. The problem is that the dropout-menu only works the first time, but I click again, the height stays at 400px, so the if-statement isn't correct I think.
HTML:
<div id="menuIcon" onclick="openMenu()">
<div id="bar"> </div>
<div id="bar"> </div>
<div id="bar"> </div>
<div id="bar"> </div>
</div>
<div id="dropBar">
<ul>
<li> Portfolio </li>
<li> About me </li>
<li> Contact </li>
</ul>
</div>
CSS:
#dropBar {
text-align: center;
width: 100%;
background-color: white;
height: 0px;
overflow-x: hidden;
transition: 0.3s;
}
JAVASCRIPT:
function openMenu() {
var x = document.getElementById('dropBar');
if (x.style.height = "0px") {
x.style.height = "400px";
} else {
x.style.height = "0px";
}
}
In if statement you shouldn't use single equality sign. Use === equality operator like this:
if (x.style.height === "0px") {
x.style.height = "400px";
}
With this little change, your function works:
https://jsfiddle.net/rgbgtL08/
First of all, with a single = you're assigning not comparing
Then you should use clientHeight instead of style.height which returns the CssStyleDeclaration
function openMenu() {
var x = document.getElementById('dropBar');
// double == for comparison
// clientHeight returns a number
if (x.clientHeight == 0) {
//do some
} else {
//dome sone else
}
}
note
clientHeight includes padding in the calc

css apply style if parent width more than specific value

Want to apply css selectors if only parent element width more than specific value.
CSS must not use media query to implement this because no relation between viewport width and the parent div width.
Javascript is welcome but avoid continuous width check please.
Ex.
<style>
/* something like that div[width>400px] */
.parent div[width>400px]{
background:red;
}
</style>
<!--ok width is more than 400 so apply style to child div-->
<div class="parent" style="width:500px;">
<div>
</div>
</div>
<!--width is still less than 400 so don;t apply styles-->
<div class="parent" style="width:300px;">
<div>
</div>
</div>
The Resize event only works on the window element.
Vanilla JavaScript would be something like this.
var parentDivTriggrtWidth = 400;
var childDivClassNames = ["red", "blue"];
window.addEventListener("load", function(e){
var list = document.getElementsByClassName("parent");
for(var i=0; i<list.length; i++){
var parentDiv = list[i];
parentDiv.resizeParent = function(width){
if(typeof width!="undefined"){ this.style.width = width+"px"; }
var k = this.clientWidth > parentDivTriggrtWidth ? 1 : 0;
this.children[0].className = childDivClassNames[k];
// Debug only
this.children[0].innerHTML = "Parent Size: "+this.clientWidth+"<br />Class: "+this.children[0].className;
}
window.addEventListener("resize", function(e){ parentDiv.resizeParent(); },false);
parentDiv.resizeParent();
}
},false);
Look at the snippet in "fullpage"
var parentDivTriggrtWidth = 400;
var childDivClassNames = ["red", "blue"];
window.addEventListener("load", function(e){
var list = document.getElementsByClassName("parent");
for(var i=0; i<list.length; i++){
var parentDiv = list[i];
parentDiv.resizeParent = function(width){
if(typeof width!="undefined"){ this.style.width = width+"px"; }
var k = this.clientWidth > parentDivTriggrtWidth ? 1 : 0;
this.children[0].className = childDivClassNames[k];
// Debug only
this.children[0].innerHTML = "Parent Size: "+this.clientWidth+"<br />Class: "+this.children[0].className;
}
window.addEventListener("resize", function(e){ parentDiv.resizeParent(); },false);
parentDiv.resizeParent();
}
},false);
.parent {
border: 3px solid #aaaaaa;
}
.parent div {
width: 200px;
height: 200px;
color: white
}
.red {
background-color: red;
}
.blue {
background-color: blue;
}
<h3>width 500px (resize by JavaScript)</h3>
<div id="p1" class="parent" style="width:500px;">
<div></div>
</div>
<button type="button" onclick="document.getElementById('p1').resizeParent(800)">Resize +</button>
<button type="button" onclick="document.getElementById('p1').resizeParent(200)">Resize -</button>
<button type="button" onclick="document.getElementById('p1').resizeParent(500)">Reset</button>
<hr />
<h3>width 100% (resize window)</h3>
<!--width is still less than 400 so don;t apply styles-->
<div id="p2" class="parent" style="width:100%;">
<div></div>
</div>
jQuery is an option :
$( document ).ready(function() {
if ($(".parent").width() > 700) {
$('.parent').css("background-color", "red");
}
});
if i got you right...
JQuery:
$(document).ready(function(){
var ParentWidth = $('.parent').width();
if (ParentWidth > 400) {
$('.parent').addClass('newstyle');
}
});
CSS:
.newstyle
{
background: red;
/*** add more css ***/
}
i Recommends you to use class because you can add more css to the class later.

Categories

Resources