skip to Main Content

I want to highlight ranges of dates in a calendar (monthly view). The ranges of dates should be rounded of at both sides. I can round of the left side, but I cannot get the right side to work. What’s the problem here?

/* For the first highlighted li element in any range (this works well) */
.days li:not(.highlighted) + li.highlighted {
  border-top-left-radius: 10px;
  border-bottom-left-radius: 10px;
}

/* For the last highlighted li element in any range (this doesn't work) */
.days li.highlighted + li:not(.highlighted) {
  border-top-right-radius: 10px !important;
  border-bottom-right-radius: 10px !important;
}
<div class="calendar">
    <ul class="weeks">
      <li>Sun</li>
      <li>Mon</li>
      <li>Tue</li>
      <li>Wed</li>
      <li>Thu</li>
      <li>Fri</li>
      <li>Sat</li>
    </ul>
    <ul class="days">
      <li class="inactive">26</li>
      <li class="inactive">27</li>
      <li class="inactive">28</li>
      <li class="inactive">29</li>
      <li class="inactive">30</li>
      <li class="inactive">31</li>
      <li>1</li>
      <li class="highlighted">2</li>
      <li class="highlighted">3</li>
      <li>4</li>
    </ul>
</div>

I’ve provided the full HTML code and an example in a JSFiddle as well.
And here is the full code :

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  display: flex;
  align-items: center;
  padding: 0 10px;
  justify-content: center;
  min-height: 100vh;
  background: #9B59B6;
}

.wrapper {
  width: 95%;
  margin: auto;
  margin-top: 10px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 15px 40px rgba(0, 0, 0, 0.12);
}

.calendar {
  padding: 20px;
}

.calendar ul {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  text-align: center;
}

.calendar .days {
  margin-bottom: 20px;
}

.calendar li {
  color: #333;
  width: calc(100% / 7);
  font-size: 1.07rem;
}

.calendar .weeks li {
  font-weight: 500;
  cursor: default;
}

.calendar .days li {
  z-index: 1;
  cursor: pointer;
  position: relative;
  margin-top: 30px;
}

.days li.highlighted {
  background-color: lightblue;
}


/* For the first highlighted li element in any range */

.days li:not(.highlighted)+li.highlighted {
  border-top-left-radius: 10px;
  border-bottom-left-radius: 10px;
}


/* For the last highlighted li element in any range */

.days li.highlighted+li:not(.highlighted) {
  border-top-right-radius: 10px !important;
  border-bottom-right-radius: 10px !important;
}
<div class="wrapper">
  <div class="calendar">
    <ul class="weeks">
      <li>Sun</li>
      <li>Mon</li>
      <li>Tue</li>
      <li>Wed</li>
      <li>Thu</li>
      <li>Fri</li>
      <li>Sat</li>
    </ul>
    <ul class="days">
      <li class="inactive">26</li>
      <li class="inactive">27</li>
      <li class="inactive">28</li>
      <li class="inactive">29</li>
      <li class="inactive">30</li>
      <li class="inactive">31</li>
      <li>1</li>
      <li>2</li>
      <li class="highlighted">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>
      <li>18</li>
      <li class="highlighted">19</li>
      <li class="highlighted">20</li>
      <li class="active highlighted">21</li>
      <li class="highlighted">22</li>
      <li class="highlighted">23</li>
      <li class="highlighted">24</li>
      <li class="highlighted">25</li>
      <li class="highlighted">26</li>
      <li class="highlighted">27</li>
      <li class="highlighted">28</li>
      <li class="highlighted">29</li>
      <li class="highlighted">30</li>
      <li class="inactive highlighted">1</li>
      <li class="inactive highlighted">2</li>
      <li class="inactive highlighted">3</li>
      <li class="inactive">4</li>
      <li class="inactive">5</li>
      <li class="inactive">6</li>

    </ul>
  </div>
</div>

3

