Search code examples
jquerycssjquery-uimedia-queries

Combining media-queries, last-of-type, and class names


I'm working on an application with a unique rule-set.
Here is a simplified rule-set:

  • The "main-entity" is always visible
  • There is only ever one "main-entity"
  • The "main-entity" can be at any position in the list
  • On large screens, there should be no more than 7 visible entities (1 main and 6 regular)
  • On medium screens, there should be no more than 4 visible entities (1 main and 3 regular)
  • On small screens, there should be no more than 2 visible entities (1 main and 1 regular)
  • The last elements should be shown first.

Here is the CSS:

.btn-breadcrumb > li.main-entity {
  display: block;
  color: red;
}
.btn-breadcrumb > li {
  display: none;
}
/* === For phones =================================== */
@media (max-width: 767px) {
  .btn-breadcrumb > li:nth-last-child(-n+1) {
    display: block;
  }
}
/* === For tablets ================================== */
@media (min-width: 768px) and (max-width: 991px) {
  .btn-breadcrumb > li:nth-last-child(-n+3) {
    display: block;
  }
}
/* === For desktops ================================== */
@media (min-width: 992px) {
  .btn-breadcrumb > li:nth-last-child(-n+6) {
    display: block;
  }
}

and here is some HTML:

<ul class="btn-breadcrumb">
  <li>Entity 1</li>
  <li>Entity 2</li>
  <li>Entity 3</li>
  <li>Entity 4</li>
  <li>Entity 5</li>
  <li>Entity 6</li>
  <li class="main-entity">Entity 7</li>
  <li>Entity 8</li>
</ul>

When the main-entity is in the beginning of the list, there is no problem. See a simple fiddle here. Change the width to see it in action.

However, if the main-entity is one of the last elements, I'm off by 1. See here.

In the original implementation, the main-entity was always in position 1, so it was easy to implement. Now with the requirement that the main-entity can move, I'm not sure what the best way to determine if the main-entity is in the visible set of entities depending on the screen size. I know this cannot be done purely with CSS (I've been through several discussions such as here, explaining why pseudo classes can't be applied to a selector).

Using jQuery, I can detect resize events and determine the screen width and then set visible elements accordingly. This just seems very redundant to have to pull my media query values into my code. Is that really the only solution here?


Solution

  • You can avoid adding media queries into the Javascript with the following:

    JavaScript

    $('.btn-breadcrumb > li:not(.main-entity)').slice(-1).addClass('phone');
    $('.btn-breadcrumb > li:not(.main-entity)').slice(-3).addClass('tablet');
    $('.btn-breadcrumb > li:not(.main-entity)').slice(-6).addClass('desktop');
    

    CSS

    /* === For phones =================================== */
    @media (max-width: 767px) {
      .btn-breadcrumb > li.phone {
        display: block;
      }
    }
    /* === For tablets ================================== */
    @media (min-width: 768px) and (max-width: 991px) {
      .btn-breadcrumb > li.tablet {
        display: block;
      }
    }
    /* === For desktops ================================== */
    @media (min-width: 992px) {
      .btn-breadcrumb > li.desktop {
        display: block;
      }
    }
    

    HTML will output like this:

    <ul class="btn-breadcrumb">
    <li>Entity 1</li>
    <li class="desktop">Entity 2</li>
    <li class="desktop">Entity 3</li>
    <li class="desktop">Entity 4</li>
    <li class="tablet desktop">Entity 5</li>
    <li class="tablet desktop">Entity 6</li>
    <li class="main-entity">Entity 7</li>
    <li class="phone tablet desktop">Entity 8</li>
    </ul>
    

    Play around with moving the .main-entity class to another list item and you will see that it obeys your rules.

    https://jsfiddle.net/rr5Lcjok/60/