Search code examples
htmlcssknockout.jsoutline

Add outline to grouped buttons that have the same class name binded one next to other


I have a parent View model:

var monthVM = function (mData) {
this.Id = mData.Id;
this.Name = mData.Name;
if (mData.Days != null) {
        $.each(mData.Days, function (index, item) {
            var newDay = new dayVM(item, index);
            this.Days.push(newDay );
        });
    }
}

And dayVM:

var dayVM= function (dData, index) {
    this.Id=dData.Id;
    this.Mon = ko.observable(dData.Mon);
    this.Tue = ko.observable(dData.Tue);
    this.Wed = ko.observable(dData.Wed);
    this.Thu = ko.observable(dData.Thu);
    this.Fri = ko.observable(dData.Fri);
    this.Sat = ko.observable(dData.Sat);
    this.Sun = ko.observable(dData.Sun);
    
    this.didOnMon = function (item) {       
        if (item.Mon() == false) item.Mon(true);
        else item.Mon(false);
        //other stuff
    }
    this.didOnTue = function (item) {       
        if (item.Tue() == false) item.Tue(true);
        else item.Tue(false);
        //other stuff
    }
}

The HTML binding

<div class="row">
   <div class="col-9 btn-group">
        <button data-bind="css: Mon() == false ? 'btn btn-white btn-xs mt-1' : 'btn btn-dark btn-xs mt-1', click:changeMon">Mon</button>
        <button data-bind="css: Tue() == false ? 'btn btn-white btn-xs mt-1' : 'btn btn-dark btn-xs mt-1', click:changeTue">Tue</button>
        <button data-bind="css: Wed() == false ? 'btn btn-white btn-xs mt-1' : 'btn btn-dark btn-xs mt-1', click:changeWed">Wed</button>
        <button data-bind="css: Thu() == false ? 'btn btn-white btn-xs mt-1' : 'btn btn-dark btn-xs mt-1', click:changeThu">Thu</button>
        <button data-bind="css: Fri() == false ? 'btn btn-white btn-xs mt-1' : 'btn btn-dark btn-xs mt-1', click:changeFri">Fri</button> div
        <button data-bind="css: Sat() == false ? 'btn btn-white btn-xs mt-1' : 'btn btn-dark btn-xs mt-1', click:changeSat">Sat</button>
        <button data-bind="css: Sun() == false ? 'btn btn-white btn-xs mt-1' : 'btn btn-dark btn-xs mt-1', click:changeSun">Sun</button>
   </div>
</div>

I need to add a border like grouping the buttons that are dark, one next to other, but still keeping the design: the buttons are filling col-9 div like enter image description here

Every time one of the buttons becomes white, it should adjust the outline for the other dark ones.

I've tried using

.btn-dark-custom {
   outline: 1px solid black;
   outline-offset: 2px;
}

<button class="btn btn-dark btn-dark-custom" onclick="changeWed()">Wed</button>

but it draws the border for each dark button, not as a group. I've also tried adding border lines, in JS, but I cannot add the offset to it.


Solution

  • In pure css it's a bit complex, but here is a possibility (Jquery is used just for the click class toggle) :

    $('.elem').click(function(){$(this).toggleClass('active')})
    /* BASE */
    .elem {
      float:left;
      background: #eee;
      padding: 5px 10px;
      cursor: pointer;
      position: relative;
    }
    .elem.active {
      background: #444;
      color: #eee;
    }
    
    /* PSEUDO ELEMENT */
    .elem::after {
      position: absolute;
      z-index: 1;
      left: -4px;
      top: -4px;
      right: -4px;
      bottom: -4px;
      border: 2px solid black;
    }
    
    /* SHOW PSEUDO ELEMENT IN .ACTIVE */
    .elem.active::after {
      content: '';
    }
    
    /* SELECT .ACTIVE BEFORE OTHER .ACTIVE */
    .elem.active + .elem.active::after {
      border-left: none;
      border-right: none;
    }
    
    /* SELECT .ACTIVE FIRST CHILD OR FIRST ELEM AFTER NOT ACTIVE */
    .elem.active:first-child::after,
    .elem:not(.active) + .elem.active::after {
      border-right: none;
    }
    
    /* SELECT LAST CHILD */
    .elem.active:last-child::after {
      border-right: 2px solid black !important;
    }
    
    /* TRICKS LAST .ACTIVE SUCCESSIVE */
    .elem.active + .elem:not(.active)::after {
      content: '';
      border: none;
      border-left: 2px solid black;
      left: 2px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div>
      <div class="elem active">Mon</div>
      <div class="elem active">Tue</div>
      <div class="elem">Wed</div>
      <div class="elem active">Thu</div>
      <div class="elem active">Fri</div>
      <div class="elem active">Sat</div>
      <div class="elem">Sun</div>
    </div>