Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can CSS handle this hourglass-like situation?

Tags:

html

css

I am having a tough time thinking a solution to the following problem.
Let me illustrate it first:

Navigation Interface - Hourglass like

Situation
I have 26 items (in this example, in general the number is not known..) but only 12 can be visible at one time.. I also have some navigation elements (the green boxes)

Width of purple and green boxes is fixed but height of purple can vary according to content ..

All is normal and i can do it with css.

I am using an unordered list (of floated items) for my items and i have designated the first two <li> elements as the navigations ones. First has float left and second float right. It all works and the flow of the rest of the items goes between the two green ones.

Problem
But now i need the green items to be on the second row (or last if that concept helps as there will only be two rows)

I want to be able to hide the first X elements and show the next X and they fall in position on their own ..

To rephrase the question, can i position some elements (the green ones) in such a way to control their position but still allow them to interfere with the flow from their new locations ?

I hope this is clear. If not ask away and i will provide as much info as possible..

Things i have tried that did not work

  • Moving the green item with negative bottom margins, or positive top margins. They will move out of their place but the other elements will not fill in their position.
  • Using absolute position, but then the elements are completely removed from the flow and they do not affect the other elements so they overlap with the other elements..

[they grayed out items are hidden, i just show them so you know that they exist..]

Some code to get you started

<style type="text/css">ul,
li {
  padding: 0;
  margin: 0;
  list-style-type: none;
}

ul {
  width: 155px;
  position: relative;
  height: 125px;
  border: 1px solid red;
}

li {
  float: left;
  background-color: purple;
  margin-left: 5px;
  margin-top: 5px;
  width: 25px;
  text-align: center;
  line-height: 25px;
  color: white;
}

.prev {
  color: black;
  background-color: green;
}

.next {
  color: black;
  float: right;
  margin-right: 5px;
  background-color: green;
}

</style>
<body>
  <ul>
    <li class="prev">&lt;</li>
    <li class="next">&gt;</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>11</li>
    <li>12</li>
    <li>13</li>
    <li>14</li>
    <li>15</li>
    <li>16</li>
    <li>17</li>
  </ul>
</body>
like image 560
Gabriele Petrioli Avatar asked Jan 19 '10 19:01

Gabriele Petrioli


4 Answers

OK obviously this can not be solved with only Css/Html ..

So, to solve it, i used some CSS (with inline-block crossbrowser) and some jQuery to move the navigation buttons around so they stay always at the point i want them..

For reference here is the solution ..

function resetNextPrev() {
  $next.insertAfter('#performances li.shown:eq(' + ($perpage - 1) + ')');
  $prev.insertAfter('#performances li.shown:eq(' + ($perline - 1) + ')');
}
$(document).ready(function() {
  $perpage = 8;
  $perline = ($perpage + 2) / 2;
  $page = 1;
  $itemcount = $('#performances li.performance').length;
  $pages = Math.ceil($itemcount / $perpage);
  $next = $('#performances li.next');
  $prev = $('#performances li.prev');

  $('#performances li.performance').slice(0, $perpage).addClass('shown');

  if (($pages * $perpage) > $itemcount)
    for (var i = 0; i < ($pages * $perpage) - $itemcount; i++)
      $('<li class="performance placeholder">test</li>').appendTo('#performances');
  resetNextPrev();

  $('li.next').click(function() {
    if ($page < $pages)
      $('#performances li.performance').filter('.shown').removeClass('shown').end().slice($perpage * (++$page - 1), $perpage * $page).addClass('shown');
    resetNextPrev($perline);

  });
  $('li.prev').click(function() {
    if ($page > 1)
      $('#performances li.performance').filter('.shown').removeClass('shown').end().slice($perpage * (--$page - 1), $perpage * $page).addClass('shown');
    resetNextPrev($perline);

  });
});
<style type="text/css">ul,
li {
  padding: 0;
  margin: 0;
  list-style-type: none;
}

#performances {
  width: 155px;
  border: 1px solid red;
  line-height: 0;
  font-size: 0;
}

#performances li {
  font-size: 12px;
  background-color: purple;
  margin-left: 5px;
  margin-bottom: 5px;
  margin-top: 5px;
  width: 25px;
  text-align: center;
  line-height: 25px;
  color: white;
  display: none;
  vertical-align: top;
}

#performances .prev {
  color: black;
  background-color: green;
  display: -moz-inline-stack;
  display: inline-block;
}

#performances .next {
  color: black;
  background-color: green;
  display: -moz-inline-stack;
  display: inline-block;
}

#performances .shown {
  display: -moz-inline-stack;
  display: inline-block;
}

#performances .placeholder {
  visibility: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="performances">
  <li class="prev">&lt;</li>
  <li class="next">&gt;</li>
  <li class="performance">1</li>
  <li class="performance">2</li>
  <li class="performance">3</li>
  <li class="performance">4 dfs s sf</li>
  <li class="performance">5</li>
  <li class="performance">6</li>
  <li class="performance">7</li>
  <li class="performance">8</li>
  <li class="performance">9</li>
  <li class="performance">10</li>
  <li class="performance">11</li>
  <li class="performance">12</li>
  <li class="performance">13</li>
  <li class="performance">14</li>
  <li class="performance">15</li>
  <li class="performance">16</li>
  <li class="performance">17</li>
  <li class="performance">18</li>
  <li class="performance">19</li>
</ul>

There are a couple of hardcoded values inside, but i will leave it for anyone that might pick up something new from this ...

Thanks to all for the guidance :)

like image 116
Gabriele Petrioli Avatar answered Oct 18 '22 14:10

Gabriele Petrioli


It may be worth it to use javascript for a situation this complex. Libraries like jQuery can make it pretty painless. Defining these wrapping rules explicitly in js will be clearer and easier to maintain than doing it implicitly with a lot of css rules.

like image 30
Christian Oudard Avatar answered Oct 18 '22 14:10

Christian Oudard


Make the li except the navigation ones as display: inline-block and perhaps move the navigation li to the end of the list?

like image 2
Chetan S Avatar answered Oct 18 '22 13:10

Chetan S


Without seeing your code I cannot be sure. However, have you tried putting the green elements into tags and marking them as clear: both;? This might move them into a 3rd row though. It is something you should checkout.

like image 1
Ben Hoffman Avatar answered Oct 18 '22 12:10

Ben Hoffman