5

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).

Luke
  • 2,350
  • 6
  • 26
  • 41
  • http://stackoverflow.com/questions/5275098/a-css-selector-to-get-last-visible-div – Patrick Mlr Sep 01 '16 at 09:43
  • @PatrickMlr I've seen that link but there is used a `display:none`. We're struggling with the overflow here – Luke Sep 01 '16 at 09:45
  • You could try to get the `width` of the container and the `offset` every element with jQuery. And if the offset is greater than the width, you do your thing. – Patrick Mlr Sep 01 '16 at 09:50
  • @PatrickMlr yup, that's another implementation of my current idea. I asked the question to find a better one – Luke Sep 01 '16 at 09:52
  • Do all the inner elements have the same width? – thirtydot Sep 01 '16 at 09:53
  • @thirtydot In this example - yes. But I'm sure that someone who's gonna find this topic will not have same sized elements. It also should be responsive so cutting down div after like 600px is a terrible solution. – Luke Sep 01 '16 at 09:55
  • 1
    If the elements can be different widths, there is no better approach than looping over the elements and calculating widths (for a general solution). Are new elements being dynamically added? Can the widths of elements change? If not, you can cache the widths at the start, and then at least the resize loop will be more efficient. – thirtydot Sep 01 '16 at 10:10
  • @thirtydot I've added a possible solution that meets all the expectations, feel free to make it better – Luke Sep 01 '16 at 10:36
  • i've added a solution in my answer. works for different widths . let me know if that's what you are looking for. – Mihai T Sep 01 '16 at 11:04

3 Answers3

1

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>
Shaggy
  • 6,696
  • 2
  • 25
  • 45
  • This answer will also work only for same sized elements but it's a great example of media queries usage. – Luke Sep 01 '16 at 10:10
  • I take it you've no way of knowing the content of each child element and, therefore, their widths? – Shaggy Sep 01 '16 at 15:46
0

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

Mihai T
  • 17,254
  • 2
  • 23
  • 32
  • This solution will work only when all elements have same size, see: https://jsfiddle.net/z59yosLc/ – Luke Sep 01 '16 at 10:06
  • 1
    that's what i wrote in my answer .. also it's an answer to your question using the code provided by you. so by SO standards this is a correct answer – Mihai T Sep 01 '16 at 10:09
  • @user1100671 edited my answer with another solution ...works for different widths – Mihai T Sep 01 '16 at 10:56
0

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/

Luke
  • 2,350
  • 6
  • 26
  • 41
  • There are many possible improvements. And, as with all things involving jQuery, someone already wrote a plugin: https://github.com/customd/jquery-visible. If you want efficiency, you can do better, but it's unlikely to be worth the time. – thirtydot Sep 01 '16 at 11:19
  • @thirtydot it doesn't work for overflow: http://i.imgur.com/ke9DO1q.png – Luke Sep 02 '16 at 07:00