Mark last visible child in overflown div using CSS or JS - javascript

I have a bar with inline-block divs. Some of them are out of viewport because I set: white-space:nowrap; overflow: hidden; for the container. I'm looking for ways to select last visible child. By visible I mean that the div is placed (preferably fully) in area of it's container.
As far as I know there is selector like that neither in CSS nor in jQuery. The closest one is jQuery's :visible but it says that all the divs are visible because they consume space in the page layout.
The only way out I see is to enumerate divs on load and every resize in order to calculate if the div is still in the container by summing it's width, padding and margins.
Do you have any better ideas?
#container {
white-space:nowrap;
overflow: hidden;
}
.element {
display: inline-block;
vertical-align:top;
}
<div id="container">
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
</div>
In current, non responsive version of stack overflow on the snippet we can see 4 full divs and small part of 5th. I'd like to select 5th one (or preferably 4th div because the next one isn't fully visible).

You could use media queries. Of course, this could become very cumbersome, depending on the number of child elements you have, but it does save the overhead of using an onresize event listener.
For the below Snippet, I've assumed that the parent element is running the full width of the screen.
*{box-sizing:border-box;margin:0;padding:0;}
#container{
font-size:0;
overflow:hidden;
white-space:nowrap;
}
.element{
display:inline-block;
opacity:.5;
padding:5px;
vertical-align:top;
width:150px;
}
img{
width:100%;
}
#media (max-width:299px){
.element:first-child{opacity:1;}
}
#media (min-width:300px) and (max-width:449px){
.element:nth-child(2){opacity:1;}
}
#media (min-width:450px) and (max-width:599px){
.element:nth-child(3){opacity:1;}
}
#media (min-width:600px) and (max-width:749px){
.element:nth-child(4){opacity:1;}
}
#media (min-width:750px) and (max-width:899px){
.element:nth-child(5){opacity:1;}
}
#media (min-width:900px) and (max-width:1049px){
.element:nth-child(6){opacity:1;}
}
#media (min-width:1050px) and (max-width:1199px){
.element:nth-child(7){opacity:1;}
}
#media (min-width:1200px){
.element:nth-child(8){opacity:1;}
}
<div id="container">
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
<div class="element">
<img src="http://placehold.it/150x150" alt=""/>
</div>
</div>

i've done some JQ code, hope it helps
this works if all elements have the same width. if they have different widths the code would need some small changes
see here > JSFIDDLE
JQ CODE :
var vwidth = $(window).width() // get window width
var ewidth = $(".element").width() // get element width
var total = vwidth / ewidth // calculate how many elements fit inside the window width
var integer = parseInt(total)// get the integer from the result above
$(".element").eq( integer - 1 ).addClass("lastvisible")// -1 because eq starts from 0
solution for elements with different widths :
JQ :
var vwidth = $(window).width(); // get screen width
$(".element").each(function(){
var eleft = $(this).offset().left // each element's distance from left of the screen
var ewidth = $(this).width()// each element's width
var total = eleft + ewidth
if (total < vwidth) { // if sum between distance from left of screen + element width is smaller than the window screen
that = $(this); // all elements that are visible inside the screen
}
});
that.addClass("lastvisible") //only the last element visible inside the screen
see fiddle here > JsFiddle

This is my way to make it work but I'll welcome any better way.
Everything is being calculated by jQuery:
var cwidth = parseInt($('#container').width()); // get container width
var lastElement = $('#container .element:first'); // assume that first element is visible
$("#container .element:not(:first)").each(function(){
//get right offset for every div
var rightOffset = $(this).offset().left
+ parseInt($(this).width())
+ parseInt($(this).css('padding-left'))
+ parseInt($(this).css('margin-left'));
//if the right offset is bigger than container width then stop enumerating - previous one was the last fully visible
if (rightOffset > cwidth){
return false;
}
//offset was lower than container with so this is our new fully visible element
lastElement = $(this);
});
lastElement.addClass("lastvisible")
advantages:
Working for different element sizes
Add same recalculating on window resize and you've got a working responsive way
drawbacks:
multiple jQuery recalculations that are quite havy for the browser
in my opinion ugly code
https://jsfiddle.net/6k5xujtc/1/

Related

How can I get different item position with same classname?