Answers


  1. This is a live demo of your code:

    li.highlighted {
      background: #aaf;
    }
    
    .days li:not(.highlighted)+li.highlighted {
      border-top-left-radius: 10px;
      border-bottom-left-radius: 10px;
    }
    
    .days li.highlighted+li:not(.highlighted) {
      border-top-right-radius: 10px !important;
      border-bottom-right-radius: 10px !important;
    }
    <ul class=days>
      <li>1</li>
      <li class=highlighted>2</li>
      <li class=highlighted>3</li>
      <li>4</li>
    </ul>

    You’re targetting li:not(.highlighted) but since it has no visible border or background colour you can’t see any difference.

    When I set a background on the other li elements you can see the radius on 4:

    li {
      background: #afa;
    }
    
    li.highlighted {
      background: #aaf;
    }
    
    .days li:not(.highlighted)+li.highlighted {
      border-top-left-radius: 10px;
      border-bottom-left-radius: 10px;
    }
    
    .days li.highlighted+li:not(.highlighted) {
      border-top-right-radius: 10px !important;
      border-bottom-right-radius: 10px !important;
    }
    <ul class=days>
      <li>1</li>
      <li class=highlighted>2</li>
      <li class=highlighted>3</li>
      <li>4</li>
    </ul>

    You want to target li.highlighted, but that isn’t the subject of the selector.

    The :has() psuedo-class will let you make the highlighted li element the subject but browser support is still lacking (most major browsers support it now, but Firefox’s implementation is still buggy and locked behind a feature flag).

    li {
      background: #afa;
    }
    
    li.highlighted {
      background: #aaf;
    }
    
    .days li:not(.highlighted)+li.highlighted {
      border-top-left-radius: 10px;
      border-bottom-left-radius: 10px;
    }
    
    .days li.highlighted:has(+ li:not(.highlighted)) {
      border-top-right-radius: 10px !important;
      border-bottom-right-radius: 10px !important;
    }
    <ul class=days>
      <li>1</li>
      <li class=highlighted>2</li>
      <li class=highlighted>3</li>
      <li>4</li>
    </ul>

    You’re be safest adding an extra class:

    li {
      background: #afa;
    }
    
    li.highlighted {
      background: #aaf;
    }
    
    .days li:not(.highlighted)+li.highlighted {
      border-top-left-radius: 10px;
      border-bottom-left-radius: 10px;
    }
    
    .days li.highlighted.end-of-set {
      border-top-right-radius: 10px !important;
      border-bottom-right-radius: 10px !important;
    }
    <ul class=days>
      <li>1</li>
      <li class=highlighted>2</li>
      <li class="highlighted end-of-set">3</li>
      <li>4</li>
    </ul>
    Login or Signup to reply.
  2. The issue it that with .days li.highlighted + li:not(.highlighted) you are selecting the element after the last .highlighted and that one doesn’t have the lightblue background so no round border can be displayed.

    As shown by Quentin, there is no reliable CSS selector to target the last element with a specific class. And the safest would be to add a class to the last elements with the .highlighted class.

    If you cannot do that, you could use a workaround with a pseudo element to make the last round border :

    *{
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    body{
      display: flex;
      align-items: center;
      padding: 0 10px;
      justify-content: center;
      min-height: 100vh;
      background: #9B59B6;
    }
    .wrapper{
      width: 95%;
      margin: auto;
      margin-top: 10px;
      background: #fff;
      border-radius: 10px;
      box-shadow: 0 15px 40px rgba(0,0,0,0.12);
    }
    
    .calendar{
      padding: 20px;
    }
    .calendar ul{
      display: flex;
      flex-wrap: wrap;
      list-style: none;
      text-align: center;
    }
    .calendar .days{
      margin-bottom: 20px;
      overflow: hidden;
    }
    .calendar li{
      color: #333;
      width: calc(100% / 7);
      font-size: 1.07rem;
    }
    .calendar .weeks li{
      font-weight: 500;
      cursor: default;
    }
    .calendar .days li{
      z-index: 1;
      cursor: pointer;
      position: relative;
      margin-top: 30px;
    }
    .days li.highlighted{
      background-color: lightblue;
    }
    
    /* For the first highlighted li element in any range */
    .days li:not(.highlighted) + li.highlighted {
      border-top-left-radius: 10px;
      border-bottom-left-radius: 10px;
    }
    
    /* For the last highlighted li element in any range */
    
    li.highlighted {
      position: relative;
    }
    li.highlighted::after {
      content: '';
      position: absolute;
      left: 100%;
      width: 10px;
      height: 100%;
      border-radius: 0 10px 10px 0;
      background: inherit;
    }
    <div class="wrapper">
      <div class="calendar">
        <ul class="weeks">
          <li>Sun</li>
          <li>Mon</li>
          <li>Tue</li>
          <li>Wed</li>
          <li>Thu</li>
          <li>Fri</li>
          <li>Sat</li>
        </ul>
        <ul class="days">
          <li class="inactive">26</li>
          <li class="inactive">27</li>
          <li class="inactive">28</li>
          <li class="inactive">29</li>
          <li class="inactive">30</li>
          <li class="inactive">31</li>
          <li>1</li>
          <li>2</li>
          <li class="highlighted">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>
          <li>18</li>
          <li class="highlighted">19</li>
          <li class="highlighted">20</li>
          <li class="active highlighted">21</li>
          <li class="highlighted">22</li>
          <li class="highlighted">23</li>
          <li class="highlighted">24</li>
          <li class="highlighted">25</li>
          <li class="highlighted">26</li>
          <li class="highlighted">27</li>
          <li class="highlighted">28</li>
          <li class="highlighted">29</li>
          <li class="highlighted">30</li>
          <li class="inactive highlighted">1</li>
          <li class="inactive highlighted">2</li>
          <li class="inactive highlighted">3</li>
          <li class="inactive">4</li>
          <li class="inactive">5</li>
          <li class="inactive">6</li>
    
        </ul>
      </div>
    </div>

    Note that :

    • the pseudo element is applied to all the elements with the .highlighted class. but it can only be seen over the first elements after the .highlighted ones
    • I added overflow: hidden; on the .days element to hide the pseudo elements that shouldn’t be seen (at the end of each line)
    Login or Signup to reply.
  3. Another option (in addition to the already proposed solutions) is to use :before and :after in .days li.highlighted + li:not(.highlighted) with the colors used:

    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    body {
      display: flex;
      align-items: center;
      padding: 0 10px;
      justify-content: center;
      min-height: 100vh;
      background: #9B59B6;
    }
    
    .wrapper {
      width: 95%;
      margin: auto;
      margin-top: 10px;
      ;
    }
    
    .calendar {
      --background: #fff;
      --highlighted: lightblue;
      --radius: 10px;
      padding: 20px;
      background: var(--background);
      border-radius: 10px;
      box-shadow: 0 15px 40px rgba(0, 0, 0, 0.12)
    }
    
    .calendar ul {
      display: flex;
      flex-wrap: wrap;
      list-style: none;
      text-align: center;
    }
    
    .calendar .days {
      margin-bottom: 20px;
    }
    
    .calendar li {
      color: #333;
      width: calc(100% / 7);
      font-size: 1.07rem;
    }
    
    .calendar .weeks li {
      font-weight: 500;
      cursor: default;
    }
    
    .calendar .days li {
      z-index: 1;
      cursor: pointer;
      position: relative;
      margin-top: 30px;
      padding:0 var(--radius);
    }
    
    /* highlighted styles */
    
    .days li.highlighted {
      background-color: var(--highlighted);
    }
    
    .days li:not(.highlighted) + li.highlighted {
      border-top-left-radius: var(--radius);
      border-bottom-left-radius: var(--radius);
    }
    
    .days li.highlighted + li:not(.highlighted) {
      position: relative;
    }
    
    .days li.highlighted + li:not(.highlighted):before,
    .days li.highlighted + li:not(.highlighted):after{
      content: '';
      position: absolute;
      width: var(--radius);
      top: 0;
      bottom: 0;
      right: 100%;
      pointer-events: none;
    }
    
    .days li.highlighted + li:not(.highlighted):before{
      background-color: var(--background);
    }
    
    .days li.highlighted + li:not(.highlighted):after{
      background-color: var(--highlighted);
      border-radius:0 var(--radius) var(--radius) 0;
    }
    <div class="wrapper">
      <div class="calendar">
        <ul class="weeks">
          <li>Sun</li>
          <li>Mon</li>
          <li>Tue</li>
          <li>Wed</li>
          <li>Thu</li>
          <li>Fri</li>
          <li>Sat</li>
        </ul>
        <ul class="days">
          <li class="inactive">26</li>
          <li class="inactive">27</li>
          <li class="inactive">28</li>
          <li class="inactive">29</li>
          <li class="inactive">30</li>
          <li class="inactive">31</li>
          <li>1</li>
          <li>2</li>
          <li class="highlighted">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>
          <li>18</li>
          <li class="highlighted">19</li>
          <li class="highlighted">20</li>
          <li class="active highlighted">21</li>
          <li class="highlighted">22</li>
          <li class="highlighted">23</li>
          <li class="highlighted">24</li>
          <li class="highlighted">25</li>
          <li class="highlighted">26</li>
          <li class="highlighted">27</li>
          <li class="highlighted">28</li>
          <li class="highlighted">29</li>
          <li class="highlighted">30</li>
          <li class="inactive highlighted">1</li>
          <li class="inactive highlighted">2</li>
          <li class="inactive highlighted">3</li>
          <li class="inactive">4</li>
          <li class="inactive">5</li>
          <li class="inactive">6</li>
    
        </ul>
      </div>
    </div>

    In this case, the selection will not go beyond the cell, as in @web-tiki solution.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search