When mousemove() it only gets the position of first item. Now they are all overlapping. How can I improve this?
https://codepen.io/penny289/pen/JjJzYbv
$(window).mousemove(function(evt){
$('.img-box').each(function(){
var positionX= $(this).offset().left/100
var positionY= $(this).offset().top/100
$(this).css("left",positionX+evt.pageX/100+"%")
.css("top",positionY+evt.pageY/100+"%")
})
})
<div class="container">
<div class="img-box box-1">
<img src="https://images.unsplash.com/photo-1632012643163-c9c4fbbd9f05?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzEwNg&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-2">
<img src="https://images.unsplash.com/photo-1632778931175-128809d8facc?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzE2MQ&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-3">
<img src="https://images.unsplash.com/photo-1594734044877-2ebba0c14720?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzIwMg&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-4">
<img src="https://images.unsplash.com/photo-1630231211819-a131d7538a41?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzIxNQ&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-5">
<img src="https://images.unsplash.com/photo-1632073591482-0d69552e07df?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzI1NA&ixlib=rb-1.2.1&q=85">
</div>
</div>
It does not get the coordinates of the first image only. Rather, you seem to have several problems:
You are dividing by 100, presumably because you are working with percentages, but unless your screen is 100 pixels wide that is obviously wrong.
.offset() does return an offset relative to the document, but you are positioning your items relative to your container
You are trying to dynamically grab the offset every time, but if you go for this approach you would need to know what part of that offset is from the previous time you called this function. Otherwise you start accumulating the x and y position of your MouseEvent and quickly move the entire thing off the screen.
There is no reason for you to use percentages, so just work with absolute pixels and simplify your code.
Then store the initial offset with .data(..) so you don't have to subtract your previous mouse position and keep track of that every single time. Since you want to have the offset relative to the container (because your css renders it relative to the container), subtract the container offset from your image offset.
Now you can make the images move with your mouse by adding your mouse pageX/pageY.
Besides that, you should use a debounce (does not work in stacksnippets) and window.requestAnimationFrame so your cpu does not melt trying to draw something for every pixel your mouse moves, but rather only when it is ready to draw a single frame.
$(window).mousemove(function(evt){
//_.debounce(() => {
window.requestAnimationFrame(() => {
const containerOffsetX = $('.container').offset().left;
const containerOffsetY = $('.container').offset().top;
$('.img-box').each(function(elem, i){
let imageOffsetX = $(this).data('offsetX');
if (!imageOffsetX) {
imageOffsetX = $(this).offset().left - containerOffsetX;
$(this).data('offsetX', imageOffsetX);
}
let imageOffsetY = $(this).data('offsetY');
if (!imageOffsetY) {
imageOffsetY = $(this).offset().top - containerOffsetY;
$(this).data('offsetY', imageOffsetY);
}
const mouseOffsetX = evt.pageX;
const mouseOffsetY = evt.pageY;
const newPositionX = imageOffsetX + mouseOffsetX;
const newPositionY = imageOffsetY + mouseOffsetY;
$(this).css("left", `${newPositionX}px`)
.css("top", `${newPositionY}px`)
});
});
//}, 10);
});
body{
display:flex;
align-items:center;
justify-content:center;
}
.container{
width:70vw;
height:500px;
position:relative;
}
.img-box{
position:absolute;
}
.img-box img{
width:300px;
height:200px;
/* transform:translate(-50%); */
}
.img-box.box-1{
top:10%;
}
.img-box.box-2{
left:20%;
top:80%;
}
.img-box.box-3{
top:50%;
left:50%;
}
.img-box.box-4{
top:10%;
left:90%
}
.img-box.box-5{
left:90%;
top:70%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div class="container">
<div class="img-box box-1">
<img src="https://images.unsplash.com/photo-1632012643163-c9c4fbbd9f05?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzEwNg&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-2">
<img src="https://images.unsplash.com/photo-1632778931175-128809d8facc?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzE2MQ&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-3">
<img src="https://images.unsplash.com/photo-1594734044877-2ebba0c14720?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzIwMg&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-4">
<img src="https://images.unsplash.com/photo-1630231211819-a131d7538a41?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzIxNQ&ixlib=rb-1.2.1&q=85">
</div>
<div class="img-box box-5">
<img src="https://images.unsplash.com/photo-1632073591482-0d69552e07df?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYzMjk4MzI1NA&ixlib=rb-1.2.1&q=85">
</div>
</div>

How to resize a png image to fit in a div?

I am trying to resize a PNG image to fit in a div
This the div where I'd like to fit it in:
But this is how it looks like:
I tried to solve it by this Changing image sizes proportionally using CSS? but no change was noticed.
Here's the code snippet:
<div className="Card-header">
{this.props.roadmapID}
<label className="Card-header-status">{this.props.technology.toString().replace(/,/g , " ")}</label>
<label>{this.props.category}</label>
<img src="images/dark_chat.png"></img>
<CardStatus
status = {this.props.status}
onClickStatus = {this.props.onClickStatus}
/>
</div>
div.Card-header > img {
max-width: 100%;
max-height: 100%;
}
Use in your Stylesheet
.Card-header {
width: XYpx;
height: XYpx;
}
and this in your html:
<div class="card-header">
<img src="yourpic.jpg" style=" width:100%; height:100%;">
</div>
Your image will now expand to your given div size you declared in the stylesheet.
Why not set your image height to 100% of your div and then use width:auto ?
<img src="/path/to/your-image.png" style="height:100%; width:auto;" >
Even if the height of your div changes, the image will adjust proportionally.
Also, if you want this page to load reasonably quickly, it would definitely be worth re-sizing that image.
There is no code so this is a guess:
<div MB018>
<img src="whatever.jpg" width="10px" height="10px">
</div>

Calculate element padding dynamically using JavaScript

I'm trying to calculate the padding-bottom property for multiple elements in an image gallery. Check out the following code for one element:
<div class="item-container fashion">
<a href="images/fashion/11-large.jpg"
data-size="600x900"
class="item"
style="padding-bottom: 150%">
<img class="lazyload"
alt="Description"
src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
data-sizes="auto"
data-src="images/fashion/11-small.jpg"/>
</a>
</div>
As you can see I define the size of the image in "data-size" attribute (600x900). In order to get the padding-bottom value which I need to prevent reflow, I simply divide calculate (height/width) x 100, which in this case yields 150 - my padding-bottom value.
Now I can easily calculate this manually and input it as I'm doing above and it works just fine. But since my gallery will contain hundreds of images all with different ratios, I'm gonna need a more automated way of calculating the padding value.
Is there anyway to achieve this by doing the calculation in JavaScript and then apply it to the respective element? If I were to include the dimensions in the filename for example and parse it maybe I could even avoid manually inputting the data-size value too...?
I would really like to avoid having to manually do hundreds of calculations, plus It'll be great to learn a new trick for the future. Thanks!
UPDATE
here's what I got so far, as you can see image1 and image2 have different dimensions and ratio. As you can see i'm doing something wrong the padding isn't working out just right. I'm setting "item" height to 0 because padding-bottom will end up taking care of the height. thoughts?
var tags = document.getElementsByClassName('item');
for (var i = 0; i < tags.length; ++i) {
/* This is the part I mentioned about, you may want to use one of the methods above depending on how your css and the rest of your code looks like*/
tags[i].style.paddingBottom = (100 * (tags[i].offsetHeight / tags[i].offsetWidth)) + 'px';
}
.item {
position: relative;
height: 0;
display: inline-block;
border: 1px solid red;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="item-box fashion">
<a href="http://lorempixel.com/output/city-h-c-600-900-7.jpg" data-size="600x900" class="item">
<img width="300" height="450" class="lazyload" alt="Image description" src="http://lorempixel.com/output/city-h-c-600-900-7.jpg" data-sizes="auto" />
</a>
</div>
<div class="item-box fashion">
<a href="http://lorempixel.com/output/fashion-q-c-600-400-5.jpg" data-size="600x900" class="item">
<img width="300" height="200" class="lazyload" alt="Image description" src="http://lorempixel.com/output/fashion-q-c-600-400-5.jpg" data-sizes="auto" />
</a>
</div>
First of all why don't you have to define the dimension of the picture. You can use element.offsetWidth element.offsetHeight OR element.style.width, element.style.height (these two would have to be parsed because they return a string for instance 5px) OR element.getBoundingClientRect() (the lattest is an object containing top, left, right, bottom etc.)
Now, that being said using java you can do the following ...
var tags = document.getElementsByClassName('item');
for(var i = 0; i < tags.length; ++i){
/* This is the part I mentioned about, you may want to use one of the methods above depending on how your css and the rest of your code looks like*/
tags[i].style.paddingBottom = (100 * (tags[i].offsetHeight / tags[i].offsetWidth)) + 'px';
}
.item{
width: auto;
height: auto;
display: inline-block;
border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="item-box fashion">
<a href="http://lorempixel.com/output/city-h-c-600-900-7.jpg" data-size="600x900" class="item">
<img width="300" height="450" class="lazyload" alt="Image description" src="http://lorempixel.com/output/city-h-c-600-900-7.jpg" data-sizes="auto" />
</a>
</div>
<div class="item-box fashion">
<a href="http://lorempixel.com/output/fashion-q-c-600-400-5.jpg" data-size="600x900" class="item">
<img width="300" height="200" class="lazyload" alt="Image description" src="http://lorempixel.com/output/fashion-q-c-600-400-5.jpg" data-sizes="auto" />
</a>
</div>

toogle not working when wrapped around 2 containers

am trying to make a slider, and make the text and image slide when i click on an arrow(img)
<div class="col span_12_of_12 bannerHomeHeight">
<div class="homeImage1" id="homeBannerContainer1" style="display: block">
<div class="homeImage">
<h4>HIV</h4>
<img src="/images/banner-hiv-icons.png" alt=""/>
</div>
<div class="homeBanner">
<h3>HIV support materials for healthcare professionals, paitent groups and paitents</h3>
<div class="homeArrow">
<img src="/images/arrow.png" alt=""/>
</div>
</div>
</div>
</div>
<div class="homeImage1" id="homeBannerContainer2" style="display: none">
<div class="homeImage">
<h4>HCV</h4>
<img src="/images/banner-hep-icons.png" alt=""/>
</div>
<div class="homeBanner">
<h3>HCV support materials for healthcare professionals, paitent groups and paitents</h3>
<div class="homeArrow">
<img src="/images/arrow.png" alt=""/>
</div>
</div>
</div>
My J query is:
$(function () {
$(".homeArrow").on('click', function () {
$('.homeImage1').animate({
width: 'toggle'
});
});
});
homeImage1 is the container which i want sliding but the 2nd one goes to the bottom rather than coming in from the side.
live: thenandnow.anytimeafter9.co.uk
The problem is your bannerHomeHeight for the first slider frame is still there taking up space when you toggle its child homeImage1's display.
Try toggle bannerHomeHeight instead:
$(function () {
$(".homeArrow").on('click', function () {
$(".bannerHomeHeight").animate({
width: 'toggle'
});
});
});
[EDIT]
The problem with this is that when both elements are side by side during animation they take up > 100% and one is forced underneath. To solve this we can give .bannerHomeHeight 2 style changes (max height and width) so it is as follows:
.bannerHomeHeight {
margin-top: -16px;
min-height: 170px;
background-color: #54565b;
max-height: 170px;
width: 98%;
}
This way the height isn't seen to change to fit the content as it animates, and being 98% width is just enough to prevent the combination of the 2 becoming over 100% (I don't know whats causing this exactly, I guess something to do with padding/margins ?)

Muliple hidden fullscreen divs?

I'm working on my portfolio website, but can't solve the following problem.
The website is basically just pictures, if you click on one,
a semi-transparent fullscreen div opens with information (more pics and some text).
If you click again the div will close.
jQuery for hiding and showing:
<script>
$(function()
{
$('.masonryImage').click(function()
{
$('.hiddenDiv').show();
$("body").css("overflow", "hidden");
});
$('.hiddenDiv').click(function()
{
$('.hiddenDiv').hide();
$("body").css("overflow", "auto");
});
});
</script
HTML:
<div class="masonryImage">
<img src="images/pic1.jpg" alt="">
</div>
<div class="hiddenDiv">
<div class="text">
<p>Lorem ipsum...</p>
</div>
<div class="pics">
<img src="images/pic2.jpg" alt="">
</div>
</div>
So far it works with one picture, but when I'm adding another,
the new hidden text will overlay the first one, same with the pictures.
Is it because I'm using the same class ("masonryImage")?
Or isn't my Javascript removing the divs properly?
Many thanks.
Edit: CSS might be usefull:
.hiddenDiv {
position:fixed;
top:0;
left:0;
background:rgba(255,255,255,0.8);
z-index:900;
width:100%;
height:100%;
display:none;
overflow: scroll;
}
.masonryImage {
margin: 20px 20px 20px;
display: inline-block;
cursor: pointer;
}
here is how I modified your code :
DEMO
HTML
<div class="masonryImage">
<img src="..." alt="">
<div class="hiddenDiv">
<div class="text">
<p>Lorem ipsum...</p>
</div>
<div class="pics">
<img src="..." alt="">
</div>
</div>
</div>
I put the hiddenDiv inside the masonryImage so every masonryImage will have a custom hiddenDiv to show/hide.
JQUERY
$('.masonryImage').click(function()
{
if ($(this).find('.hiddenDiv').toggle().is(":visible")) {
//alert('hiddenDiv is visible !');
$("body").css("overflow", "hidden");
}
else {
//alert('hiddenDiv is hidden !');
$("body").css("overflow", "auto");
}
});
You can just use .toogle() to show/hide the div. $(this) refers to the clicked masonryImage and .find('.hiddenDiv') to its child (you can also use .children('.hiddenDiv') ).
Then you can test if the clicked div is hidden or visible with .is(":visible"), to apply your body custom css :)
Hope I helped you.

Categories